【问题标题】:Can't get the ip address with pcap_findalldevs无法使用 pcap_findalldevs 获取 IP 地址
【发布时间】:2023-03-15 02:22:01
【问题描述】:

我正在使用 pcap_findalldevs 来获取计算机中的设备列表。我成功地得到了它,带有设备的名称和描述,但我不知道为什么,我得到了网络掩码 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: %s\n", 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 %s\n", 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;
    }
}

【问题讨论】:

  • 您没有遍历界面的所有地址 - winpcap 返回地址列表的方式是否可能有些奇怪。您应该枚举 dev->addresses 列表中列出的所有地址。
  • 我在互联网上搜索,每个人都像我一样做..我不知道为什么它不起作用..
  • “我在互联网上搜索,每个人都像我一样做。”好吧,他们都做错了;也许他们很幸运,当他们的代码运行时,IPv4 地址恰好位于列表的开头,但是假设列表总是在列表开头有一个 IPv4 地址的代码代码不正确。

标签: c++ networking pcap libpcap winpcap


【解决方案1】:

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

这是我过去使用的代码(我跳过了地址为 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
        }

    }

【讨论】:

  • 即使在我删除了中断并对其进行调试后,我得到了正确的界面,但它显示地址和网络掩码为 0.0.0.0..
  • 你可以在这里看到调试:prntscr.com/3ttlck为什么sa_family是23(AF_INET6)?它应该是 2(AF_INET) 不是吗?谢谢
  • 在调试中我看到你有 dev->addresses->next,它包含在 IPv4 地址中。尝试展开它并查看 IPv4 地址是否在其中。可能您的卡有两个地址(一个用于 IPv6,一个用于 IPv4)
【解决方案2】:

iptos example from WinPcap 使用单个静态缓冲区来生成结果。这意味着当你调用它两次时,第二次调用的结果会覆盖第一次调用的结果。

因此你的代码:

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

将始终在地址和网络掩码位置打印相同的值(地址或网络掩码,取决于编译器的参数评估顺序)。

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

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

【讨论】:

  • 它不起作用.. prntscr.com/3ttu2o 问题是当我生成列表时我得到 0.0.0.0.. 请查看我的其他评论以查看调试.. 谢谢!
【解决方案3】:

这是你应该做的:

/* get the devices list */
if (pcap_findalldevs(&devList, errbuf) == -1)
{
    fprintf(stderr, "There is a problem with pcap_findalldevs: %s\n", 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 %s\n", 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 地址的设备。

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 我不认为本地配置可以解决编程问题。您是否还要要求安装您的 c++ 应用程序的每个人也更改他们自己计算机上的设置?
    • 这是您可以为上述问题获得临时解决方案的一种方式。我为 Windows XP 编写的程序运行良好,现在当我尝试将代码移植到 Windows 7 时,我面临上述问题(因为对于单个接口,W7 中同时存在 IPv6 和 IPv4,而 XP 只有 IPV4)。这可以通过在代码中忽略 IPv6 地址(如前所述)或禁用 IPV6 来解决,如果你不想更改代码。两者都工作正常。我清楚吗...
    【解决方案5】:

    来自 Anrew Medico 的 post 让我想到了这个解决方案:

    起初我使用 const auto 进行初始化。这是一个 const char*。而且我还得到了 IP 地址的子网掩码。由于 iptos() 对我不起作用,我将 deklaration 更改为 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);
    

    希望这对其他人有所帮助,就像它帮助了我一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      • 2010-11-04
      • 2023-03-09
      • 1970-01-01
      相关资源
      最近更新 更多