123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- #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 caputando 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 Disects 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<ip_packet> *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<ip_packet> *Sniffer::getPacketList(){
- return &packet_list ;
-
- }
-
- /// \fn void Sniffer::find_devices(vector<string> &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<string> &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 ;
- }
|