有什么方法可以改变同步Windows API SendARP的行为吗?

问题描述 投票:0回答:2

我正在 Windows 上编写一个本地网络扫描仪,用于查找具有 IP Helper Functions 的在线主机,这相当于

nmap -PR
,但没有 WinPcap。我知道如果远程主机没有响应,SendARP会阻塞并发送 3 次 arp 请求,所以我使用
std::aync
为每个主机创建一个线程,但问题是我想每 20ms 发送一个 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请求,如果没有来自远程主机的回复,它就超出了我的控制范围,并且我在一个线程中看到了很多请求。时间很短(<10ms) in Wireshark, so my question is:

  1. 有什么方法可以使
    SendARP
    异步吗?
  2. 如果没有,我可以控制线程中
    SendARP
    的发送时间吗?
c++ multithreading winapi asynchronous arp
2个回答
0
投票

似乎没有任何方法可以强制

SendARP
以非阻塞方式行事,看起来当主机无法访问时,它会尝试重新查询几次然后放弃。

至于解决方案,没有什么是你想听到的。 MSDN 文档指出,有一个较新的 API 弃用了

SendARP
,称为 ResolveIpNetEntry2,它也可以执行相同的操作,但它的行为方式似乎也相同。

它接收到的结构体包含一个名为

ReachabilityTime.LastUnreachable
的字段,它是: 节点在未收到可达性确认后假定邻居不可达的时间(以毫秒为单位)。

然而,似乎并没有任何实际效果。

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


0
投票

不幸的是,Windows中的SendARP函数没有提供用于异步执行或控制ARP请求时序的内置机制。它是一个阻塞功能,发送 ARP 请求并等待响应或超时,如果没有回复,您无法控制重新发送 ARP 请求的时机。

为了实现以受控时序异步发送 ARP 请求的目标,您需要使用原始套接字或较低级别的网络库来实现自己的 ARP 请求逻辑。这将使您能够更好地控制 ARP 请求的时间和并发性。

以下是您可以执行的操作的高级概述:

使用原始套接字或 libpcap/winpcap 等网络库发送 ARP 请求。 为每个要向其发送 ARP 请求的主机创建一个单独的线程。 在每个线程中,发送 ARP 请求并等待响应(您可以设置自己的超时时间)。 使用每个线程中的睡眠或其他机制控制 ARP 请求的时间。

以下是如何在单独的线程中使用原始套接字发送 ARP 请求的示例:

#include <iostream>
#include <vector>
#include <thread>
#include <chrono>

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

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

using namespace std;

void sendArpRequest(const char* ipAddress) {
    // Create a raw socket and send ARP request here.
    // You'll need to implement the ARP packet structure and send/receive logic.
    // Use Sleep or another mechanism to control the timing.
}

int main() {
    vector<thread> threads;

    for (int i = 1; i < 255; i++) {
        char ipAddress[20];
        sprintf(ipAddress, "192.168.1.%d", i);
        threads.emplace_back(sendArpRequest, ipAddress);
        this_thread::sleep_for(chrono::milliseconds(20)); // Control the timing
    }

    for (auto& thread : threads) {
        thread.join();
    }

    return 0;
}

使用原始套接字实现 ARP 请求可能很复杂,并且您需要在代码中处理 ARP 响应和超时。您可能还需要以提升的权限运行程序来创建原始套接字。此外,请确保您的代码中有适当的错误处理和资源管理。

© www.soinside.com 2019 - 2024. All rights reserved.