2013-02-08 110 views
0

是否有人可以帮助我锻炼为什么我的ICMP序列号不会在每个请求中递增,当它被用作ping程序时,它会增加每个ping的序列号。 也没有人有任何想法为什么我的往返时间显示为负数?当这是一个ping程序时,这也工作得很好。为什么我的ICMP序列号不递增? (C Socket编程)

请承担所有的代码'作品',我已经删除了一些更容易阅读。

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 = 0; 
    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; 


     /* 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); 
     } 

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

     /* 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; 

     /* 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 = 1; 
     timeout.tv_usec = 1; 
     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(""); 
      } 

     /* 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)/10) < 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), 
     ip->ttl, 
     ((float)rtt)/10); 


} /*END SEND LOOP 


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

回答

2

你永远设置在此代码序列为0,只宣称它是一个int。

+0

同样的问题仍然存在,它在这个程序的ping版本中工作 –

+0

对于所有7次迭代它是否保持0?您也可以使用您添加的任何修补程序更新代码。 – Eric

+1

哦,我看到发生了什么。您将在循环的每次迭代过程中重新分配“icmp”的值。首先,它是为你的传出数据包,然后重新分配对该变量的响应。 发生了什么是您将序列设置为3,但TTL过期正在被发送回来,将序列重置为0.当您和目标之间存在一些随机路由器时,您无法预期该序列是预期的正在拦截并回复带有错误消息的请求。 – Eric

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; 

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

你是治疗缓冲buff与该两个IP报头和一个ICMP首标开始。我相信你需要通过IP报头的大小,以抵消icmphdr指针,除非你icmphdr结构包括iphdr在其开始(其中Linux版本没有):

icmp = (struct icmphdr*)(buff + sizeof(iphdr)); 

而且,你overswriting的IP在将IP标头写入缓冲区之后做memset (buff, 0, sizeof(buff));的标题。