Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Couldn't capture 802.11 radio beacon packets using Npcap SDK in Windows C++ #741

Open
kmramn opened this issue Jul 4, 2024 · 7 comments

Comments

@kmramn
Copy link

kmramn commented Jul 4, 2024

Describe the bug
I wrote a C++ program using Npcap SDK in Windows environment where I have enabled Wi-Fi in monitor mode. But the program is unable to capture Wi-Fi 802.11 Beacon packets. Using Wireshark application, I am able to capture the Wi-Fi 802.11 Beacon packets.

To Reproduce
Steps to reproduce the behavior:

#include <pcap.h>
#pragma comment(lib, "wpcap.lib")

#include <Windows.h>
#include <winerror.h>

#include <stdio.h>

#include <iostream>
using namespace std;

#include <tchar.h>
#include <strsafe.h>

#include <time.h>

BOOL LoadNpcapDlls()
{
    _TCHAR npcap_dir[512];
    UINT len;
    len = GetSystemDirectory(npcap_dir, 480);
    if (!len) {
        fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
        return FALSE;
    }
    _tcscat_s(npcap_dir, 512, _T("\\Npcap"));
    if (SetDllDirectory(npcap_dir) == 0) {
        fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
        return FALSE;
    }
    return TRUE;
}

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm ltime;
    char timestr[16];
    time_t local_tv_sec;

    (VOID)(param);
    (VOID)(pkt_data);

    /* convert the timestamp to readable format */
    local_tv_sec = header->ts.tv_sec;
    localtime_s(&ltime, &local_tv_sec);
    strftime(timestr, sizeof timestr, "%H:%M:%S", &ltime);

    printf("%s,%.6d len:%d\n",
        timestr, header->ts.tv_usec, header->len);
}

/* Main Decleration */
void wmain()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int inum;
    int i = 0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];

    /* Load Npcap and its functions. */
    if (!LoadNpcapDlls())
    {
        fprintf(stderr, "Couldn't load Npcap\n");
        exit(1);
    }

    /* Retrieve the device list on the local machine */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING,
        NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    /* Print the list */
    for (d = alldevs; d; d = d->next)
    {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)\n", d->description);
        else
            printf(" (No description available)\n");
    }

    if (i == 0)
    {
        printf("\nNo interfaces found! Make sure Npcap is installed.\n");
        return;
    }

    printf("Enter the interface number (1-%d):", i);
    scanf_s("%d", &inum);

    if (inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return;
    }

    /* Jump to the selected adapter */
    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);

    /* Open the device */
    if ((adhandle = pcap_open(d->name, // name of the device
        2048, // portion of the packet to capture
               // 65536 guarantees that the whole packet will
               // be captured on all the link layers
        PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
        1000, // read timeout
        NULL, // authentication on the remote machine
        errbuf // error buffer
    )) == NULL)
    {
        fprintf(stderr,
            "\nUnable to open the adapter. %s is not supported by Npcap\n",
            d->name);
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return;
    }
    //Try setting monitor mode and error check, trimmed down to the error I'm facing 
    int mm_set = pcap_can_set_rfmon(adhandle);
    if (mm_set == 0)
    {
        fprintf(stderr, "Error setting monitor mode: Device doesn't have MM capability\n");
    }
    else
    {
        if (!pcap_set_rfmon(adhandle, 1))
        {
            cout << "Monitor Mode Enabled, pcap_set_rfmon(...) == 0" << endl;
        }
    }
    cout << endl;

    //Using pcap_set_rfmon() here to illustrate issue, this will output a 0 
    //indicating success but the pcap_activate() error check contradicts this
    cout << pcap_set_rfmon(adhandle, 1) << endl;

    //int status = pcap_activate(adhandle);
    //Activate the interface for sniffing
    if (pcap_activate(adhandle))
    {
        cout << endl;
        pcap_perror(adhandle, "Error");
        cout << endl;
        pcap_set_rfmon(adhandle, 0);
        pcap_activate(adhandle);
    }

    printf("\nlistening on %s...\n", d->description);

    /* At this point, we don't need any more the device list. Free it */
    //pcap_freealldevs(alldevs);

    /* start the capture */
    pcap_loop(adhandle, 0, packet_handler, NULL);
}

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
Capturing the radio 802.11 Beacon using C++ is not working.
image

Capturing the radio 802.11 Beacon using Wireshark is working.
image

Is it possible to capture the radio 802.11 Beacon packets using C++ and Npcap SDK? If possible, can you please suggest me what correction U have to make? Thank you.

@guyharris
Copy link
Contributor

guyharris commented Jul 4, 2024

(Single quotes do not serve as "make this fixed-width text" brackets; you must use three backquotes, ```. Here's a properly-fixed-widthified, and better-indented, version of the code, which should be easier to read.)

#include <pcap.h>
#pragma comment(lib, "wpcap.lib")

#include <Windows.h>
#include <winerror.h>

#include <stdio.h>

#include 
using namespace std;

#include <tchar.h>
#include <strsafe.h>

#include <time.h>

BOOL LoadNpcapDlls()
{
    _TCHAR npcap_dir[512];
    UINT len;
    len = GetSystemDirectory(npcap_dir, 480);
    if (!len) {
        fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
        return FALSE;
    }
    _tcscat_s(npcap_dir, 512, _T("\Npcap"));
    if (SetDllDirectory(npcap_dir) == 0) {
        fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
        return FALSE;
    }
    return TRUE;
}

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm ltime;
    char timestr[16];
    time_t local_tv_sec;

    (VOID)(param);
    (VOID)(pkt_data);

    /* convert the timestamp to readable format */
    local_tv_sec = header->ts.tv_sec;
    localtime_s(&ltime, &local_tv_sec);
    strftime(timestr, sizeof timestr, "%H:%M:%S", &ltime);

    printf("%s,%.6d len:%d\n",
        timestr, header->ts.tv_usec, header->len);
}

/* Main Decleration */
void wmain()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int inum;
    int i = 0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];

    /* Load Npcap and its functions. */
    if (!LoadNpcapDlls())
    {
        fprintf(stderr, "Couldn't load Npcap\n");
        exit(1);
    }

    /* Retrieve the device list on the local machine */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING,
        NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    /* Print the list */
    for (d = alldevs; d; d = d->next)
    {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)\n", d->description);
        else
            printf(" (No description available)\n");
    }

    if (i == 0)
    {
        printf("\nNo interfaces found! Make sure Npcap is installed.\n");
        return;
    }

    printf("Enter the interface number (1-%d):", i);
    scanf_s("%d", &inum);

    if (inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return;
    }

    /* Jump to the selected adapter */
    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);

    /* Open the device */
    if ((adhandle = pcap_open(d->name, // name of the device
        2048, // portion of the packet to capture
              // 65536 guarantees that the whole packet will
              // be captured on all the link layers
        PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
        1000, // read timeout
        NULL, // authentication on the remote machine
        errbuf // error buffer
    )) == NULL)
    {
        fprintf(stderr,
            "\nUnable to open the adapter. %s is not supported by Npcap\n",
            d->name);
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return;
    }
    //Try setting monitor mode and error check, trimmed down to the error I'm facing 
    int mm_set = pcap_can_set_rfmon(adhandle);
    if (mm_set == 0)
    {
        fprintf(stderr, "Error setting monitor mode: Device doesn't have MM capability\n");
    }
    else
    {
        if (!pcap_set_rfmon(adhandle, 1))
        {
            cout << "Monitor Mode Enabled, pcap_set_rfmon(...) == 0" << endl;
        }
    }
    cout << endl;

    //Using pcap_set_rfmon() here to illustrate issue, this will output a 0 
    //indicating success but the pcap_activate() error check contradicts this
    cout << pcap_set_rfmon(adhandle, 1) << endl;

    //int status = pcap_activate(adhandle);
    //Activate the interface for sniffing
    if (pcap_activate(adhandle))
    {
        cout << endl;
        pcap_perror(adhandle, "Error");
        cout << endl;
        pcap_set_rfmon(adhandle, 0);
        pcap_activate(adhandle);
    }

    printf("\nlistening on %s...\n", d->description);

    /* At this point, we don't need any more the device list. Free it */
    //pcap_freealldevs(alldevs);

    /* start the capture */
    pcap_loop(adhandle, 0, packet_handler, NULL);
}

@guyharris
Copy link
Contributor

        if ((adhandle = pcap_open(d->name, // name of the device
...
        //Try setting monitor mode and error check, trimmed down to the error I'm facing 

pcap_open() does all the work to open a device; you can't set monitor mode after a device is opened.

You need to use pcap_create() and pcap_activate(), as well as:

  • pcap_set_snaplen() to set the snapshot length to 2048 (BTW, there's no guarantee that 65535 is large enough for all link layers; tcpdump and Wireshark currently default to 262144 for most devices);
  • pcap_set_timeout() to set the buffer timeout to 1 second (1000 milliseconds).

You do not need to set promiscuous mode if you're setting monitor mode.

Those should be done between pcap_create() and pcap_activate(), along with...

        //Using pcap_set_rfmon() here to illustrate issue, this will output a 0 
        //indicating success but the pcap_activate() error check contradicts this
        cout << pcap_set_rfmon(adhandle, 1) << endl;

...the pcap_set_rfmon() mode.

Older versions of libpcap would not catch attempts to set monitor mode after a pcap_t has been activated, so that call would do nothing and then return 0. Newer versions of libpcap - including the version that the current version of Npcap uses - will check whether the pcap_t is activated and return an error. (pcap_open_live() and pcap_open() return a pointer to an already-activated pcap_t; pcap_create() returns a pointer to an unactivated pcap_t.)

What version of Npcap are you using?

@kmramn
Copy link
Author

kmramn commented Jul 5, 2024

Npcap version in Control Panel

image

Earlier while installing through Wireshark, it was having the version 1.78. So, I have to uninstall manually and install 1.79

using pcap_lib_version()

image

I will definitely try your above suggestion.

@kmramn
Copy link
Author

kmramn commented Jul 18, 2024

This is the entire code that I wrote.

#include <pcap.h>
#pragma comment(lib, "wpcap.lib")
#include <Windows.h>
#include <winerror.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#include <tchar.h>
#include <strsafe.h>
#include <time.h>

BOOL LoadNpcapDlls()
{
    _TCHAR npcap_dir[512];
    UINT len;
    len = GetSystemDirectory(npcap_dir, 480);
    if (!len) {
        fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
        return FALSE;
    }
    _tcscat_s(npcap_dir, 512, _T("\\Npcap"));
    if (SetDllDirectory(npcap_dir) == 0) {
        fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
        return FALSE;
    }
    return TRUE;
}

void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm ltime;
    char timestr[16];
    time_t local_tv_sec;

    // unused variables
    (VOID)(param);
    (VOID)(pkt_data);

    // convert the timestamp to readable format
    local_tv_sec = header->ts.tv_sec;
    localtime_s(&ltime, &local_tv_sec);
    strftime(timestr, sizeof timestr, "%H:%M:%S", &ltime);

    printf("%s,%.6d len:%d\n",
        timestr, header->ts.tv_usec, header->len);
}

void wmain()
{
    const char *pcap_version = pcap_lib_version();
    printf("%s\n", pcap_version);

    pcap_if_t *alldevs;
    pcap_if_t *d;
    int inum;
    int i = 0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];

    // Load Npcap and its functions.
    if (!LoadNpcapDlls())
    {
        fprintf(stderr, "Couldn't load Npcap\n");
        exit(1);
    }

    // Retrieve the device list on the local machine
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING,
        NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    // Print the list
    for (d = alldevs; d; d = d->next)
    {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)\n", d->description);
        else
            printf(" (No description available)\n");
    }

    if (i == 0)
    {
        printf("\nNo interfaces found! Make sure Npcap is installed.\n");
        return;
    }

    printf("Enter the interface number (1-%d):", i);
    scanf_s("%d", &inum);

    if (inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        // Free the device list
        pcap_freealldevs(alldevs);
        return;
    }

    // Jump to the selected adapter
    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);

    for (int j = 0; d->name[j]; j++)
        cout << d->name[j] << endl;

    // Create pcap handle
    if ((adhandle = pcap_create(d->name, errbuf)) == NULL)
    //if ((adhandle = pcap_create((const char*)L"rpcap://Device/NPF_{A0C40D7F-C59D-4ECA-86A3-C4A30B549BE6}\0\0", errbuf)) == NULL)
    //if ((adhandle = pcap_create("any", errbuf)) == NULL)
    //if ((adhandle = pcap_create(NULL, errbuf)) == NULL)
    {
        printf("pcap_create() failed: %s\n", errbuf);
        exit(EXIT_FAILURE);
    }

    // Check if device can be put into monitor mode
    if (pcap_can_set_rfmon(adhandle) == 0)
    {
        printf("Monitor mode can not be set.\n");
        exit(EXIT_FAILURE);
    }

    // Attempt to put the card into monitor mode
    if (pcap_set_rfmon(adhandle, 1) != 0)
    {
        printf("Failed to set monitor mode.\n");
        exit(EXIT_FAILURE);
    }

    if (pcap_set_snaplen(adhandle, 2048) != 0)  // Set the snapshot length to 2048
    {
        printf("Failed to set snaplen.\n");
        exit(EXIT_FAILURE);
    }

    //if (pcap_set_promisc(adhandle, 0) != 0) // Turn promiscuous mode off
    //{
    //    printf("Failed to set pcap_set_promisc.\n");
    //    exit(EXIT_FAILURE);
    //}

    if (pcap_set_timeout(adhandle, 1000) != 0) // Set the timeout to 512 milliseconds
    {
        printf("Failed to set timeout.\n");
        exit(EXIT_FAILURE);
    }

    if (pcap_activate(adhandle) != 0)
    {
        printf("pcap_activate() failed\n");
        exit(EXIT_FAILURE);
    }

    //int status = pcap_activate(handler);
    //Try setting monitor mode and error check, trimmed down to the error I'm facing 
    int mm_set = pcap_can_set_rfmon(adhandle);
    if (mm_set == 0)
    {
        fprintf(stderr, "Error setting monitor mode: Device doesn't have MM capability\n");
    }
    else
    {
        if (!pcap_set_rfmon(adhandle, 1))
        {
            cout << "Monitor Mode Enabled, pcap_set_rfmon(...) == 0" << endl;
        }
    }
    cout << endl;

    //Using pcap_set_rfmon() here to illustrate issue, this will output a 0 
    //indicating success but the pcap_activate() error check contradicts this
    cout << pcap_set_rfmon(adhandle, 1) << endl;

    //int status = pcap_activate(adhandle);
    //Activate the interface for sniffing
    if (pcap_activate(adhandle))
    {
        cout << endl;
        pcap_perror(adhandle, "Error");
        cout << endl;
        pcap_set_rfmon(adhandle, 0);
        pcap_activate(adhandle);
    }

    printf("\nlistening on %s...\n", d->description);

    // At this point, we don't need any more the device list. Free it
    //pcap_freealldevs(alldevs);

    // start the capture
    pcap_loop(adhandle, 0, packet_handler, NULL);
}

But while calling pcap_create() it is throwing the following error.

pcap_create() failed: Error opening adapter: The filename, directory name, or volume label syntax is incorrect.  (123)

I also tried to hardcode the string in C++ as given below, but still I got the same error.

rpcap://\\Device\\NPF_{A0C40D7F-C59D-4ECA-86A3-C4A30B549BE6}
rpcap:\\\\Device\\NPF_{A0C40D7F-C59D-4ECA-86A3-C4A30B549BE6}
rpcap://Device\\NPF_{A0C40D7F-C59D-4ECA-86A3-C4A30B549BE6}
rpcap://\\\\Device\\NPF_{A0C40D7F-C59D-4ECA-86A3-C4A30B549BE6}

Is there any format that I need to follow? Thank you.

@guyharris
Copy link
Contributor

Is there any format that I need to follow?

Yes. Try just \Device\NPF_{A0C40D7F-C59D-4ECA-86A3-C4A30B549BE6} (with double backslashes if necessary). pcap_create() currently doesn't support URL syntax, but, as you're not doing a remote capture, the rpcap:// is unnecessary and can be omitted.

@guyharris
Copy link
Contributor

And just use pcap_findalldevs().

@kmramn
Copy link
Author

kmramn commented Jul 20, 2024

Thank you so much, now it is capturing.

image

I make habit of researching first and then post my doubts. But since this is helpful and working, so I will post my doubt directly in this thread. Can I reply to this 802.11 radio frames, provided, with my valid key properly? Thank you again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants