#include "sniffer.h" /// \fn Sniffer::Sniffer() /// \~English /// \brief Constructor, does nothing /// \~Spanish /// \brief Constructor, no hace nada Sniffer::Sniffer(){ } /// \fn Sniffer::Sniffer(QWaitCondition *pw, QMutex *mx, int *ps) /// \~English /// \brief Sets the mutexes for the inter communication between /// the sniffer and the GUI. /// \param pw used to pause the capture of packets /// \param mx used to protect critical region /// \param ps flag to pause the packet capture /// \~Spanish /// \brief Ajusta los mutexes para la inter comunicacion entre /// el sniffer y el GUI. /// \param pw se usa para pausar la captura de paquetes /// \param mx usado para proteger la region critica /// \param ps bandera para pausar la captura de paquetes Sniffer::Sniffer(QWaitCondition *pw, QMutex *mx, int *ps){ wait_pause = pw ; mutex = mx ; pause = ps ; } /// \fn Sniffer::~Sniffer() /// \~English /// \brief Destructor, does nothing /// \~Spanish /// \brief Destructor, no hace nada Sniffer::~Sniffer(){ } /// \fn void Sniffer::process() /// \~English /// \brief The sniffer is run as a separate thread and the function process /// is the main function of the thread. It is the sniffer. /// \~Spanish /// \brief El sniffer se corre como un hilo por separado y la funcion process /// es la funcion principal de el hilo. Es el sniffer. void Sniffer::process() Q_DECL_OVERRIDE { char *dev = NULL; /* capture device name */ /* nombre del dispositivo para capturar */ char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ /* buffer de error */ pcap_t *handle; /* packet capture handle */ /* manejador de captura de paquete */ struct pcap_pkthdr header; /* The header that pcap gives us */ /* El header devuelto por pcap */ const u_char *packet; /* The actual packet */ /* El paquete como tal */ int num_packets = 100; /* number of packets to capture */ /* numero de paquetes a capturar */ unsigned long iptu_count = 0 ; /* counter of tcp|udp packets */ /* contador de paquetes tcp|udp */ /* print capture info */ /* imprime informacion de captura */ printf("Device: %s\n", dev); printf("Number of packets: %d\n", num_packets); /* open capture device */ /* abre el dispositivo para capturar */ handle = pcap_open_live(device.c_str(), SNAP_LEN, 1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); exit(EXIT_FAILURE); } /* make sure we're capturing on an Ethernet device */ /* se asegura que se esta capturando en un dispositivo de Ethernet */ if (pcap_datalink(handle) != DLT_EN10MB) { fprintf(stderr, "%s is not an Ethernet\n", dev); exit(EXIT_FAILURE); } /* Check if device can be set to monitor */ /* Revisa si el device puede ser ajustado a modo monitoreo */ if (pcap_can_set_rfmon(handle)){ pcap_set_rfmon(handle, 1) ; pcap_activate(handle) ; } /* now we can set our callback function in an infinite loop */ /* ahora podemos ajustar la funcion de llamada devuelta en un cyclo infinito */ for(;;){ mutex->lock() ; if(*pause){ wait_pause->wait(mutex) ; // Stop capturing, next we need to restart // Para de capturar, next we need to restart pcap_close(handle) ; /* open capture device */ /* abre el dispositivo de captura */ handle = pcap_open_live(device.c_str(), SNAP_LEN, 1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); exit(EXIT_FAILURE); } /* make sure we're capturing on an Ethernet device */ /* se asegura que estamos capturando en un dispositivo Ethernet */ if (pcap_datalink(handle) != DLT_EN10MB) { fprintf(stderr, "%s is not an Ethernet\n", dev); exit(EXIT_FAILURE); } } mutex->unlock(); packet = pcap_next(handle, &header) ; /* If a packet is received then process the packet */ /* Si se recibe un paquete entonces se procesa */ if(packet) got_packet(&header, packet); /* If the packet will be displayed then send singal to GUI */ /* Si el paquete va a ser desplegado se envia senal al GUI */ if(iptu_count < packet_list.size()){ iptu_count = packet_list.size() ; emit resultReady((unsigned long) packet_list.size()); } } /* cleanup */ /* limpio */ pcap_close(handle); /* Termino de capturar */ printf("\nCapture complete.\n"); printf("PACKETS IN LIST %lu\n", packet_list.size()) ; } /* * print data in rows of 16 bytes: offset hex ascii * * 00000 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1.. */ /// \fn void Sniffer::print_hex_ascii_line(const u_char *payload, int len, int offset) /// \~English /// \brief Prints to std output the a payload in ascii /// \param payload payload of the packet /// \param len length of the packet /// \param offset offset /// \~Spanish /// \brief Imprime la carga en ascii a std output /// \param payload carga del paquete /// \param len largo de la carga /// \param offset distancia void Sniffer::print_hex_ascii_line(const u_char *payload, int len, int offset) { int i; int gap; const u_char *ch; /* offset */ printf("%05d ", offset); /* hex */ ch = payload; for(i = 0; i < len; i++) { printf("%02x ", *ch); ch++; /* print extra space after 8th byte for visual aid */ if (i == 7) printf(" "); } /* print space to handle line less than 8 bytes */ if (len < 8) printf(" "); /* fill hex gap with spaces if not full line */ if (len < 16) { gap = 16 - len; for (i = 0; i < gap; i++) { printf(" "); } } printf(" "); /* ascii (if printable) */ ch = payload; for(i = 0; i < len; i++) { if (isprint(*ch)) printf("%c", *ch); else printf("."); ch++; } printf("\n"); return; } /// \fn string Sniffer::format_hex_ascii_line(const char *payload, int len, int offset) /// \~English /// \brief Return string with the bytes of a payload line in ascii /// \param payload payload of the packet /// \param len length of the packet /// \param offset offset of packet /// \return a string with the bytes of a payload line in ascii /// \~Spanish /// \brief Devuelve una cadena de caracteres con los bytes de una linea /// de la carga en ascii /// \param payload carga del paquete /// \param len largo del paquete /// \param offset distancia del paquete /// \return a string with the bytes of a payload line in ascii string Sniffer::format_hex_ascii_line(const char *payload, int len, int offset) { int i; int gap; const char *ch; string line ; char temp[15] ; /* offset */ sprintf(temp, "%05d ", offset); line.append(temp) ; /* hex */ ch = payload; for(i = 0; i < len; i++) { sprintf(temp, "%02x ", (unsigned char) *ch); line.append(temp) ; ch++; /* print extra space after 8th byte for visual aid */ if (i == 7) line.append(" ") ; } /* print space to handle line less than 8 bytes */ if (len < 8) line.append(" ") ; /* fill hex gap with spaces if not full line */ if (len < 16) { gap = 16 - len; for (i = 0; i < gap; i++) { line.append(" ") ; } } line.append(" "); /* ascii (if printable) */ ch = payload; for(i = 0; i < len; i++) { if (isprint(*ch)) line += (unsigned char) *ch ; else line.append(".") ; ch++; } line.append("\n") ; return line ; } /* * print packet payload data (avoid printing binary data) */ /// \fn void Sniffer::print_payload(const u_char *payload, int len) /// \~English /// \brief Prints the payload in ascii /// \param payload payload of the packet /// \param len payload length /// \~Spanish /// \brief Imprime la carga en ascii /// \param payload carga del paquete /// \param len largo de la carga void Sniffer::print_payload(const u_char *payload, int len) { int len_rem = len; int line_width = 16; /* number of bytes per line */ /* numero de bytes por linea */ int line_len; int offset = 0; /* zero-based offset counter */ /* basado a cero, contador de compensacion */ const u_char *ch = payload; if (len <= 0) return; /* data fits on one line */ /* data cabe en una linea */ if (len <= line_width) { print_hex_ascii_line(ch, len, offset); return; } /* data spans multiple lines */ /* data cubre multiples lineas */ for ( ;; ) { /* compute current line length */ /* computa el largo de la linea corriente */ line_len = line_width % len_rem; /* print line */ /* imprime linea */ print_hex_ascii_line(ch, line_len, offset); /* compute total remaining */ /* computa total que queda */ len_rem = len_rem - line_len; /* shift pointer to remaining bytes to print */ /* mueve el apuntado a los bytes que quedan para imprimir */ ch = ch + line_len; /* add offset */ /* anade compensacion */ offset = offset + line_width; /* check if we have line width chars or less */ /* revisa si tenemos una linea con ancho completo o menos */ if (len_rem <= line_width) { /* print last line and get out */ /* imprime la ultima linea y sale */ print_hex_ascii_line(ch, len_rem, offset); break; } } return; } /// \fn string Sniffer::format_payload(const char *payload, int len) /// \~English /// \brief Formats the payload from a byte stream into a string of ascci /// \param payload payload of the packet /// \param len length of the packet /// \return the payload in a string of ascii /// \~Spanish /// \brief Formatea la carga de un torrente de bytes a un cadena de /// caracteres ascii /// \param payload carga del paquete /// \param len largo del paquete /// \return la carga en una cadena de caracteres ascii string Sniffer::format_payload(const char *payload, int len) { int len_rem = len; int line_width = 16; /* number of bytes per line */ int line_len; int offset = 0; /* zero-based offset counter */ const char *ch = payload; string formated ; if (len <= 0) return ""; /* data fits on one line */ if (len <= line_width) { formated += format_hex_ascii_line(ch, len, offset); return ""; } /* data spans multiple lines */ for ( ;; ) { /* compute current line length */ line_len = line_width % len_rem; /* print line */ formated += format_hex_ascii_line(ch, line_len, offset); /* compute total remaining */ len_rem = len_rem - line_len; /* shift pointer to remaining bytes to print */ ch = ch + line_len; /* add offset */ offset = offset + line_width; /* check if we have line width chars or less */ if (len_rem <= line_width) { /* print last line and get out */ formated += format_hex_ascii_line(ch, len_rem, offset); break; } } return formated; } /// \fn void Sniffer::got_packet(const struct pcap_pkthdr *, const u_char *packet) /// \~English /// \brief Dissects the received packet. Takes out the info needed. /// \param pcap_pkthdr header of the pcap packet /// \param packet recieved packet /// \~Spanish /// \brief Secciona el paquete recibido. Extrae la informacion necesaria. /// \param pcap_pkthdr encabezado del paquete de pcap /// \param packet paquete recibido void Sniffer::got_packet(const struct pcap_pkthdr *, const u_char *packet) { /* declare pointers to packet headers */ /* declara apuntadores a los headers del paquete. */ const struct sniff_ethernet *ethernet; /* The Ethernet header */ /* El encabezado de Ethernet */ const struct sniff_ip *ip; /* The IP header */ /* Encabezado de IP */ const struct sniff_tcp *tcp; /* The TCP header */ /* Encabezado de TCP */ const struct sniff_udp *udp ; /* The UDP header */ /* Encabezado de UDP */ const u_char *payload; /* Packet payload */ /* Carga del paquete */ ip_packet ip_pkt ; /* IP Packet */ /* Paquete de IP */ int size_ip; // to store the size of IP // para guardar el tamano de IP int size_tcp; // to store the size of tcp // para guardar el tamano de TCP int size_payload; // to store the size of payload // para guardar el tamano del payload ethernet = (struct sniff_ethernet*)(packet); /* define/compute IP header offset */ /* define/computa donde empieza el header de IP */ ip = (struct sniff_ip*)(packet + SIZE_ETHERNET); size_ip = IP_HL(ip)*4; if (size_ip < 20) { // qDebug() << " * Invalid IP header length: " << size_ip <<" bytes\n" ; printf(" * Invalid IP header length: %u bytes\n", size_ip); return ; } /* print source and destination IP addresses */ /* imprime las direcciones fuente y destino de IP */ printf(" From: %s\n", inet_ntoa(ip->ip_src)); printf(" To: %s\n", inet_ntoa(ip->ip_dst)); ip_pkt.setEtherSHost((u_char *)ethernet->ether_shost) ; ip_pkt.setEtherDHost((u_char *)ethernet->ether_dhost); ip_pkt.setIPSAddress(inet_ntoa(ip->ip_src)); ip_pkt.setIPDAddress(inet_ntoa(ip->ip_dst)); ip_pkt.setIPProto(ip->ip_p); /* determine protocol */ /* determina el protocolo */ switch(ip->ip_p) { case IPPROTO_TCP: printf(" Protocol: TCP\n"); /* define/compute tcp header offset */ /* define/computa el donde empieza el encabezado tcp */ tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip); size_tcp = TH_OFF(tcp)*4; if (size_tcp < 20) { printf(" * Invalid TCP header length: %u bytes\n", size_tcp); return; } ip_pkt.setIPSPort(ntohs(tcp->th_sport)) ; ip_pkt.setIPDPort(ntohs(tcp->th_dport)) ; printf(" Src port: %d\n", ntohs(tcp->th_sport)); printf(" Dst port: %d\n", ntohs(tcp->th_dport)); /* define/compute tcp payload (segment) offset */ /* define/computa donde empieza la carga tcp */ payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp); /* compute tcp payload (segment) size */ /* computa el tamano de la carga tcp */ size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp); ip_pkt.setPayload((char *) payload, size_payload); packet_list.push_back(ip_pkt); break ; case IPPROTO_UDP: printf(" Protocol: UDP\n"); udp = (struct sniff_udp*)(packet + SIZE_ETHERNET + size_ip); ip_pkt.setIPSPort(ntohs(udp->th_sport)) ; ip_pkt.setIPDPort(ntohs(udp->th_dport)) ; printf(" Src port: %d\n", ntohs(udp->th_sport)); printf(" Dst port: %d\n", ntohs(udp->th_dport)); /* define/compute udp payload (segment) offset */ /* define/computa donde comienza UDP */ payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + 8); /* compute udp payload (segment) size */ /* computa donde comienza la carga del UDP */ size_payload = ntohs(ip->ip_len) - (size_ip + 8); ip_pkt.setPayload((char *)payload, size_payload); packet_list.push_back(ip_pkt); break; case IPPROTO_ICMP: printf(" Protocol: ICMP\n"); break; case IPPROTO_IP: printf(" Protocol: IP\n"); break; default: printf(" Protocol: unknown\n"); break; } return; } /// \fn vector *Sniffer::getPacketList() /// \~English /// \brief Returns the packet list that contains the packets that are /// Ethernet -> IP -> (TCP|UDP) /// \return vector of packets /// \~Spanish /// \brief Devuelve la lista de paquetes que contiene los paquetes que son /// Ethernet -> IP -> (TCP|UDP) /// \return vector de paquetes vector *Sniffer::getPacketList(){ return &packet_list ; } /// \fn void Sniffer::find_devices(vector &devs) /// \~English /// \brief Find the network devices in the computer, and store them in vector devs. /// \param devs vector of string for device names /// \~Spanish /// \brief Encuentra los dispositivos de red en la computadora, y los almacena en /// el vector devs /// \param devs vector de cadenas de caracteres para los nombres void Sniffer::find_devices(vector &devs){ char errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t *devices ; if(pcap_findalldevs(&devices, errbuf) == 0 && devices != NULL){ while(devices){ string s(devices->name) ; devs.push_back(s) ; devices = devices->next ; } pcap_freealldevs(devices); } else{ devs.push_back("None") ; } return ; } /// \fn void Sniffer::setDevice(string dev) /// \~English /// \brief Sets the device to capture packets to dev /// \param dev name of the device /// \~Spanish /// \brief Ajusta el dispositivo para caputurar paquetes a dev /// \param dev nombre del dispositivo void Sniffer::setDevice(string dev){ device = dev ; }