使用WinSock侦听任意ICMP Time Exceeded(TTL = 0)数据包

Har*_*ock 5 c++ sockets windows networking winsock

所以我的目标是使用WinSock和原始套接字来监听所有ICMP Time Exceeded数据包(当IP数据包的TTL达到0时由网关生成).

我的第一种方法涉及2个套接字,一个是UDP,TTL设置为2(几乎保证TTL达到0; wireshark证实了这一点),另一个是SOCK_RAW和IPPROTO_ICMP.

这种方法不起作用 - 我假设ICMP套接字只返回与发送数据包匹配的数据包(即echo请求 - > echo reply).再推进这个方法,我打开了SIO_RCVALL(混杂模式 - socket接收所有内容).几乎是真的,我开始接收该套接字上的所有入站和出站数据包,但ICMP Time Exceeded(以及可能的其他)除外.这通过让一个线程每5秒发送一个TTL 2的UDP数据包来显示,但是没有返回ICMP数据包.为了证明ICMP实际上已经出现,我能够观察到来自cmd的简单ping中涉及的ICMP数据包.

我的第二种方法是将UDP和ICMP放在同一个套接字上.这涉及到我制作IP和UDP标头.Wireshark的显示UDP走出去,为与创建包(校验等)没有任何问题预期,也说明了返回的ICMP已超时数据包,但是我又不能看到任何ICMP流量在我的插座来(除此之外,当我测试ICMP正在使用简单的ping时).

所以我的问题是,你究竟如何得到这些数据包?我已经看过一个简单的tracert程序源代码,但我在那里看不到任何我做得太不同的东西了.

套接字创建/设置

        SOCKET s;

        if((s = socket(AF_INET, SOCK_RAW, 0)) == SOCKET_ERROR)
        {
            cout << "socket(AF_INET, SOCK_RAW, 0) failed with error code: " << WSAGetLastError() << endl;
            return 1;
        }


        sockaddr_in source;
        memset(&source, 0, sizeof(source));
        source.sin_family = AF_INET;
        source.sin_port = 0;
        source.sin_addr.S_un.S_addr = inet_addr("10.64.0.8");

        if(bind(s, (sockaddr*) &source, sizeof(source)) == SOCKET_ERROR)
        {
            cout << "bind failed with error: " << WSAGetLastError() << endl;
            return 1;
        }

        uint32_t optval = 1;
        DWORD bytesReturned;

        if (WSAIoctl(s, SIO_RCVALL, &optval, sizeof(optval), NULL, 0, &bytesReturned, NULL, NULL) == SOCKET_ERROR)
        {
            cout << "WSAIotcl() failed with error code " << WSAGetLastError() << endl;
            return 1;
        }

        if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*) &optval, sizeof(optval)) == SOCKET_ERROR)
        {
            cout << "Failed to remove IP header. Error code: " << WSAGetLastError() << endl;
            return 1;
        }
Run Code Online (Sandbox Code Playgroud)

从套接字读取

    if(WSARecvFrom(s, &buffer, 1, &in, &flags, (sockaddr*) &from, &fromSize, &ol, NULL) == SOCKET_ERROR)
    {
        int error = WSAGetLastError();
        if(error != WSA_IO_PENDING)
        {
            cout << "WSARecvFrom Failed with error code: " << error << endl;
            return;
        }
    }

    int rc = WaitForSingleObject(ol.hEvent, INFINITE);
    if(rc == WAIT_FAILED)
    {
        cout << "Wait for object failed" << endl;
        return;
    }

    WSAGetOverlappedResult(s, &ol, &in, false, &flags);

    ipv4_header_t* ipHeader = (ipv4_header_t*) buf;

    if(ipHeader->dest == addr)
    {
        cout << "Received Protocol: " << (uint32_t) ipHeader->protocol << endl;     
    }
Run Code Online (Sandbox Code Playgroud)

小智 0

侦听您的 UDP 数据包的机器是什么类型?某些主机防火墙拒绝发送 ICMP 消息