2

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 ?

MicrosoctCprog
  • 460
  • 1
  • 3
  • 23
  • 3
    Does this answer your question? [libpcap - capture packets from all interfaces](https://stackoverflow.com/questions/8995741/libpcap-capture-packets-from-all-interfaces) – Daniel Walker Nov 01 '20 at 17:59

1 Answers1

1

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
}
Daniel Walker
  • 6,380
  • 5
  • 22
  • 45
  • That work but I didn't understand why it's work , 1) should I calculate `layer_2_header_length ` each packet received (in the while) or only before the while ? 2) why does it changed between `ens33` and `any` ? thanks! – MicrosoctCprog Nov 01 '20 at 18:34
  • Once you set up a `pcap_t`, the layer 2 header size will be the same for every packet captured. The reason why it changes between "ens33" and "any" is because, when you're capturing on all interfaces, you could have multiple layer 2 types coming in. Therefore, they need to be standardized. – Daniel Walker Nov 01 '20 at 19:15
  • 1
    "Once you set up a `pcap_t,` the layer 2 header size will be the same for every packet captured." Not for all layer 2 types; IEEE 802.11, for example, has a variable-length layer 2 header. – user13951124 Nov 02 '20 at 01:36
  • Huh. I did not know that. Thanks! – Daniel Walker Nov 02 '20 at 02:21
  • is there more option than `DLT_LINUX_SLL` `DLT_EN10MB` ? – MicrosoctCprog Nov 02 '20 at 08:12
  • There are. You should read the documentation for details. – Daniel Walker Nov 02 '20 at 12:51
  • See also [the tcpdump.org link-layer header types page](https://www.tcpdump.org/linktypes.html). – user13951124 Nov 02 '20 at 23:17