好的,所以我尝试使用讲师提供的 Material 编写一个简单的ICMP跟踪路由,这些 Material 是我想合并以实现目标的echo_request和icmp_receive程序,但这种方法行不通。

您可以看到这些程序的代码以及我包含在我的代码>here<中的其他代码

请记住,我是套接字编程的初学者。我从今天开始,但我仍然不了解某些事情。

所以我的代码看起来像这样(它不是traceroute的最终版本!这只是我认为应该给出一些结果的一个片段):

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netinet/ip_icmp.h>
#include "sockwrap.h"
#include "icmp.h"
#include <time.h>

unsigned char   buffer[IP_MAXPACKET+1];
unsigned char*  buffer_ptr;
int             re;

int main(int argc, char **argv){
    if(argc != 2){
        printf("Usage: ./traceroute <ip>\n");
        return 1;
    }

    int sockfd = Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

    struct sockaddr_in remote_address;
    bzero (&remote_address, sizeof(remote_address));
    remote_address.sin_family = AF_INET;
    inet_pton(AF_INET, argv[1], &remote_address.sin_addr);

    int ttl = 1;

    while(1){
        struct icmp icmp_packet;
        icmp_packet.icmp_type = ICMP_ECHO;
        icmp_packet.icmp_code = 0;
        icmp_packet.icmp_id = 123;
        icmp_packet.icmp_seq = ttl;
        icmp_packet.icmp_cksum = 0;
        icmp_packet.icmp_cksum = in_cksum((u_short*)&icmp_packet, 8, 0);

        Setsockopt (sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(int));

        Sendto(sockfd, &icmp_packet, ICMP_HEADER_LEN, 0, &remote_address, sizeof(remote_address));
        Sendto(sockfd, &icmp_packet, ICMP_HEADER_LEN, 0, &remote_address, sizeof(remote_address));
        Sendto(sockfd, &icmp_packet, ICMP_HEADER_LEN, 0, &remote_address, sizeof(remote_address));

        clock_t start = clock();
        float seconds = 0;
        while(seconds < 1){
            clock_t c = clock();
            seconds = (float)(c - start)/CLOCKS_PER_SEC;
        }

        struct sockaddr_in sender;
        socklen_t sender_len = sizeof(sender);
        buffer_ptr = buffer;
        re = Recvfrom (sockfd, buffer_ptr, IP_MAXPACKET,
                                            0, &sender, &sender_len);

        char str[20];
        inet_ntop(AF_INET, &(sender.sin_addr), str, sizeof(str));
        // this printf shows me ip adresses of routers on route to
        // destination(probably?), but anything below it doesn't seem to work
        // properly :(
        //printf ("%s\n", str);

        struct icmp* icmp_packet_recv = (struct icmp*) buffer_ptr;

        printf("%d %d\n", icmp_packet_recv->icmp_id, icmp_packet_recv->icmp_seq);

        if (icmp_packet_recv->icmp_type == ICMP_TIME_EXCEEDED &&
            icmp_packet_recv->icmp_code == ICMP_EXC_TTL) {

            struct ip* packet_orig = (struct ip*) buffer_ptr;

            if (packet_orig->ip_p == IPPROTO_ICMP) {
                if(icmp_packet_recv->icmp_seq == ttl && icmp_packet_recv->icmp_id == 123)
                    printf ("%s\n", str);
            }
        }
        if (icmp_packet_recv->icmp_type == ICMP_ECHOREPLY) {
            printf ("%s\n", str);
            return 0;
        }

        ttl++;
    }

    return 0;
}

之所以可以这样工作,是因为当我printf("%s\n", str);的str是发件人的ip时,它看起来像是在跟踪路由,但是当我要检查接收到的软件包时,它会确定与我发送的邮件不同的icmp_idicmp_seq。这对我来说似乎很奇怪,因为当我运行echo_requesticmp_receive并发送一个包含id 123和seq 1的程序包时,我收到了完全相同的idseq,但是在我的程序中它是不同的(我正在通过此printf("%d %d\n", icmp_packet_recv->icmp_id, icmp_packet_recv->icmp_seq);检查的内容)。

如果您能指出我在代码中正在做愚蠢的事情并加以解释,我将不胜感激。结果这项任务比我预期的要难。

最佳答案

调用re之后,您需要检查Recvfrom。可能会有错误,也可能是您期望的长度不同。

另外,正如我记得的那样,使用此RAW套接字,您将获得所有发送到您的网络接口(interface)的ICMP数据包;因此,您需要接收所有数据包,并且只能使用包含相同序列号的数据包。

而且我看不到bind()。没必要吗?

关于c - C语言中简单的icmp traceroute实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29344543/

10-10 01:54