Search code examples
c++pcappacket-snifferswinpcapsniffing

'pcap_loop' is not recording packets and isn't even running


I'm trying to do some simple packet capturing with pcap, and so I've created a handle to listen through eth0. My issue is with the pcap_loop(handle, 10, myCallback, NULL); line near the end of my code. I'm trying to use pcap_loop. The expected output is supposed to be:

eth0
Activated!
1
2
3
...
10
Done processing packets!

Current output is missing the increments:

eth0
Activated!
Done processing packets!

Currently it's just skipping right through to "Done processing packets!" and I have no idea why. Even if it doesn't go to the callback, it should still be waiting on packets as the ;count' parameter (see documentation for pcap_loop) is set to 10.

#include <iostream>
#include <pcap.h>
#include <stdlib.h>
#include <netinet/in.h> 
#include <arpa/inet.h>

void myCallback(u_char *useless, const struct pcap_pkthdr* hdr, const u_char*packet){
    static int count = 1;
    std::cout <<count<<std::endl;
    count ++;
}

int main(){
    char errbuf[PCAP_ERRBUF_SIZE];
    char * devName;
    char* net;
    char* mask;
    const u_char*packet;
    struct in_addr addr;
    struct pcap_pkthdr hdr;
    bpf_u_int32 netp;
    bpf_u_int32 maskp;

    pcap_if_t *devs;
    pcap_findalldevs(&devs, errbuf);
    devName = pcap_lookupdev(errbuf);
    std::cout <<devName<<std::endl;

    int success = pcap_lookupnet(devName, &netp, &maskp, errbuf);
    if(success<0){
        exit(EXIT_FAILURE);
    }
    pcap_freealldevs(devs);

    //Create a handle
    pcap_t *handle = pcap_create(devName, errbuf);
    pcap_set_promisc(handle, 1);
    pcap_can_set_rfmon(handle);

    //Activate the handle
    if(pcap_activate(handle)){
        std::cout <<"Activated!"<<std::endl;
    }
    else{
        exit(EXIT_FAILURE);
    }

    pcap_loop(handle, 10, myCallback, NULL);
    std::cout <<"Done processing packets!"<<std::endl;

    //close handle
    pcap_close(handle);
    }

Solution

  • pcap_findalldevs(&devs, errbuf);
    

    That call isn't doing anything useful, as you're not doing anything with devs other than freeing it. (You also aren't checking whether it succeeds or fails.) You might as well remove it unless you have some need to know what all the devices on which you can capture are.

    pcap_can_set_rfmon(handle);
    

    That all isn't doing anything useful, as you're not checking its return value. If you are capturing on a Wi-Fi device, and you want to capture in monitor mode, you call pcap_set_rfmon() - not pcap_can_set_rfmon() - on the handle after creating and before activating the handle.

    //Activate the handle
    if(pcap_activate(handle)){
        std::cout <<"Activated!"<<std::endl;
    }
    else{
        exit(EXIT_FAILURE);
    }
    

    To quote the pcap_activate() man page:

    RETURN VALUE
       pcap_activate()  returns  0  on  success  without  warnings, PCAP_WARN-
       ING_PROMISC_NOTSUP on success on a device that doesn't support  promis-
       cuous  mode  if promiscuous mode was requested, PCAP_WARNING on success
       with any other warning, PCAP_ERROR_ACTIVATED if the handle has  already
       been  activated, PCAP_ERROR_NO_SUCH_DEVICE if the capture source speci-
       fied when the handle was created doesn't exist,  PCAP_ERROR_PERM_DENIED
       if  the  process  doesn't  have  permission to open the capture source,
       PCAP_ERROR_RFMON_NOTSUP if monitor mode was specified but  the  capture
       source  doesn't  support  monitor  mode, PCAP_ERROR_IFACE_NOT_UP if the
       capture source is not up, and PCAP_ERROR if another error occurred.  If
       PCAP_WARNING  or PCAP_ERROR is returned, pcap_geterr() or pcap_perror()
       may be called with p as an argument  to  fetch  or  display  a  message
       describing  the  warning  or  error.   If  PCAP_WARNING_PROMISC_NOTSUP,
       PCAP_ERROR_NO_SUCH_DEVICE,  or  PCAP_ERROR_PERM_DENIED   is   returned,
       pcap_geterr()  or  pcap_perror() may be called with p as an argument to
       fetch or display an message giving additional details about the problem
       that might be useful for debugging the problem if it's unexpected.
    

    This means that the code above is 100% wrong - if pcap_activate() returns a non-zero value, it may have failed, and if it returns 0, it succeeded.

    If the return value is negative, it's an error value, and it has failed. If it's non-zero but positive, it's a warning value; it has succeeded, but, for example, it might not have turned promiscuous mode on, as the OS or device might not let promiscuous mode be set.

    So what you want is, instead:

    //Activate the handle
    int status;
    status = pcap_activate(handle);
    if(status >= 0){
        if(status == PCAP_WARNING){
            // warning
            std:cout << "Activated, with warning: " << pcap_geterror(handle) << std::endl;
        }
        else if (status != 0){
            // warning
            std:cout << "Activated, with warning: " << pcap_statustostr(status) << std::endl;
        }
        else{
            // no warning
            std::cout <<"Activated!"<<std::endl;
        }
    }
    else{
        if(status == PCAP_ERROR){
            std:cout << "Failed to activate: " << pcap_geterror(handle) << std::endl;
        }
        else{
            std:cout << "Failed to activate: " << pcap_statustostr(status) << std::endl;
        }
        exit(EXIT_FAILURE);
    }