简体   繁体   中英

Listening for arbitrary ICMP Time Exceeded (TTL = 0) packets with WinSock

So my goal is to use WinSock and raw sockets in order to listen for all ICMP Time Exceeded packets (which are generated by gateways when the TTL of an IP packet reaches 0).

My first approach involved 2 sockets, one being UDP with TTL set to 2 (pretty much guaranteed to have TTL reach 0; wireshark confirmed this), and another one being SOCK_RAW with IPPROTO_ICMP.

This approach did not work - I assume the ICMP socket would only return packets matched to sent packets (ie, echo request -> echo reply). Pushing this method a little further, I turned on SIO_RCVALL (promiscuous mode - socket receives everything ). Almost true to it's word, I started receiving all inbound and outbound packets on that socket, with the exception of ICMP Time Exceeded (and possibly others). This is shown by having one thread send a UDP packet with TTL 2 every 5 seconds, however no ICMP packet was returned. To prove that ICMP was in fact showing up at all, I was able to observe the ICMP packets involved in a simple ping from cmd.

My second approach was to put the UDP and ICMP on the same socket. This involves me crafting the IP and UDP header. Wireshark shows the UDP going out, as expected with no issues with the creation of the packet (checksum, etc), and also shows the ICMP Time Exceeded packets being returned, however again I can't see any ICMP traffic coming on my socket (apart from again, when I test that ICMP is working with a simple ping).

So my question is, how on earth do you get your hands on these packets? I've had a look at a simple tracert program source code, but I couldn't see anything in there that I was doing too differently.

Socket Creation / Settings

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

Reading from socket

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

what is type of machine listining to your UDP packets ? some host firewalls deny sending ICMP messages

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM