无法获取 IP 地址与 pcap_findalldevs

Can't get the ip address with pcap_findalldevs

本文关键字:pcap findalldevs 地址 获取 IP      更新时间:2023-10-16

我使用pcap_findalldevs来获取计算机中的设备列表。我成功地获得了设备名称和描述,但我不知道为什么,我获得Netmask 0.0.0.0和ip地址也0.0.0.0。下面是生成列表的代码:

/* get the devices list */
if (pcap_findalldevs(&devList, errbuf) == -1)
{
    fprintf(stderr, "There is a problem with pcap_findalldevs: %sn", errbuf);
    return -1;
}
/* scan the list for a suitable device to capture from */
for (dev = devList; dev != NULL; dev = dev->next)
{
    pcap_addr_t *dev_addr; //interface address that used by pcap_findalldevs()
    /* check if the device captureble*/
    if ((dev_addr = dev->addresses) != NULL && dev_addr->addr->sa_family == AF_INET && dev_addr->addr && dev_addr->netmask) {
        printf("Found a device %s on address %s with netmask %sn", dev->name, iptos(((struct sockaddr_in *)dev_addr->addr)->sin_addr.s_addr), iptos(((struct sockaddr_in *)dev_addr->netmask)->sin_addr.s_addr));
        break;
    }
}

这是你应该做的:

/* get the devices list */
if (pcap_findalldevs(&devList, errbuf) == -1)
{
    fprintf(stderr, "There is a problem with pcap_findalldevs: %sn", errbuf);
    return -1;
}
/* scan the list for a suitable device to capture from */
for (dev = devList; dev != NULL; dev = dev->next)
{
    pcap_addr_t *dev_addr; //interface address that used by pcap_findalldevs()
    /* check if the device captureble*/
    for (dev_addr = dev->addresses; dev_addr != NULL; dev_addr = dev_addr->next) {
        if (dev_addr->addr->sa_family == AF_INET && dev_addr->addr && dev_addr->netmask) {
            printf("Found a device %s on address %s with netmask %sn", dev->name, iptos(((struct sockaddr_in *)dev_addr->addr)->sin_addr.s_addr), iptos(((struct sockaddr_in *)dev_addr->netmask)->sin_addr.s_addr));
            goto found;
        }
    }
}
found:
这样,您就可以检查整个地址列表,而不仅仅是列表中的第一个地址。如果,当您到达found时,dev是非空的,它指向至少有一个IPv4地址的设备,并且dev_addr指向该地址。
如果"dev"为空,表示没有IPv4地址的设备。

来自andrew Medico的帖子让我想到了这个解决方案:

首先使用const auto进行初始化。这是一个const char*。我还得到了ip地址的子网掩码。由于iptos()不能为我工作,我将声明更改为const string。

const string interface_ip = inet_ntoa(reinterpret_cast<struct sockaddr_in*>(address->addr)->sin_addr);
const string interface_netmask = inet_ntoa(reinterpret_cast<struct sockaddr_in*>(address->netmask)->sin_addr);

希望这篇文章能帮助到别人,就像它曾经帮助过我一样。

在找到第一个接口后退出循环,该接口可能是环回接口。

这是我过去使用的代码(我跳过地址为0.0.0.0的环回):

    for(pcap_if_t* pInterface(m_pAllDevices); pInterface != 0; pInterface = pInterface->next)
    {
        if((pInterface->flags & PCAP_IF_LOOPBACK) != 0) // Skip loopback interfaces
        {
            continue;
        }
        std::string address;
        if(pInterface->addresses != 0)
        {
#if defined(WIN32)
            static char tempChar[1] = {0};
            DWORD stringSize(0);
            if(pInterface->addresses != 0 && WSAAddressToStringA(pInterface->addresses->addr, sizeof(*(pInterface->addresses->addr)), 0, tempChar, &stringSize) == SOCKET_ERROR && WSAGetLastError() == WSAEFAULT)
            {
                address.resize((size_t)stringSize);
                WSAAddressToStringA(pInterface->addresses->addr, sizeof(*(pInterface->addresses->addr)), 0, &(address[0]), &stringSize);
            }
#else
            char tempBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, pInterface->addresses->addr, tempBuffer, sizeof(tempBuffer));
            address = tempBuffer;
#endif
        }
    }

来自WinPcap的iptos示例使用单个静态缓冲区来生成结果。这意味着当您调用它两次时,第二次调用的结果将覆盖第一次调用的结果。

因此你的代码:

printf("Found a device %s on address %s with netmask %sn",
       dev->name, iptos(<addr-expr>), iptos(<mask-expr>));

将始终在地址和netmask位置打印相同的值(地址或netmask,取决于编译器的参数求值顺序)。

要纠正这个问题,可以复制结果字符串并将它们保存到单独的变量中,如下所示:

char* addr = strdup(iptos(<addr-expr>));
char* mask = stdrup(iptos(<mask-expr>));
printf("Found a device %s on address %s with netmask %sn",
       dev->name, addr, mask>);
free(addr);
free(mask);

这对我有用。打开网络连接设置。右键单击我们的连接并选择属性。现在取消选中Internet协议版本6(TCP/IPV6)。现在运行您的应用程序,您将获得正确的IP地址。