如何在WinPcap中获取所选适配器的MAC地址?

时间:2017-12-11 08:33:32

标签: winpcap

例如,当程序运行时,我输入1作为输入,并希望在here中获取该接口的MAC地址。我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

我做了很多工作,试图找出如何在Windows下获取任意接口的mac地址,并将其与从WinPCap返回的设备信息相匹配。

很多帖子都说你应该使用GetAdaptersInfo或类似的函数来获取mac地址,但不幸的是,这些函数只适用于绑定了ipv4或ipv6的接口。我有一张故意没有绑定任何东西的网卡,因此Windows不会通过它发送任何数据。

然而,

GetIfTable()似乎实际上可以获得系统上的每个接口(我的有40个奇怪的接口)。它具有每个接口的硬件mac地址,因此您只需将其与相应的WinPCap设备匹配即可。 WinPCap中的设备名称具有较长的GUID,它也存在于从GetIfTable获取的接口表条目的名称字段中。但是,这些名称并不完全匹配,因此您必须从每个名称中提取GUID并将其匹配。另一个复杂因素是WinPCap设备中的名称字段是常规字符串,但是从GetIfTable获取的数据中的名称是一个宽字符串。下面的代码在两个不同的系统上工作,一个是Windows 7,另一个是Windows 10.我使用Microsoft GetIfTable示例代码作为起点:

#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "IPHLPAPI.lib")

#include <pcap.h>

// Compare the guid parts of both names and see if they match
int compare_guid(wchar_t *wszPcapName, wchar_t *wszIfName)
{
    wchar_t *pc, *ic;

    // Find first { char in device name from pcap
    for (pc = wszPcapName; ; ++pc)
    {
        if (!*pc)
            return -1;

        if (*pc == L'{'){
            pc++;
            break;
        }
    }

    // Find first { char in interface name from windows
    for (ic = wszIfName; ; ++ic)
    {
        if (!*ic)
            return 1;

        if (*ic == L'{'){
            ic++;
            break;
        }
    }

    // See if the rest of the GUID string matches
    for (;; ++pc,++ic)
    {
        if (!pc)
            return -1;

        if (!ic)
            return 1;

        if ((*pc == L'}') && (*ic == L'}'))
            return 0;

        if (*pc != *ic)
            return *ic - *pc;
    }
}

// Find mac address using GetIFTable, since the GetAdaptersAddresses etc     functions
// ony work with adapters that have an IP address
int get_mac_address(pcap_if_t *d, u_char mac_addr[6])
{
    // Declare and initialize variables.

    wchar_t* wszWideName = NULL;

    DWORD dwSize = 0;
    DWORD dwRetVal = 0;

    int nRVal = 0;

    unsigned int i;


    /* variables used for GetIfTable and GetIfEntry */
    MIB_IFTABLE *pIfTable;
    MIB_IFROW *pIfRow;

    // Allocate memory for our pointers.
    pIfTable = (MIB_IFTABLE *)malloc(sizeof(MIB_IFTABLE));
    if (pIfTable == NULL) {
        return 0;
    }
    // Make an initial call to GetIfTable to get the
    // necessary size into dwSize
    dwSize = sizeof(MIB_IFTABLE);
    dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE);

    if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
        free(pIfTable);
        pIfTable = (MIB_IFTABLE *)malloc(dwSize);
        if (pIfTable == NULL) {
            return 0;
        }

        dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE);
    }

    if (dwRetVal != NO_ERROR)
        goto done;

    // Convert input pcap device name to a wide string for compare
    {
        size_t stISize,stOSize;

        stISize = strlen(d->name) + 1;

        wszWideName = malloc(stISize * sizeof(wchar_t));

        if (!wszWideName)
            goto done;

        mbstowcs_s(&stOSize,wszWideName,stISize, d->name, stISize);
    }

    for (i = 0; i < pIfTable->dwNumEntries; i++) {
        pIfRow = (MIB_IFROW *)& pIfTable->table[i];

        if (!compare_guid(wszWideName, pIfRow->wszName)){
            if (pIfRow->dwPhysAddrLen != 6)
                continue;

            memcpy(mac_addr, pIfRow->bPhysAddr, 6);
            nRVal = 1;
            break;
        }
    }

done:
    if (pIfTable != NULL) 
        free(pIfTable);
    pIfTable = NULL;

    if (wszWideName != NULL)
        free(wszWideName);
    wszWideName = NULL;

    return nRVal;
}