Search code examples
cnetwork-programmingpcaplibpcap

C - pcap does not work when sniffing packets from all interfaces (with "any")


I am trying to write a packet sniffer in C. this program should capture all incoming LLDP packets (lldp is not important for this question) from all available interfaces (eth0... etc). the program works just fine when I specify an interface in the dev variable but does not work when trying to capture from all interfaces at once. (program does not show anything although I can see that there are some packets using Tcpdump command in Linux).

In the man page for pcap_open_live ( https://www.tcpdump.org/manpages/pcap_open_live.3pcap.html ) it does say that whenever you want to capture packets from all interfaces you should change the first argument to either NULL or "any" so I changed dev (variable with the name of the interface) to be "any" and expected the program to work but it didn't.. it does not give me any errors but it seems like it cant capture any packet...

I suppose I am doing something wrong so I will appreciate any Help And thanks in advance.

Btw: the mentioned man page states that the Linux kernel should be version 2.2 or higher which I checked is true (version 4.19).

#include <pcap/pcap.h>
#include <stdlib.h>


void callback_func(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packetData) 
{ 
    static int count = 1; 
    fprintf(stdout, "%3d, ", count);
    fflush(stdout);
    count++; 
}


int main() 
{ 
    const char *dev = "any";
    char errbuf[PCAP_ERRBUF_SIZE]; 
    char lldp_filter_exp[] = "ether[12:2]=0x88cc";
    pcap_t* descr; 
    const u_char *packetData; 
    struct pcap_pkthdr packetHeader;
    struct bpf_program fp;        /* hold compiled program */


    /* open device for reading */
    descr = pcap_open_live(dev, BUFSIZ, 0,-1, errbuf); 
    if(descr == NULL) {
        fprintf(stderr, "Error calling pcap_open_live(): %s\n", errbuf);
        exit(1);
    } 

    pcap_setdirection(descr, PCAP_D_IN);

    /* compile the filter expression*/
    if(pcap_compile(descr, &fp, lldp_filter_exp, 0, PCAP_NETMASK_UNKNOWN) == PCAP_ERROR) {
        fprintf(stderr, "Error calling pcap_compile\n");
        exit(1);
    } 
 
    /* set the filter */
    if(pcap_setfilter(descr, &fp) == PCAP_ERROR) {
        fprintf(stderr, "Error setting filter\n");
        exit(1);
    } 

    /* loop for callback function */
    pcap_loop(descr, -1, callback_func, NULL);

    return 0; 
}

Solution

  • If you filter for specific bytes filter string should be "ether[12:2]==0x88cc". However as you want to filter for specific ether type i would use "ether proto 0x88cc". This also works for capturing device "any".

    Let me say that i also was surprised that your first filter string didn't work for device "any" and because of that i captured frames with wireshark on specific device as well as on device "any". The frames captured on device "any" use a different destination MAC address and there are two zero bytes inserted before ether type. That's why your filter string won't match. Up to now i didn't find an answer within documentation for this specific frame format for device "any" captures.

    Maybe anybody else could shed some light on that.

    Frame specific device: fc f8 ae 59 32 3d f0 c8 50 5b cc 3f 08 00 45 00

    Frame device "any": 00 00 00 01 00 06 f0 c8 50 5b cc 3f 00 00 08 00 45