【问题标题】:Any way to change the behavior of synchronous Windows API SendARP?有什么方法可以改变同步 Windows API SendARP 的行为?
【发布时间】:2017-09-23 09:12:26
【问题描述】:

我正在 Windows 上编写一个本地网络扫描程序来查找具有 IP 助手功能的在线主机,这相当于 nmap -PR 但没有 WinPcap。我知道SendARP 会在远程主机没有响应的情况下阻塞并发送 3 次 arp 请求,所以我使用std::aync 为每个主机创建一个线程,但问题是我想每 20 毫秒发送一次 ARP 请求所以在很短的时间内不会有太多的arp数据包。

#include <iostream>
#include <future>
#include <vector>

#include <winsock2.h>
#include <iphlpapi.h>


#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

using namespace std;

int main(int argc, char **argv)
{
    ULONG MacAddr[2];       /* for 6-byte hardware addresses */
    ULONG PhysAddrLen = 6;  /* default to length of six bytes */
    memset(&MacAddr, 0xff, sizeof (MacAddr));
    PhysAddrLen = 6;

    IPAddr SrcIp = 0;
    IPAddr DestIp = 0;

    char buf[64] = {0};

    size_t start = time(NULL);

    std::vector<std::future<DWORD> > vResults;

    for (auto i = 1; i< 255; i++)
    {
        sprintf(buf, "192.168.1.%d", i);
        DestIp = inet_addr(buf);
        vResults.push_back(std::async(std::launch::async, std::ref(SendARP), DestIp, SrcIp, MacAddr, &PhysAddrLen));
        Sleep(20);
    }

    for (auto it= vResults.begin(); it != vResults.end(); ++it)
    {
        if (it->get() == NO_ERROR)
        {
            std::cout<<"host up\n";
        } 
    }

    std::cout<<"time elapsed "<<(time(NULL) - start)<<std::endl;

    return 0;
}

起初我可以通过在启动线程后调用Sleep(20) 来做到这一点,但是一旦这些线程中的SendARP 重新发送 ARP 请求,如果没有来自远程主机的回复,它就超出了我的控制范围,我看到了很多请求在 Wireshark 中很短的时间内(

  1. 有什么方法可以使SendARP 异步?
  2. 如果不行,可以在线程中控制SendARP的发送时间吗?

【问题讨论】:

  • 简单地限制未解决的 ARP 请求的数量似乎更实用。即首先发送 5 个请求,当您收到回复时,发送更多。
  • 我想要一个本地网络的快速 ARP 扫描(在 5 秒内),对于典型的 /24 网络,每 20 毫秒发送一次 ARP 请求扫描整个网络大约需要 5 秒,但 SendARP 可能如果远程主机在 Windows 7/8/10 上关闭,则阻止 3 秒。
  • 我错过了这个问题。 “在很短的时间内有很多请求”表明速率太高,而“我想要快速扫描”表明速率太低。它是什么?您将需要 254 个线程,因为在 5 秒的时间间隔内不能有两个持续 3 秒的阻塞调用。所有 254 个呼叫必须在前两秒内启动。
  • 鉴于您无法控制 SendArp 超时和重新传输的内部...使用原始套接字发送您自己的 arp 请求可能是唯一的选择...缺点是应用程序必须以管理员身份运行...
  • 这正是我想做的——控制速率,每 20 毫秒发送一次请求。如果SendARP 只发送一个 ARP 请求,我可以启动一个线程然后休眠 20 毫秒,但它没有。

标签: c++ multithreading winapi asynchronous arp


【解决方案1】:

似乎没有任何方法可以强制SendARP以非阻塞方式进行操作,看起来当主机无法访问时,它会尝试重新查询几次才放弃。

至于解决方案,你不想听。 MSDN Docs 声明有一个新的 API 弃用了 SendARP,称为 ResolveIpNetEntry2,它也可以做同样的事情,但它的行为似乎也相同。

它接收到的结构包含一个名为ReachabilityTime.LastUnreachable 的字段,即:节点在没有收到可达性确认后假定邻居不可达的时间,以毫秒为单位。

但是,它似乎没有任何实际效果。

最好的方法是使用 WinPCap 或其他驱动程序,似乎没有办法在用户空间中解决您的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-05
    • 2017-02-23
    • 1970-01-01
    • 2018-04-14
    • 2011-11-29
    • 2019-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多