Search code examples
linuxtcpudplibpcap

How do I get packet length and ip addresses in libpcap


From this example

void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *buffer)
{
    int size = header->len;

    //Get the IP Header part of this packet , excluding the ethernet header
    struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr));
    ++total;
    switch (iph->protocol) //Check the Protocol and do accordingly...
    {
        case 1:  //ICMP Protocol
            ++icmp;
            print_icmp_packet( buffer , size);
            break;

        case 2:  //IGMP Protocol
            ++igmp;
            break;

        case 6:  //TCP Protocol
            ++tcp;
            print_tcp_packet(buffer , size);
            break;

        case 17: //UDP Protocol
            ++udp;
            print_udp_packet(buffer , size);
            break;

        default: //Some Other Protocol like ARP etc.
            ++others;
            break;
    }
    printf("TCP : %d   UDP : %d   ICMP : %d   IGMP : %d   Others : %d   Total : %d\r", tcp , udp , icmp , igmp , others , total);
}

variable size is, I guess, the size of the header. How do I get the size of the whole packet?

Also, how do I convert uint32_t IP addresses to human readable IP addresses of the form xxx.xxx.xxx.xxx?


Solution

  • variable size is, I guess, the size of the header.

    You have guessed incorrectly.

    To quote the pcap man page:

       Packets  are  read  with  pcap_dispatch()  or  pcap_loop(),  which
       process one or more packets, calling a callback routine  for  each
       packet,  or  with  pcap_next() or pcap_next_ex(), which return the
       next packet.  The callback for pcap_dispatch() and pcap_loop()  is
       supplied  a  pointer  to  a struct pcap_pkthdr, which includes the
       following members:
    
              ts     a struct timeval containing the time when the packet
                     was captured
    
              caplen a  bpf_u_int32  giving  the  number  of bytes of the
                     packet that are available from the capture
    
              len    a bpf_u_int32 giving the length of  the  packet,  in
                     bytes  (which might be more than the number of bytes
                     available from the capture, if  the  length  of  the
                     packet is larger than the maximum number of bytes to
                     capture).
    

    so "len" is the total length of the packet. However, there may not be "len" bytes of data available; if the capture was done with a "snapshot length", for example with tcpdump, dumpcap, or TShark using the -s option, the packet could have been cut short, and "caplen" would indicate how many bytes of data you actually have.

    Note, however, that Ethernet packets have a minimum length of 60 bytes (not counting the 4-byte FCS at the end, which you probably won't get in your capture), including the 14-byte Ethernet header; this means that short packets must be padded. 60-14 = 46, so if a host sends, over Ethernet, an IP packet that's less than 46 bytes long, it must pad the Ethernet packet.

    This means that the "len" field gives the total length of the Ethernet packet, but if you subtract the l4 bytes of Ethernet header from "len", you won't get the length of the IP packet. To get that, you'll need to look in the IP header at the "total length" field. (Don't assume it'll be less than or equal to the value of "len" - 14 - a machine might have sent an invalid IP packet.)

    Also, how do I convert uint32_t IP addresses to human readable IP addresses of the form xxx.xxx.xxx.xxx?

    By calling routines such as inet_ntoa(), inet_ntoa_r(), or inet_ntop().