1

我正在尝试实现一个 Traceroute 程序,但我遇到了两个问题,一个是 TTL 和 RTT 打印错误;尽管它们在作为 ping 程序实施时正确打印出来。最后,我的主要问题是,当我增加 TTL 时,它会增加 2 而不是 1。

我只包含了我认为必要的代码,谢谢。

提前致谢 :)

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);
}
4

2 回答 2

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 在每次迭代中增加 2 的原因。

该行的ip->ttl=(ttl++)意思是:取 的值ttl并将其复制到ip->ttl,然后在这样做之后加ttl一。

于 2013-02-07T23:19:19.907 回答
1

您在该循环中将 ttl 增加两次。当 for 循环开始时:

    ttl+=1;

然后再次将其分配给结构

   ip->ttl=(ttl++);

至于 rtt,那段代码在我看来是错误的。

于 2013-02-07T23:19:53.933 回答