Busindre » Blog Archive » Solución del problema de compilación del sniffer Ngrep (GNU/Linux)

Solución del problema de compilación del sniffer Ngrep (GNU/Linux)

January 19th, 2008 by Busindre

Ngrep es un conocido sniffer incluido en las famosa lista de "Las 50 herramientas mejores herramientas de seguridad", que tiene como principal cualidad el filtrado de paquetes en relación a los datos que contienen (payload), no solo las cabeceras. El comando "grep" en GNU sirve para filtrar salidas o buscar cadenas de texto en ficheros, ngrep realiza lo mismo con los datos de los paquetes (No solo las "headers") a nivel de capa de red. Realmente no hace nada que no pudiéramos hacer con Tcpdump, Snoop, Ethereal y demás aplicaciones, ya que tiene el motor basado en en la popular Pcap, que es usada como interfaz para capturar paquetes y tareas de filtración con los mismos, la implementación de pcap en sistemas UNIX se llama "Libpcap" y en sistemas Microsoft "WinPcap", es el usado en la mayoría de los sniffers.

Cuando intentamos compilarla, al ejecutar el comando "./configure" en el directorio de fuentes de Ngrep para su posterior compilación, podemos encontrarnos con este pequeño problema al que daremos rápida solución.

Descargar: http://ngrep.sourceforge.net/download.html

Compilación / Instalación

$ ./configure
$ make
$ make install

Error en el configure:

XML:
  1. creating Makefile
  2. creating doc/Makefile
  3. creating test/Makefile
  4.  
  5. Configuring Network Grep (ngrep) ...
  6.  
  7. checking for a broken redhat glibc udphdr declaration... no
  8. checking for a complete set of pcap headers...
  9.  
  10. more than one set found in:
  11. /usr/include
  12. /usr/local/include
  13.  
  14. please wipe out all unused pcap installations

Solución:

Para solucionarlo debemos localizar el directorio donde se encuentra "pcap.h", que es la que se necesita en la compilación de ngrep y la mayoría de sniffers.


$ locate pcap.h
/usr/local/include/pcap.h

Por lo que ahora usaremos la opción de "--with-pcap-includes" para indicarle directorio "include" de la librería pcap.

$ ./configure --with-pcap-includes=/usr/local/include

Si la salida del comando "locate" hubiera sido /usr/include/pcap-bpf.h

$ ./configure --with-pcap-includes=/usr/include

Vamos a ver, a modo de curiosidad un ejemplo de uso de librería pcap mediante un script de uno de los manuales del proyecto tcpdump. Este script se apoya en el uso de pcap para la captura y análisis de paquetes y es una valiosa prueba de concepto para comprender mejor el tipo de código y funciones que usan los más conocidos sniffers del mercado.

Compilarlo

$ gcc -Wall -o sniffex sniffex.c -lpcap

Script sniffex.c:

C:
  1. #define APP_NAME        "sniffex"
  2. #define APP_DESC        "Sniffer example using libpcap"
  3. #define APP_COPYRIGHT   "Copyright (c) 2005 The Tcpdump Group"
  4. #define APP_DISCLAIMER  "THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM."
  5.  
  6. #include <pcap.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include <sys/types.h>
  13. #include <sys/socket.h>
  14. #include <netinet/in.h>
  15. #include <arpa/inet.h>
  16.  
  17. /* default snap length (maximum bytes per packet to capture) */
  18. #define SNAP_LEN 1518
  19.  
  20. /* ethernet headers are always exactly 14 bytes [1] */
  21. #define SIZE_ETHERNET 14
  22.  
  23. /* Ethernet addresses are 6 bytes */
  24. #define ETHER_ADDR_LEN  6
  25.  
  26. /* Ethernet header */
  27. struct sniff_ethernet {
  28.         u_char  ether_dhost[ETHER_ADDR_LEN];    /* destination host address */
  29.         u_char  ether_shost[ETHER_ADDR_LEN];    /* source host address */
  30.         u_short ether_type;                     /* IP? ARP? RARP? etc */
  31. };
  32.  
  33. /* IP header */
  34. struct sniff_ip {
  35.         u_char  ip_vhl;                 /* version <<4 | header length>> 2 */
  36.         u_char  ip_tos;                 /* type of service */
  37.         u_short ip_len;                 /* total length */
  38.         u_short ip_id;                  /* identification */
  39.         u_short ip_off;                 /* fragment offset field */
  40.         #define IP_RF 0x8000            /* reserved fragment flag */
  41.         #define IP_DF 0x4000            /* dont fragment flag */
  42.         #define IP_MF 0x2000            /* more fragments flag */
  43.         #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
  44.         u_char  ip_ttl;                 /* time to live */
  45.         u_char  ip_p;                   /* protocol */
  46.         u_short ip_sum;                 /* checksum */
  47.         struct  in_addr ip_src,ip_dst;  /* source and dest address */
  48. };
  49. #define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
  50. #define IP_V(ip)                (((ip)->ip_vhl)>> 4)
  51.  
  52. /* TCP header */
  53. typedef u_int tcp_seq;
  54.  
  55. struct sniff_tcp {
  56.         u_short th_sport;               /* source port */
  57.         u_short th_dport;               /* destination port */
  58.         tcp_seq th_seq;                 /* sequence number */
  59.         tcp_seq th_ack;                 /* acknowledgement number */
  60.         u_char  th_offx2;               /* data offset, rsvd */
  61. #define TH_OFF(th)      (((th)->th_offx2 & 0xf0)>> 4)
  62.         u_char  th_flags;
  63.         #define TH_FIN  0x01
  64.         #define TH_SYN  0x02
  65.         #define TH_RST  0x04
  66.         #define TH_PUSH 0x08
  67.         #define TH_ACK  0x10
  68.         #define TH_URG  0x20
  69.         #define TH_ECE  0x40
  70.         #define TH_CWR  0x80
  71.         #define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
  72.         u_short th_win;                 /* window */
  73.         u_short th_sum;                 /* checksum */
  74.         u_short th_urp;                 /* urgent pointer */
  75. };
  76.  
  77. void
  78. got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
  79.  
  80. void
  81. print_payload(const u_char *payload, int len);
  82.  
  83. void
  84. print_hex_ascii_line(const u_char *payload, int len, int offset);
  85.  
  86. void
  87. print_app_banner(void);
  88.  
  89. void
  90. print_app_usage(void);
  91.  
  92. /*
  93. * app name/banner
  94. */
  95. void
  96. print_app_banner(void)
  97. {
  98.  
  99.     printf("%s - %s\n", APP_NAME, APP_DESC);
  100.     printf("%s\n", APP_COPYRIGHT);
  101.     printf("%s\n", APP_DISCLAIMER);
  102.     printf("\n");
  103.  
  104. return;
  105. }
  106.  
  107. /*
  108. * print help text
  109. */
  110. void
  111. print_app_usage(void)
  112. {
  113.  
  114.     printf("Usage: %s [interface]\n", APP_NAME);
  115.     printf("\n");
  116.     printf("Options:\n");
  117.     printf("    interface    Listen on <interface> for packets.\n");
  118.     printf("\n");
  119.  
  120. return;
  121. }
  122.  
  123. /*
  124. * print data in rows of 16 bytes: offset   hex   ascii
  125. *
  126. * 00000   47 45 54 20 2f 20 48 54  54 50 2f 31 2e 31 0d 0a   GET / HTTP/1.1..
  127. */
  128. void
  129. print_hex_ascii_line(const u_char *payload, int len, int offset)
  130. {
  131.  
  132.     int i;
  133.     int gap;
  134.     const u_char *ch;
  135.  
  136.     /* offset */
  137.     printf("%05d   ", offset);
  138.    
  139.     /* hex */
  140.     ch = payload;
  141.     for(i = 0; i <len; i++) {
  142.         printf("%02x ", *ch);
  143.         ch++;
  144.         /* print extra space after 8th byte for visual aid */
  145.         if (i == 7)
  146.             printf(" ");
  147.     }
  148.     /* print space to handle line less than 8 bytes */
  149.     if (len <8)
  150.         printf(" ");
  151.    
  152.     /* fill hex gap with spaces if not full line */
  153.     if (len <16) {
  154.         gap = 16 - len;
  155.         for (i = 0; i <gap; i++) {
  156.             printf("   ");
  157.         }
  158.     }
  159.     printf("   ");
  160.    
  161.     /* ascii (if printable) */
  162.     ch = payload;
  163.     for(i = 0; i <len; i++) {
  164.         if (isprint(*ch))
  165.             printf("%c", *ch);
  166.         else
  167.             printf(".");
  168.         ch++;
  169.     }
  170.  
  171.     printf("\n");
  172.  
  173. return;
  174. }
  175.  
  176. /*
  177. * print packet payload data (avoid printing binary data)
  178. */
  179. void
  180. print_payload(const u_char *payload, int len)
  181. {
  182.  
  183.     int len_rem = len;
  184.     int line_width = 16;            /* number of bytes per line */
  185.     int line_len;
  186.     int offset = 0;     /* zero-based offset counter */
  187.     const u_char *ch = payload;
  188.  
  189.     if (len <= 0)
  190.         return;
  191.  
  192.     /* data fits on one line */
  193.     if (len <= line_width) {
  194.         print_hex_ascii_line(ch, len, offset);
  195.         return;
  196.     }
  197.  
  198.     /* data spans multiple lines */
  199.     for ( ;; ) {
  200.         /* compute current line length */
  201.         line_len = line_width % len_rem;
  202.         /* print line */
  203.         print_hex_ascii_line(ch, line_len, offset);
  204.         /* compute total remaining */
  205.         len_rem = len_rem - line_len;
  206.         /* shift pointer to remaining bytes to print */
  207.         ch = ch + line_len;
  208.         /* add offset */
  209.         offset = offset + line_width;
  210.         /* check if we have line width chars or less */
  211.         if (len_rem <= line_width) {
  212.             /* print last line and get out */
  213.             print_hex_ascii_line(ch, len_rem, offset);
  214.             break;
  215.         }
  216.     }
  217.  
  218. return;
  219. }
  220.  
  221. /*
  222. * dissect/print packet
  223. */
  224. void
  225. got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
  226. {
  227.  
  228.     static int count = 1;                   /* packet counter */
  229.    
  230.     /* declare pointers to packet headers */
  231.     const struct sniff_ethernet *ethernet;  /* The ethernet header [1] */
  232.     const struct sniff_ip *ip;              /* The IP header */
  233.     const struct sniff_tcp *tcp;            /* The TCP header */
  234.     const char *payload;                    /* Packet payload */
  235.  
  236.     int size_ip;
  237.     int size_tcp;
  238.     int size_payload;
  239.    
  240.     printf("\nPacket number %d:\n", count);
  241.     count++;
  242.    
  243.     /* define ethernet header */
  244.     ethernet = (struct sniff_ethernet*)(packet);
  245.    
  246.     /* define/compute ip header offset */
  247.     ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
  248.     size_ip = IP_HL(ip)*4;
  249.     if (size_ip <20) {
  250.         printf("   * Invalid IP header length: %u bytes\n", size_ip);
  251.         return;
  252.     }
  253.  
  254.     /* print source and destination IP addresses */
  255.     printf("       From: %s\n", inet_ntoa(ip->ip_src));
  256.     printf("         To: %s\n", inet_ntoa(ip->ip_dst));
  257.    
  258.     /* determine protocol */   
  259.     switch(ip->ip_p) {
  260.         case IPPROTO_TCP:
  261.             printf("   Protocol: TCP\n");
  262.             break;
  263.         case IPPROTO_UDP:
  264.             printf("   Protocol: UDP\n");
  265.             return;
  266.         case IPPROTO_ICMP:
  267.             printf("   Protocol: ICMP\n");
  268.             return;
  269.         case IPPROTO_IP:
  270.             printf("   Protocol: IP\n");
  271.             return;
  272.         default:
  273.             printf("   Protocol: unknown\n");
  274.             return;
  275.     }
  276.    
  277.     /*
  278.      *  OK, this packet is TCP.
  279.      */
  280.    
  281.     /* define/compute tcp header offset */
  282.     tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
  283.     size_tcp = TH_OFF(tcp)*4;
  284.     if (size_tcp <20) {
  285.         printf("   * Invalid TCP header length: %u bytes\n", size_tcp);
  286.         return;
  287.     }
  288.    
  289.     printf("   Src port: %d\n", ntohs(tcp->th_sport));
  290.     printf("   Dst port: %d\n", ntohs(tcp->th_dport));
  291.    
  292.     /* define/compute tcp payload (segment) offset */
  293.     payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);
  294.    
  295.     /* compute tcp payload (segment) size */
  296.     size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
  297.    
  298.     /*
  299.      * Print payload data; it might be binary, so don't just
  300.      * treat it as a string.
  301.      */
  302.     if (size_payload> 0) {
  303.         printf("   Payload (%d bytes):\n", size_payload);
  304.         print_payload(payload, size_payload);
  305.     }
  306.  
  307. return;
  308. }
  309.  
  310. int main(int argc, char **argv)
  311. {
  312.  
  313.     char *dev = NULL;         /* capture device name */
  314.     char errbuf[PCAP_ERRBUF_SIZE];    /* error buffer */
  315.     pcap_t *handle;    /* packet capture handle */
  316.  
  317.     char filter_exp[] = "ip";      /* filter expression [3] */
  318.     struct bpf_program fp;      /* compiled filter program (expression) */
  319.     bpf_u_int32 mask;         /* subnet mask */
  320.     bpf_u_int32 net;            /* ip */
  321.     int num_packets = 10;         /* number of packets to capture */
  322.  
  323.     print_app_banner();
  324.  
  325.     /* check for capture device name on command-line */
  326.     if (argc == 2) {
  327.         dev = argv[1];
  328.     }
  329.     else if (argc> 2) {
  330.         fprintf(stderr, "error: unrecognized command-line options\n\n");
  331.         print_app_usage();
  332.         exit(EXIT_FAILURE);
  333.     }
  334.     else {
  335.         /* find a capture device if not specified on command-line */
  336.         dev = pcap_lookupdev(errbuf);
  337.         if (dev == NULL) {
  338.             fprintf(stderr, "Couldn't find default device: %s\n",
  339.                 errbuf);
  340.             exit(EXIT_FAILURE);
  341.         }
  342.     }
  343.    
  344.     /* get network number and mask associated with capture device */
  345.     if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
  346.         fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
  347.             dev, errbuf);
  348.         net = 0;
  349.         mask = 0;
  350.     }
  351.  
  352.     /* print capture info */
  353.     printf("Device: %s\n", dev);
  354.     printf("Number of packets: %d\n", num_packets);
  355.     printf("Filter expression: %s\n", filter_exp);
  356.  
  357.     /* open capture device */
  358.     handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
  359.     if (handle == NULL) {
  360.         fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  361.         exit(EXIT_FAILURE);
  362.     }
  363.  
  364.     /* make sure we're capturing on an Ethernet device [2] */
  365.     if (pcap_datalink(handle) != DLT_EN10MB) {
  366.         fprintf(stderr, "%s is not an Ethernet\n", dev);
  367.         exit(EXIT_FAILURE);
  368.     }
  369.  
  370.     /* compile the filter expression */
  371.     if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
  372.         fprintf(stderr, "Couldn't parse filter %s: %s\n",
  373.             filter_exp, pcap_geterr(handle));
  374.         exit(EXIT_FAILURE);
  375.     }
  376.  
  377.     /* apply the compiled filter */
  378.     if (pcap_setfilter(handle, &fp) == -1) {
  379.         fprintf(stderr, "Couldn't install filter %s: %s\n",
  380.             filter_exp, pcap_geterr(handle));
  381.         exit(EXIT_FAILURE);
  382.     }
  383.  
  384.     /* now we can set our callback function */