mazkopolo mazkopolo - 2 months ago 22
C Question

How do I fetch the VLAN tags using libpcap and C?

I am trying to parse a pcap file including different type of Network Packets (some are tagged as VLAN and some aren't) using #include .
here is my code so far:

pcap_t *pcap;
const unsigned char *packet;
char errbuf[PCAP_ERRBUF_SIZE];
struct pcap_pkthdr header;
pcap = pcap_open_offline(argv[0], errbuf);
if (pcap == NULL)
{
fprintf(stderr, "error reading pcap file: %s\n", errbuf);
exit(1);
}
while ((packet = pcap_next(pcap, &header)) != NULL)
{
struct ip_header *ip;
unsigned int IP_header_length;
packet += sizeof(struct ether_header);
capture_len -= sizeof(struct ether_header);
ip = (struct ip_header*) packet;
IP_header_length = ip->vhl * 4; /* ip_hl is in 4-byte words */
char *sinfo = strdup(inet_ntoa(ip->src));
char *dinfo = strdup(inet_ntoa(ip->dst));
printf ("%s<-__->%s\n", sinfo ,dinfo);
free (sinfo);
free (dinfo);
}


There must be somewhere in the code to check the VLAN and jump over them correctly.How should I distinguish VLAN packets from non-VLANS?

Answer

(If you are testing this on a 'live' environment, it's important to remember that routers can remove 802.1q tags before forwarding to a non-trunking line.)

If you have a particular platform & protocol in mind, the fastest way to do this will always be to 'manually' check a frame:

htonl( ((uint32_t)(ETH_P_8021Q) << 16U)
     | ((uint32_t)customer_tci & 0xFFFFU) ) T

However, libpcap provides for a portable & clean packet filters in the form of functions for compiling a BPF filters and applying those to a stream of packets (although it is important to note that there are different sets of functions for on-the-wire vs. offline filtering)

In this fashion, We can use pcap_offline_filter to apply the compiled BPF filter directive to a PCAP file. I've used the filter expression vlan here, you may want something else like vlan or ip. If you need something more complex, you can consult the documentation)

...

pcap_t *pcap;
char errbuf[PCAP_ERRBUF_SIZE];
const unsigned char *packet;
struct pcap_pkthdr header;
struct bpf_program fp; // Our filter expression
pcap = pcap_open_offline(argv[0], errbuf);
if (pcap == NULL) {
    fprintf(stderr, "error reading pcap file: %s\n", errbuf);
    exit(1);
}

// Compile a basic filter expression, you can exam
if (pcap_compile(pcap, &fp, "vlan", 0, net) == -1) {
    fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
    return 2;
}

while ((packet = pcap_next(pcap, &header) != NULL)
       && pcap_offline_filter(&fp, header, packet)) {
    struct ip_header *ip;
    unsigned int IP_header_length;
    packet += sizeof(struct ether_header);
    capture_len -= sizeof(struct ether_header);
    ip = (struct ip_header*) packet;
    IP_header_length = ip->vhl * 4; /* ip_hl is in 4-byte words */
    char *sinfo = strdup(inet_ntoa(ip->src));
    char *dinfo = strdup(inet_ntoa(ip->dst));
    printf ("%s<-__->%s\n", sinfo ,dinfo);
    free (sinfo);
    free (dinfo);
}

...