5

したがって、私の目標は、WinSock と raw ソケットを使用して、すべての ICMP Time Exceeded パケット (IP パケットの TTL が 0 に達したときにゲートウェイによって生成される) をリッスンすることです。

私の最初のアプローチには 2 つのソケットがあり、1 つは TTL が 2 に設定された UDP で (TTL が 0 に達することがほぼ保証されています。wireshark はこれを確認しました)、もう 1 つは IPPROTO_ICMP を使用した SOCK_RAW です。

このアプローチは機能しませんでした。ICMP ソケットは、送信されたパケットに一致するパケットのみを返すと思います (つまり、エコー要求 -> エコー応答)。この方法をさらに推し進めて、SIO_RCVALL (プロミスキャス モード - ソケットがすべてを受け取る) をオンにしました。その言葉にほぼ忠実に、ICMP Time Exceeded (およびおそらく他のもの) を除いて、そのソケットですべてのインバウンドおよびアウトバウンド パケットを受信し始めました。これは、1 つのスレッドが 5 秒ごとに TTL 2 の UDP パケットを送信することによって示されますが、ICMP パケットは返されませんでした。ICMP が実際にまったく表示されていることを証明するために、cmd からの単純な ping に含まれる ICMP パケットを観察することができました。

私の 2 番目のアプローチは、UDP と ICMP を同じソケットに配置することでした。これには、IP および UDP ヘッダーの作成が含まれます。Wireshark は、パケット (チェックサムなど) の作成に問題がなく、予想どおりに UDP が送信されていることを示しています。また、ICMP Time Exceeded パケットが返されていることも示しています。繰り返しますが、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;     
    }
4

1 に答える 1

0

UDP パケットをリストしているマシンのタイプは何ですか? 一部のホスト ファイアウォールは、ICMP メッセージの送信を拒否します

于 2013-03-14T11:46:23.887 に答える