Nick
Nick

Reputation: 19684

libpcap - packet ip header length is zero bytes with loopback tcp requests

I am trying to view TCP payload information using libpcap. To do this I need to locate the payload's position in memory. I am using this Programming With Pcap guide to figure out the location of the request payload. When sniffing packets originating from a client that resides on the same machine as the service (loopback adapter) the IP Header length is 0. I cannot successfully find the location of the request payload. Is this to be expected when listening to loopback adapter? I am working on a MacOSx 10.8 system listening to adapter 'lo0'.

Here is what I am trying:

    //this callback is called when a packet is found
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){
    ethernet = (struct sniff_ethernet*)(packet);
    ip = (struct sniff_ip*)(packet + SIZE_ETHERNET); <-- the result is 0
    size_ip = IP_HL(ip)*4;
    if (size_ip < 20) {
        printf("   * Invalid IP header length: %u bytes\n", size_ip);
        return;
    }
    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;
    }
    payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);

}

struct sniff_ip:

#define SIZE_ETHERNET 14

 /* IP header */
struct sniff_ip {
    u_char ip_vhl;      /* version << 4 | header length >> 2 */
    u_char ip_tos;      /* type of service */
    u_short ip_len;     /* total length */
    u_short ip_id;      /* identification */
    u_short ip_off;     /* fragment offset field */
#define IP_RF 0x8000        /* reserved fragment flag */
#define IP_DF 0x4000        /* dont fragment flag */
#define IP_MF 0x2000        /* more fragments flag */
#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */
    u_char ip_ttl;      /* time to live */
    u_char ip_p;        /* protocol */
    u_short ip_sum;     /* checksum */
    struct in_addr ip_src,ip_dst; /* source and dest address */
};

Upvotes: 2

Views: 2415

Answers (1)

user862787
user862787

Reputation:

ethernet = (struct sniff_ethernet*)(packet);
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET); <-- the result is 0

If you're capturing on the loopback interface, that code is wrong. Not all interfaces on OS X (or any other OS that supports libpcap/WinPcap) provide Ethernet headers; you need to call pcap_datalink() to find the link-layer type of the capture device (or capture file, if you're reading a capture file with pcap_open_offline()) and, based on that, parse the link-layer headers of the packet.

See the list of pcap link-layer header types for a complete list.

DLT_EN10MB is the link-layer header type for Ethernet devices ("10MB" is historical, and refers to 3MB vs. 10MB Ethernet, which had different headers; DLT_EN10MB applies to 10 MB and 100 MB and 1 GB and 10 GB and 40 GB and 100 GB and... Ethernet), as well as some non-Ethernet devices that provide fake Ethernet headers.

The link-layer header type for the loopback device on most BSDs and on OS X is DLT_NULL; as the link-layer header types page says, it has a 4-byte link-layer header containing the OS's PF_ value for the protocol, which will probably be IPv4 or IPv6.

Upvotes: 8

Related Questions