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

时间:2012-12-26 20:03:51

标签: c++ windows sockets networking winsock

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

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

这种方法不起作用 - 我假设ICMP套接字只返回与发送数据包匹配的数据包(即echo请求 - > echo回复)。 推进这个方法,我打开了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;
        }

从套接字

读取
    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;     
    }

1 个答案:

答案 0 :(得分:0)

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