1
votes

I want to use libpcap to capture packets but since the length of ethernet header or 802.11 header may vary and the length of IP header may also vary, how can I determine the starting byte(pointer) of the IP Header and TCP header besides, how to distinguish whether a packet is a pure IP packet, TCP packet or UDP packet? are there any APIs or ways to do this? thanks!

1
The length of an ethernet header cannot vary! At offset 14 you will find the IP packet, and then from there you can find the length of the IP header and add that to 14 to get the offset of the TCP header. - Celada
then how about the 802.11 header? - user138126
I've never seen one of those in a packet capture, and I'm not really familiar with it, but it does seem to have a fixed size (30 bytes + 4 bytes of trailer), so, also not a problem. - Celada
when i receive a packet, I have to judge what is the size of the 2nd-layer header, because it may be an ethernet header or 802.11 header. - user138126
But in a single capture file the packets are all of the same type, and the header tells you which one it is! - Celada

1 Answers

2
votes

When you're using libpcap, you can determine the size of link layer header, either by directly looking at the pcap file header (for offline captures) pcap_file_header.linktype or (for live and offline captures) from a call to pcap_datalink(). Most of the time this will be LINKTYPE_ETHERNET. To ensure a packet is IPv4, you can cast into an Ethernet header and check to ensure the ethertype is ETHERTYPE_IP (make sure you wrap it inside of ntohs(). I usually apply bpf filters to my pcap instantiations so I never worry about that stuff. To check the higher layer protocols however and assuming you're using pcap_dispatch(), you can write a callback as per the following: (the libnet library is still useful for its wide array of portable packet structures):

#include <libnet.h>
#include <pcap.h>

void
process_packet(u_char *user, const struct pcap_pkthdr *header, const u_char *packet)
{
    struct libnet_ipv4_hdr *ip;
    struct libnet_udp_hdr  *tcp;
    uint16_t ip_hl, udp_hl, header_cruft;

    ip     = (struct libnet_ipv4_hdr *)(packet + LIBNET_ETH_H);
    ip_hl  = ip->ip_hl << 2;

    switch (ip->ip_p)
    {
        case IPPROTO_UDP:
            udp    = (struct libnet_udp_hdr *)(packet + LIBNET_ETH_H + ip_hl);
            udp_hl = tcp->th_off << 2;
            header_cruft = LIBNET_ETH_H + ip_hl + tcp_hl;
            break;
        case IPPROTO_TCP:
            /** you get the idea */
            break;
        default:
            break;
    }