2013-02-07 7 views
1

Traceroute 프로그램을 구현하려고하지만 두 가지 문제가 발생했습니다. 하나는 TTL과 RTT가 잘못 인쇄됩니다. 핑 (ping) 프로그램으로 구현 될 때 바로 출력 할 수 있습니다. 마지막으로 내 주된 문제는 TTL을 증가시킬 때 1 대신 2가 올라간다는 것입니다.TTL 값이 매번 2 씩 증가하는 이유는 무엇입니까? (C 소켓 프로그래밍)

필자는 필요하다고 생각하는 코드만을 포함 시켰습니다.

void 
respond (int signum) { 
    struct sockaddr_storage peer_addr; 
    socklen_t    peer_addrlen; 
    struct sockaddr_in  addr; 
    struct sockaddr_in  dstaddr; 
    struct iphdr *  ip; 
    struct icmphdr *  icmp; 
    struct timeval *  sent; 
    int skt; 
    int sequence; 
    long int length; 
    fd_set rdfds; 
    int ready; 
    int rtt; 
    char buff [BUF_SIZE]; 

    /* Create and check Socket Number */ 
    skt = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 


    int ttl = 0; 
    setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0; 


    /* START SEND LOOP*/ 
    int i; 
    for (i = 0; i < 4; i++){ 
     ttl+=1; 
     setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 


    /* Check Socket */ 
    if (skt < 0) { 
     perror ("socket()"); 
     exit (1); 
    } 

    /* Set IP Addresses */ 
    addr.sin_family  = AF_INET; 
    addr.sin_port  = 0; 
    addr.sin_addr.s_addr = INADDR_ANY; 


    /* Check Socket Bind */ 
    if (bind (skt, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) { 
     perror ("Can't bind socket"); 
     exit (1); 
    } 

    /* IP Buffer */ 
    ip = (struct iphdr *)buff; 
    peer_addrlen = (socklen_t) sizeof (struct sockaddr_storage); 
    memset (&dstaddr, 0, sizeof(struct sockaddr_in)); 
    dstaddr.sin_addr.s_addr = inet_addr(HOSTADDR); 
    dstaddr.sin_family = AF_INET; 

    ip->ttl=(ttl++); 

    /* ICMP Buffer */ 
    memset (buff, 0, sizeof(buff)); 
    icmp = (struct icmphdr *) buff; 
    icmp->type = ECHO_REQ; 
    icmp->id  = htons(getpid() & 0xffff); 
    icmp->seqNum = htons(sequence++); 


    /* Check Send Time */ 
    if (gettimeofday ((struct timeval *)icmp->data, NULL)) { 
     perror ("Can't establish send time"); 
     exit (1); 
    } 

    /*Calculating packet size*/ 
    length = sizeof(struct icmphdr) + sizeof(struct timeval); 
    icmp->checksum = ~(sum (0, buff, length)); 



    /* Packet too small, ERROR 
    SEND Request    */ 
    if (sendto (skt, buff, length, 0, 
     (struct sockaddr *) &dstaddr, sizeof(struct sockaddr_in)) <= 0) { 
     perror ("sendto()"); 
     exit (1); 
} 

    /* Define File Descriptor */ 
    timeout.tv_sec = 2; 
    timeout.tv_usec = 0; 
    FD_ZERO(&rdfds); 
    FD_SET (skt, &rdfds); 

    /* Select Data from File Descriptor */ 
    ready = select (skt + 1, &rdfds, NULL, NULL, &timeout); 
    if (ready < 0) { 
     perror ("Select()"); 
     exit (1); 
    } 

/* Recieve Reply */ 
memset (buff, 0, sizeof(buff)); 
    if (recvfrom (skt, buff, sizeof(buff), 0, 
     (struct sockaddr *) &peer_addr, &peer_addrlen) <= 0) exit (1); 



    /* Check Time Stamp */ 
    if (gettimeofday (&end, NULL)) { // Timestamp reception 
     perror ("Can't establish time of receipt"); 
     exit (1); 
    } 


    /* Check IP Protocol */ 
    if (ip->version != 4 || 
     sum (0, buff, sizeof(struct iphdr)) != 0xffff || 
     ip->protocol != ICMP) 
     exit(1); 


    /* Get IP Payload legth and ICMP Address*/ 
    length = ntohs(ip->length) - ip->hdrlen * 4;  // Length of IP payload 
    icmp = (struct icmphdr *)((uint32_t *)ip + ip->hdrlen); // Find ICMP hdr 


    /* Check ICMP response type*/ 
    if (icmp->type == 11){ 
     printf("Type 11: ICMP...."); 
     } 

    /* if (icmp->type != ECHO_REPL || sum (0, icmp, length) != 0xffff) { 
     fprintf (stderr, "Received %s\n", messages[icmp->type]); 
     //exit (1); 
    } */ 

    /* Find the difference between sent and end times in 10s of ms */ 
    sent = (struct timeval *)icmp->data; 
    if ((rtt = (end.tv_usec - sent->tv_usec)/100) < 0) 
     rtt += 10000; // We've cycled to a new second 
    rtt += (end.tv_sec - sent->tv_sec) * 10000; // Add any seconds 

    /* PRINT ICMP REPLY*/ 
    printf ("%ld bytes from %s: icmp_req=%d ttl=%d time=%0.1f ms\n", 
     length, 
     iptos(ntohl(ip->srcip)), 
     ntohs(icmp->seqNum), 
     /*Set initial TTL */ 
     ip->ttl, 
     ((float)rtt)/10); 


    } /*END SEND LOOP 

    /* Invalid Signal returned */ 
    if (signum == SIGINT) { 
     printf ("\nGoodbye!\n"); 
     exit(0); 
    } 

    /* 3 Second Probe */ 
    alarm (3); 
} 

답변

1
/* START SEND LOOP*/ 
int i; 
for (i = 0; i < 4; i++){ 
    ttl+=1; 
    setsockopt(skt, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 

: 사전에

덕분에 여기 하나마다 루프 반복에 의해 ttl을 높일 수 있습니다.

ip->ttl=(ttl++); 

여기에서 다시 한 번 증가시킵니다. 따라서 1 인 경우이 줄 뒤에 2가됩니다. 그러나 루프가 반복되면 다시 증가하므로 3이됩니다. 그래서 각 반복마다 두 개씩 증가합니다.

줄의 의미는 ttl이고 그 값을 ip->ttl으로 복사 한 다음 ttl을 1 늘립니다.

+0

당신이이기는 첫번째 사람 : P –

1

루프에서 ttl을 두 번 증가시키고 있습니다. For 루프가 시작되면 일단 :

ttl+=1; 

을 다시 구조체 RTT에 관해서는

ip->ttl=(ttl++); 

에 할당하면서, 물론 그 코드는 나에게 잘못 보인다.

+0

고마워, 나는 그것을 완전히 놓쳤다. RTT는이 프로그램이 ping을 수행 할 때 작동했지만 더 이상은 아닙니다./ –

+0

RTT에 대해 나에게 이상한 점은 더 크거나 같아야하는 숫자를 뺀 다음 100으로 나눠야한다는 것입니다. 그러나 결과가 항상 0보다 크고 결과가 <0이고 10,000을 더하는 지 확인하고 있습니다. (이미 100으로 나눈 값이므로 다시 틀린 것으로 보이므로 추가하지 말아야합니다. on 10?) 다음 줄에서 다시 10 분의 1 초가 아닌 1 초로 변환됩니다. – Eric