6

我必须编写一个 trceroute 脚本,但我不确定我的尝试是否正确。

现在我正在这样做(如果我做错或笨拙,请纠正我):

  1. 得到了 ip- 和 udpheader 的结构
  2. 校验和函数
  3. 打开 2 个套接字:一个用于以 SOCK_RAW 模式发送 UDP 数据包(用于操作 ttl),一个用于从路由器接收 ICMP 应答。
  4. 使用 sendto() 发送 UDP 数据包
  5. 不知道如何接收和处理 ICMP 答案

有没有比使用 sock_raw 我必须自己定义所有标题内容更舒适的方法来更改 TTL?打开 ICMP sock 时我应该为 socket() 使用哪些参数?如何接收 ICMP 答复?

4

3 回答 3

2

你的目标是什么平台?这是来自OpenBSD 源代码的 BSD 风格:

if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
    err(5, "icmp socket");
if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
    err(5, "raw socket");

我相信在 Linux 上,您需要使用IP_RECVERRand recvmsg(2)MSG_ERRQUEUE请参阅ip(7).

于 2011-02-03T13:47:52.913 回答
2

就设置 TTL 而言,您可以使用setsockopt(). ping这是 iputils在 Linux 上的源代码的摘录:

if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 1) == -1) {
    perror ("ping: can't set multicast time-to-live");
    exit(2);
}

if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) == -1) {
    perror ("ping: can't set unicast time-to-live");
    exit(2);
}
于 2011-02-03T14:03:07.670 回答
0

我遇到了同样的问题并解决了。你需要

  1. 使用 ICMP 协议创建一个新的套接字
  2. 绑定到特定端口,例如 33434
  3. 接收 ICMP 回复。

我将展示我的代码。

  // ......create sending socket and fill the udp data...

  // create socket to receive ICMP reply
    SOCKET sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,
                            WSA_FLAG_OVERLAPPED);

    // from for receiving data about routing server 
    SOCKADDR_IN server_addr, from;
    int fromlen = sizeof(from);
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(33434);

    // Set the receive and send timeout values to a second
    timeout = 1000;
    ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
                     sizeof(timeout));
    if (ret == SOCKET_ERROR) {
        printf("setsockopt(SO_RCVTIMEO) failed: %d\n", WSAGetLastError());
        return -1;
    }
    timeout = 1000;
    ret = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
                     sizeof(timeout));
    if (ret == SOCKET_ERROR) {
        printf("setsockopt(SO_SNDTIMEO) failed: %d\n", WSAGetLastError());
        return -1;
    }

    // bind to the port 33434
    int err = bind(sock, (SOCKADDR *)&server_addr, sizeof(SOCKADDR));
    if (err != 0) {
        fprintf(stderr, "bind with error: %d\n", WSAGetLastError());
        return 3;
    }

    for (ttl = 1; ((ttl < maxhops) && (!done)); ttl++) {
        int bwrote;
        // Set the time to live option on the socket
        set_ttl(sockRaw, ttl);
        // Fill in some more data in the UDP header
        ((UdpHeader *)udp_data)->length = 8;
        ((UdpHeader *)udp_data)->dest_port = htons(33434);
        ((UdpHeader *)udp_data)->source_port = htons(33434);
        ((UdpHeader *)udp_data)->checksum =
            checksum((USHORT *)udp_data, datasize);
        // Send the UDP packet to the destination
        bwrote = sendto(sockRaw, udp_data, datasize, 0, (SOCKADDR *)&dest,
                        sizeof(dest));
        if (bwrote == SOCKET_ERROR) {
            if (WSAGetLastError() == WSAETIMEDOUT) {
                printf("%2d  Send request timed out.\n", ttl);
                continue;
            }
            printf("sendto() failed: %d\n", WSAGetLastError());
            return -1;
        }
        // Read a packet back from the destination or a router along the way.
        ret = recvfrom(sock, recvbuf, MAX_PACKET, 0, (struct sockaddr *)&from,
                       &fromlen);
        if (ret == SOCKET_ERROR) {
            if (WSAGetLastError() == WSAETIMEDOUT) {
                printf("%2d  Receive Request timed out.\n", ttl);
                continue;
            }
            printf("recvfrom() failed: %d\n", WSAGetLastError());
            return -1;
        }
        /* Decode the response to see if the ICMP response is from a router
         * along the way or whether it has reached the destination. */
        done = decode_resp(recvbuf, ret, &from, ttl);
        Sleep(1000);
    }

它适用于我的电脑。(视窗 10)

结果在我的电脑里

于 2021-11-13T11:12:55.320 回答