Search code examples
clinuxubuntulibpcappacket-sniffers

Can't get protocol while capture any interfaces with libpcap


I using libpcap code to capture network traffic in my Ubuntu with the following code I have problem the parse the protocol of packet:

#include <stdio.h> 
#include <stdlib.h> 
#include <stddef.h>
#include <stdio.h>
#include <time.h>
#include <pcap.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>



int main(int argc, char *argv[]) {
    char *device = "any";
    char error_buffer[PCAP_ERRBUF_SIZE];
    pcap_t *handle;
    const u_char *packet;
    struct pcap_pkthdr packet_header;
    int packet_count_limit = 1;
    int timeout_limit = 20000; /* In milliseconds */
    bpf_u_int32 net;
    bpf_u_int32 mask;

    if ( -1 == pcap_lookupnet(device ,&net,&mask,error_buffer))
    printf("error netmask\n");


    /* Open device for live capture */
    handle = pcap_open_live(
            device ,
            BUFSIZ,
            packet_count_limit,
            timeout_limit,
            error_buffer
        );
    if(NULL == handle)
        printf("error! %s\n",error_buffer);
    struct pcap_pkthdr* header;
    u_char *buffer;

    while(1)
    {
    
        int ret  = pcap_next_ex(handle,&header, &buffer);
    if(header->len ==0)
    {
        printf("cont\n");
        continue;

    }

    struct  iphdr *iph = (struct iphdr*) (buffer + sizeof(struct ethhdr));
    printf("protocol = %d \n", iph->protocol);
    }

    return 0;
}

The problem is , when I choose to capture in any interfaces char *device = "any"; I always get protocol = 0

But when I choose char *device = "ens33"; I got right protocol (like 6 for TCP)

why is that ?


Solution

  • libpcap will sometimes, depending upon the interface chosen, replace the layer 2 header (ethernet, in this case) with a Linux cooked header which does not have the same length as an ethernet header. You can check the datalink type of your pcap_t with the pcap_datalink function.

    unsigned int layer_2_header_length;
    
    switch ( pcap_datalink(handle) ) {
    case DLT_EN10MB: // Ethernet header
        layer_2_header_length = 14;
        break;
    
    case DLT_LINUX_SLL: // Linux cooked header
        layer_2_header_length = 16;
        break;
    
    // other options
    }