1: #ifndef lint
   2: static char *rcsid =
   3:     "@(#)$Header: traceroute.c,v 1.17 89/02/28 21:01:13 van Exp $ (LBL)";
   4: #endif
   5: 
   6: /*
   7:  * traceroute host  - trace the route ip packets follow going to "host".
   8:  *
   9:  * Attempt to trace the route an ip packet would follow to some
  10:  * internet host.  We find out intermediate hops by launching probe
  11:  * packets with a small ttl (time to live) then listening for an
  12:  * icmp "time exceeded" reply from a gateway.  We start our probes
  13:  * with a ttl of one and increase by one until we get an icmp "port
  14:  * unreachable" (which means we got to "host") or hit a max (which
  15:  * defaults to 30 hops & can be changed with the -m flag).  Three
  16:  * probes (change with -q flag) are sent at each ttl setting and a
  17:  * line is printed showing the ttl, address of the gateway and
  18:  * round trip time of each probe.  If the probe answers come from
  19:  * different gateways, the address of each responding system will
  20:  * be printed.  If there is no response within a 5 sec. timeout
  21:  * interval (changed with the -w flag), a "*" is printed for that
  22:  * probe.
  23:  *
  24:  * Probe packets are UDP format.  We don't want the destination
  25:  * host to process them so the destination port is set to an
  26:  * unlikely value (if some clod on the destination is using that
  27:  * value, it can be changed with the -p flag).
  28:  *
  29:  * A sample use might be:
  30:  *
  31:  *     [yak 71]% traceroute nis.nsf.net.
  32:  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
  33:  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
  34:  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
  35:  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
  36:  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
  37:  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
  38:  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
  39:  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
  40:  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
  41:  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
  42:  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
  43:  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
  44:  *
  45:  * Note that lines 2 & 3 are the same.  This is due to a buggy
  46:  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
  47:  * packets with a zero ttl.
  48:  *
  49:  * A more interesting example is:
  50:  *
  51:  *     [yak 72]% traceroute allspice.lcs.mit.edu.
  52:  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
  53:  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
  54:  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
  55:  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
  56:  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
  57:  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
  58:  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
  59:  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
  60:  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
  61:  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
  62:  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
  63:  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
  64:  *     12  * * *
  65:  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
  66:  *     14  * * *
  67:  *     15  * * *
  68:  *     16  * * *
  69:  *     17  * * *
  70:  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
  71:  *
  72:  * (I start to see why I'm having so much trouble with mail to
  73:  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
  74:  * either don't send ICMP "time exceeded" messages or send them
  75:  * with a ttl too small to reach us.  14 - 17 are running the
  76:  * MIT C Gateway code that doesn't send "time exceeded"s.  God
  77:  * only knows what's going on with 12.
  78:  *
  79:  * The silent gateway 12 in the above may be the result of a bug in
  80:  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
  81:  * sends an unreachable message using whatever ttl remains in the
  82:  * original datagram.  Since, for gateways, the remaining ttl is
  83:  * zero, the icmp "time exceeded" is guaranteed to not make it back
  84:  * to us.  The behavior of this bug is slightly more interesting
  85:  * when it appears on the destination system:
  86:  *
  87:  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
  88:  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
  89:  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
  90:  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
  91:  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
  92:  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
  93:  *      7  * * *
  94:  *      8  * * *
  95:  *      9  * * *
  96:  *     10  * * *
  97:  *     11  * * *
  98:  *     12  * * *
  99:  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
 100:  *
 101:  * Notice that there are 12 "gateways" (13 is the final
 102:  * destination) and exactly the last half of them are "missing".
 103:  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
 104:  * is using the ttl from our arriving datagram as the ttl in its
 105:  * icmp reply.  So, the reply will time out on the return path
 106:  * (with no notice sent to anyone since icmp's aren't sent for
 107:  * icmp's) until we probe with a ttl that's at least twice the path
 108:  * length.  I.e., rip is really only 7 hops away.  A reply that
 109:  * returns with a ttl of 1 is a clue this problem exists.
 110:  * Traceroute prints a "!" after the time if the ttl is <= 1.
 111:  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
 112:  * non-standard (HPUX) software, expect to see this problem
 113:  * frequently and/or take care picking the target host of your
 114:  * probes.
 115:  *
 116:  * Other possible annotations after the time are !H, !N, !P (got a host,
 117:  * network or protocol unreachable, respectively), !S or !F (source
 118:  * route failed or fragmentation needed -- neither of these should
 119:  * ever occur and the associated gateway is busted if you see one).  If
 120:  * almost all the probes result in some kind of unreachable, traceroute
 121:  * will give up and exit.
 122:  *
 123:  * Notes
 124:  * -----
 125:  * This program must be run by root or be setuid.  (I suggest that
 126:  * you *don't* make it setuid -- casual use could result in a lot
 127:  * of unnecessary traffic on our poor, congested nets.)
 128:  *
 129:  * This program requires a kernel mod that does not appear in any
 130:  * system available from Berkeley:  A raw ip socket using proto
 131:  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
 132:  * opposed to data to be wrapped in a ip datagram).  See the README
 133:  * file that came with the source to this program for a description
 134:  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
 135:  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
 136:  * MODIFIED TO RUN THIS PROGRAM.
 137:  *
 138:  * The udp port usage may appear bizarre (well, ok, it is bizarre).
 139:  * The problem is that an icmp message only contains 8 bytes of
 140:  * data from the original datagram.  8 bytes is the size of a udp
 141:  * header so, if we want to associate replies with the original
 142:  * datagram, the necessary information must be encoded into the
 143:  * udp header (the ip id could be used but there's no way to
 144:  * interlock with the kernel's assignment of ip id's and, anyway,
 145:  * it would have taken a lot more kernel hacking to allow this
 146:  * code to set the ip id).  So, to allow two or more users to
 147:  * use traceroute simultaneously, we use this task's pid as the
 148:  * source port (the high bit is set to move the port number out
 149:  * of the "likely" range).  To keep track of which probe is being
 150:  * replied to (so times and/or hop counts don't get confused by a
 151:  * reply that was delayed in transit), we increment the destination
 152:  * port number before each probe.
 153:  *
 154:  * Don't use this as a coding example.  I was trying to find a
 155:  * routing problem and this code sort-of popped out after 48 hours
 156:  * without sleep.  I was amazed it ever compiled, much less ran.
 157:  *
 158:  * I stole the idea for this program from Steve Deering.  Since
 159:  * the first release, I've learned that had I attended the right
 160:  * IETF working group meetings, I also could have stolen it from Guy
 161:  * Almes or Matt Mathis.  I don't know (or care) who came up with
 162:  * the idea first.  I envy the originators' perspicacity and I'm
 163:  * glad they didn't keep the idea a secret.
 164:  *
 165:  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
 166:  * enhancements to the original distribution.
 167:  *
 168:  * I've hacked up a round-trip-route version of this that works by
 169:  * sending a loose-source-routed udp datagram through the destination
 170:  * back to yourself.  Unfortunately, SO many gateways botch source
 171:  * routing, the thing is almost worthless.  Maybe one day...
 172:  *
 173:  *  -- Van Jacobson (van@helios.ee.lbl.gov)
 174:  *     Tue Dec 20 03:50:13 PST 1988
 175:  *
 176:  * Copyright (c) 1988 Regents of the University of California.
 177:  * All rights reserved.
 178:  *
 179:  * Redistribution and use in source and binary forms are permitted
 180:  * provided that the above copyright notice and this paragraph are
 181:  * duplicated in all such forms and that any documentation,
 182:  * advertising materials, and other materials related to such
 183:  * distribution and use acknowledge that the software was developed
 184:  * by the University of California, Berkeley.  The name of the
 185:  * University may not be used to endorse or promote products derived
 186:  * from this software without specific prior written permission.
 187:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 188:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 189:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 190:  */
 191: 
 192: #include <stdio.h>
 193: #include <errno.h>
 194: #include <strings.h>
 195: #include <sys/time.h>
 196: 
 197: #include <sys/param.h>
 198: #include <sys/socket.h>
 199: #include <sys/file.h>
 200: #include <sys/ioctl.h>
 201: 
 202: #include <netinet/in_systm.h>
 203: #include <netinet/in.h>
 204: #include <netinet/ip.h>
 205: #include <netinet/ip_icmp.h>
 206: #include <netinet/udp.h>
 207: #include <netdb.h>
 208: 
 209: #define MAXPACKET   65535   /* max ip packet size */
 210: #ifndef MAXHOSTNAMELEN
 211: #define MAXHOSTNAMELEN  64
 212: #endif
 213: 
 214: #ifndef FD_SET
 215: #define NFDBITS         (8*sizeof(fd_set))
 216: #define FD_SETSIZE      NFDBITS
 217: #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
 218: #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
 219: #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
 220: #define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
 221: #endif
 222: 
 223: #define Fprintf (void)fprintf
 224: #define Sprintf (void)sprintf
 225: #define Printf (void)printf
 226: extern  int errno;
 227: extern  char *malloc();
 228: extern  char *inet_ntoa();
 229: extern  u_long inet_addr();
 230: 
 231: /*
 232:  * format of a (udp) probe packet.
 233:  */
 234: struct opacket {
 235:     struct ip ip;
 236:     struct udphdr udp;
 237:     u_char seq;     /* sequence number of this packet */
 238:     u_char ttl;     /* ttl packet left with */
 239:     struct timeval tv;  /* time packet left */
 240: };
 241: 
 242: u_char  packet[512];        /* last inbound (icmp) packet */
 243: struct opacket  *outpacket; /* last output (udp) packet */
 244: char *inetname();
 245: 
 246: int s;              /* receive (icmp) socket file descriptor */
 247: int sndsock;            /* send (udp) socket file descriptor */
 248: struct timezone tz;     /* leftover */
 249: 
 250: struct sockaddr whereto;    /* Who to try to reach */
 251: int datalen;            /* How much data */
 252: 
 253: char *source = 0;
 254: char *hostname;
 255: char hnamebuf[MAXHOSTNAMELEN];
 256: 
 257: int nprobes = 3;
 258: int max_ttl = 30;
 259: u_short ident;
 260: u_short port = 32768+666;   /* start udp dest port # for probe packets */
 261: 
 262: int options;            /* socket options */
 263: int verbose;
 264: int waittime = 5;       /* time to wait for response (in seconds) */
 265: int nflag;          /* print addresses numerically */
 266: 
 267: char usage[] =
 268:  "Usage: traceroute [-dnrv] [-w wait] [-m max_ttl] [-p port#] [-q nqueries] [-t tos] [-s src_addr] host [data size]\n";
 269: 
 270: 
 271: main(argc, argv)
 272:     char *argv[];
 273: {
 274:     struct sockaddr_in from;
 275:     char **av = argv;
 276:     struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
 277:     int on = 1;
 278:     struct protoent *pe;
 279:     int ttl, probe, i;
 280:     int seq = 0;
 281:     int tos = 0;
 282:     struct hostent *hp;
 283: 
 284:     argc--, av++;
 285:     while (argc && *av[0] == '-')  {
 286:         while (*++av[0])
 287:             switch (*av[0]) {
 288:             case 'd':
 289:                 options |= SO_DEBUG;
 290:                 break;
 291:             case 'm':
 292:                 argc--, av++;
 293:                 max_ttl = atoi(av[0]);
 294:                 if (max_ttl <= 1) {
 295:                     Fprintf(stderr, "max ttl must be >1\n");
 296:                     exit(1);
 297:                 }
 298:                 goto nextarg;
 299:             case 'n':
 300:                 nflag++;
 301:                 break;
 302:             case 'p':
 303:                 argc--, av++;
 304:                 port = atoi(av[0]);
 305:                 if (port < 1) {
 306:                     Fprintf(stderr, "port must be >0\n");
 307:                     exit(1);
 308:                 }
 309:                 goto nextarg;
 310:             case 'q':
 311:                 argc--, av++;
 312:                 nprobes = atoi(av[0]);
 313:                 if (nprobes < 1) {
 314:                     Fprintf(stderr, "nprobes must be >0\n");
 315:                     exit(1);
 316:                 }
 317:                 goto nextarg;
 318:             case 'r':
 319:                 options |= SO_DONTROUTE;
 320:                 break;
 321:             case 's':
 322:                 /*
 323: 				 * set the ip source address of the outbound
 324: 				 * probe (e.g., on a multi-homed host).
 325: 				 */
 326:                 argc--, av++;
 327:                 source = av[0];
 328:                 goto nextarg;
 329:             case 't':
 330:                 argc--, av++;
 331:                 tos = atoi(av[0]);
 332:                 if (tos < 0 || tos > 255) {
 333:                     Fprintf(stderr, "tos must be 0 to 255\n");
 334:                     exit(1);
 335:                 }
 336:                 goto nextarg;
 337:             case 'v':
 338:                 verbose++;
 339:                 break;
 340:             case 'w':
 341:                 argc--, av++;
 342:                 waittime = atoi(av[0]);
 343:                 if (waittime <= 1) {
 344:                     Fprintf(stderr, "wait must be >1 sec\n");
 345:                     exit(1);
 346:                 }
 347:                 goto nextarg;
 348:             }
 349:     nextarg:
 350:         argc--, av++;
 351:     }
 352:     if (argc < 1)  {
 353:         Printf(usage);
 354:         exit(1);
 355:     }
 356:     setlinebuf (stdout);
 357: 
 358:     (void) bzero((char *)&whereto, sizeof(struct sockaddr));
 359:     to->sin_family = AF_INET;
 360:     to->sin_addr.s_addr = inet_addr(av[0]);
 361:     if (to->sin_addr.s_addr != -1) {
 362:         (void) strcpy(hnamebuf, av[0]);
 363:         hostname = hnamebuf;
 364:     } else {
 365:         hp = gethostbyname(av[0]);
 366:         if (hp) {
 367:             to->sin_family = hp->h_addrtype;
 368:             bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
 369:             hostname = hp->h_name;
 370:         } else {
 371:             Printf("%s: unknown host %s\n", argv[0], av[0]);
 372:             exit(1);
 373:         }
 374:     }
 375: 
 376:     if (argc >= 2)
 377:         datalen = atoi(av[1]);
 378:     if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
 379:         Fprintf(stderr, "traceroute: packet size must be 0 <= s < %ld\n",
 380:             MAXPACKET - sizeof(struct opacket));
 381:         exit(1);
 382:     }
 383:     datalen += sizeof(struct opacket);
 384:     outpacket = (struct opacket *)malloc((unsigned)datalen);
 385:     if (! outpacket) {
 386:         perror("traceroute: malloc");
 387:         exit(1);
 388:     }
 389:     (void) bzero((char *)outpacket, datalen);
 390:     outpacket->ip.ip_dst = to->sin_addr;
 391:     outpacket->ip.ip_tos = tos;
 392: 
 393:     ident = (getpid() & 0xffff) | 0x8000;
 394: 
 395:     if ((pe = getprotobyname("icmp")) == NULL) {
 396:         Fprintf(stderr, "icmp: unknown protocol\n");
 397:         exit(10);
 398:     }
 399:     if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
 400:         perror("traceroute: icmp socket");
 401:         exit(5);
 402:     }
 403:     if (options & SO_DEBUG)
 404:         (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
 405:                   (char *)&on, sizeof(on));
 406:     if (options & SO_DONTROUTE)
 407:         (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
 408:                   (char *)&on, sizeof(on));
 409: 
 410:     if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
 411:         perror("traceroute: raw socket");
 412:         exit(5);
 413:     }
 414: #ifdef SO_SNDBUF
 415:     if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
 416:                sizeof(datalen)) < 0) {
 417:         perror("traceroute: SO_SNDBUF");
 418:         exit(6);
 419:     }
 420: #endif SO_SNDBUF
 421: #ifdef IP_HDRINCL
 422:     if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
 423:                sizeof(on)) < 0) {
 424:         perror("traceroute: IP_HDRINCL");
 425:         exit(6);
 426:     }
 427: #endif IP_HDRINCL
 428:     if (options & SO_DEBUG)
 429:         (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
 430:                   (char *)&on, sizeof(on));
 431:     if (options & SO_DONTROUTE)
 432:         (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
 433:                   (char *)&on, sizeof(on));
 434: 
 435:     if (source) {
 436:         (void) bzero((char *)&from, sizeof(struct sockaddr));
 437:         from.sin_family = AF_INET;
 438:         from.sin_addr.s_addr = inet_addr(source);
 439:         if (from.sin_addr.s_addr == -1) {
 440:             Printf("traceroute: unknown host %s\n", source);
 441:             exit(1);
 442:         }
 443:         outpacket->ip.ip_src = from.sin_addr;
 444: #ifndef IP_HDRINCL
 445:         if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
 446:             perror ("traceroute: bind:");
 447:             exit (1);
 448:         }
 449: #endif IP_HDRINCL
 450:     }
 451: 
 452:     Fprintf(stderr, "traceroute to %s (%s)", hostname,
 453:         inet_ntoa(to->sin_addr));
 454:     if (source)
 455:         Fprintf(stderr, " from %s", source);
 456:     Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
 457:     (void) fflush(stderr);
 458: 
 459:     for (ttl = 1; ttl <= max_ttl; ++ttl) {
 460:         u_long lastaddr = 0;
 461:         int got_there = 0;
 462:         int unreachable = 0;
 463: 
 464:         Printf("%2d ", ttl);
 465:         for (probe = 0; probe < nprobes; ++probe) {
 466:             int cc;
 467:             struct timeval tv;
 468:             struct ip *ip;
 469: 
 470:             (void) gettimeofday(&tv, &tz);
 471:             send_probe(++seq, ttl);
 472:             while (cc = wait_for_reply(s, &from)) {
 473:                 if ((i = packet_ok(packet, cc, &from, seq))) {
 474:                     int dt = deltaT(&tv);
 475:                     if (from.sin_addr.s_addr != lastaddr) {
 476:                         print(packet, cc, &from);
 477:                         lastaddr = from.sin_addr.s_addr;
 478:                     }
 479:                     Printf("  %d ms", dt);
 480:                     switch(i - 1) {
 481:                     case ICMP_UNREACH_PORT:
 482: #ifndef ARCHAIC
 483:                         ip = (struct ip *)packet;
 484:                         if (ip->ip_ttl <= 1)
 485:                             Printf(" !");
 486: #endif ARCHAIC
 487:                         ++got_there;
 488:                         break;
 489:                     case ICMP_UNREACH_NET:
 490:                         ++unreachable;
 491:                         Printf(" !N");
 492:                         break;
 493:                     case ICMP_UNREACH_HOST:
 494:                         ++unreachable;
 495:                         Printf(" !H");
 496:                         break;
 497:                     case ICMP_UNREACH_PROTOCOL:
 498:                         ++got_there;
 499:                         Printf(" !P");
 500:                         break;
 501:                     case ICMP_UNREACH_NEEDFRAG:
 502:                         ++unreachable;
 503:                         Printf(" !F");
 504:                         break;
 505:                     case ICMP_UNREACH_SRCFAIL:
 506:                         ++unreachable;
 507:                         Printf(" !S");
 508:                         break;
 509:                     }
 510:                     break;
 511:                 }
 512:             }
 513:             if (cc == 0)
 514:                 Printf(" *");
 515:             (void) fflush(stdout);
 516:         }
 517:         putchar('\n');
 518:         if (got_there || unreachable >= nprobes-1)
 519:             exit(0);
 520:     }
 521: }
 522: 
 523: wait_for_reply(sock, from)
 524:     int sock;
 525:     struct sockaddr_in *from;
 526: {
 527:     fd_set fds;
 528:     struct timeval wait;
 529:     int cc = 0;
 530:     int fromlen = sizeof (*from);
 531: 
 532:     FD_ZERO(&fds);
 533:     FD_SET(sock, &fds);
 534:     wait.tv_sec = waittime; wait.tv_usec = 0;
 535: 
 536:     if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
 537:         cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
 538:                 (struct sockaddr *)from, &fromlen);
 539: 
 540:     return(cc);
 541: }
 542: 
 543: 
 544: send_probe(seq, ttl)
 545: {
 546:     struct opacket *op = outpacket;
 547:     struct ip *ip = &op->ip;
 548:     struct udphdr *up = &op->udp;
 549:     int i;
 550: 
 551:     ip->ip_off = 0;
 552:     ip->ip_p = IPPROTO_UDP;
 553:     ip->ip_len = datalen;
 554:     ip->ip_ttl = ttl;
 555: 
 556:     up->uh_sport = htons(ident);
 557:     up->uh_dport = htons(port+seq);
 558:     up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
 559:     up->uh_sum = 0;
 560: 
 561:     op->seq = seq;
 562:     op->ttl = ttl;
 563:     (void) gettimeofday(&op->tv, &tz);
 564: 
 565:     i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
 566:            sizeof(struct sockaddr));
 567:     if (i < 0 || i != datalen)  {
 568:         if (i<0)
 569:             perror("sendto");
 570:         Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
 571:             datalen, i);
 572:         (void) fflush(stdout);
 573:     }
 574: }
 575: 
 576: 
 577: deltaT(tp)
 578:     struct timeval *tp;
 579: {
 580:     struct timeval tv;
 581: 
 582:     (void) gettimeofday(&tv, &tz);
 583:     tvsub(&tv, tp);
 584:     return (tv.tv_sec*1000 + (tv.tv_usec + 500)/1000);
 585: }
 586: 
 587: 
 588: /*
 589:  * Convert an ICMP "type" field to a printable string.
 590:  */
 591: char *
 592: pr_type(t)
 593:     u_char t;
 594: {
 595:     static char *ttab[] = {
 596:     "Echo Reply",   "ICMP 1",   "ICMP 2",   "Dest Unreachable",
 597:     "Source Quench", "Redirect",    "ICMP 6",   "ICMP 7",
 598:     "Echo",     "ICMP 9",   "ICMP 10",  "Time Exceeded",
 599:     "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
 600:     "Info Reply"
 601:     };
 602: 
 603:     if(t > 16)
 604:         return("OUT-OF-RANGE");
 605: 
 606:     return(ttab[t]);
 607: }
 608: 
 609: 
 610: packet_ok(buf, cc, from, seq)
 611:     u_char *buf;
 612:     int cc;
 613:     struct sockaddr_in *from;
 614:     int seq;
 615: {
 616:     register struct icmp *icp;
 617:     u_char type, code;
 618:     int hlen;
 619: #ifndef ARCHAIC
 620:     struct ip *ip;
 621: 
 622:     ip = (struct ip *) buf;
 623:     hlen = ip->ip_hl << 2;
 624:     if (cc < hlen + ICMP_MINLEN) {
 625:         if (verbose)
 626:             Printf("packet too short (%d bytes) from %s\n", cc,
 627:                 inet_ntoa(from->sin_addr));
 628:         return (0);
 629:     }
 630:     cc -= hlen;
 631:     icp = (struct icmp *)(buf + hlen);
 632: #else
 633:     icp = (struct icmp *)buf;
 634: #endif ARCHAIC
 635:     type = icp->icmp_type; code = icp->icmp_code;
 636:     if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
 637:         type == ICMP_UNREACH) {
 638:         struct ip *hip;
 639:         struct udphdr *up;
 640: 
 641:         hip = &icp->icmp_ip;
 642:         hlen = hip->ip_hl << 2;
 643:         up = (struct udphdr *)((u_char *)hip + hlen);
 644:         if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
 645:             up->uh_sport == htons(ident) &&
 646:             up->uh_dport == htons(port+seq))
 647:             return (type == ICMP_TIMXCEED? -1 : code+1);
 648:     }
 649: #ifndef ARCHAIC
 650:     if (verbose) {
 651:         int i;
 652:         u_long *lp = (u_long *)&icp->icmp_ip;
 653: 
 654:         Printf("\n%d bytes from %s to %s", cc,
 655:             inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
 656:         Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
 657:                icp->icmp_code);
 658:         for (i = 4; i < cc ; i += sizeof(long))
 659:             Printf("%2d: x%8.8lx\n", i, *lp++);
 660:     }
 661: #endif ARCHAIC
 662:     return(0);
 663: }
 664: 
 665: 
 666: print(buf, cc, from)
 667:     u_char *buf;
 668:     int cc;
 669:     struct sockaddr_in *from;
 670: {
 671:     struct ip *ip;
 672:     int hlen;
 673: 
 674:     ip = (struct ip *) buf;
 675:     hlen = ip->ip_hl << 2;
 676:     cc -= hlen;
 677: 
 678:     if (nflag)
 679:         Printf(" %s", inet_ntoa(from->sin_addr));
 680:     else
 681:         Printf(" %s (%s)", inetname(from->sin_addr),
 682:                inet_ntoa(from->sin_addr));
 683: 
 684:     if (verbose)
 685:         Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
 686: }
 687: 
 688: 
 689: #ifdef notyet
 690: /*
 691:  * Checksum routine for Internet Protocol family headers (C Version)
 692:  */
 693: in_cksum(addr, len)
 694: u_short *addr;
 695: int len;
 696: {
 697:     register int nleft = len;
 698:     register u_short *w = addr;
 699:     register u_short answer;
 700:     register int sum = 0;
 701: 
 702:     /*
 703: 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
 704: 	 *  we add sequential 16 bit words to it, and at the end, fold
 705: 	 *  back all the carry bits from the top 16 bits into the lower
 706: 	 *  16 bits.
 707: 	 */
 708:     while (nleft > 1)  {
 709:         sum += *w++;
 710:         nleft -= 2;
 711:     }
 712: 
 713:     /* mop up an odd byte, if necessary */
 714:     if (nleft == 1)
 715:         sum += *(u_char *)w;
 716: 
 717:     /*
 718: 	 * add back carry outs from top 16 bits to low 16 bits
 719: 	 */
 720:     sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
 721:     sum += (sum >> 16);         /* add carry */
 722:     answer = ~sum;              /* truncate to 16 bits */
 723:     return (answer);
 724: }
 725: #endif notyet
 726: 
 727: /*
 728:  * Subtract 2 timeval structs:  out = out - in.
 729:  * Out is assumed to be >= in.
 730:  */
 731: tvsub(out, in)
 732: register struct timeval *out, *in;
 733: {
 734:     if ((out->tv_usec -= in->tv_usec) < 0)   {
 735:         out->tv_sec--;
 736:         out->tv_usec += 1000000;
 737:     }
 738:     out->tv_sec -= in->tv_sec;
 739: }
 740: 
 741: 
 742: /*
 743:  * Construct an Internet address representation.
 744:  * If the nflag has been supplied, give
 745:  * numeric value, otherwise try for symbolic name.
 746:  */
 747: char *
 748: inetname(in)
 749:     struct in_addr in;
 750: {
 751:     register char *cp;
 752:     static char line[50];
 753:     struct hostent *hp;
 754:     static char domain[MAXHOSTNAMELEN + 1];
 755:     static int first = 1;
 756: 
 757:     if (first && !nflag) {
 758:         first = 0;
 759:         if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
 760:             (cp = index(domain, '.')))
 761:             (void) strcpy(domain, cp + 1);
 762:         else
 763:             domain[0] = 0;
 764:     }
 765:     cp = 0;
 766:     if (!nflag && in.s_addr != INADDR_ANY) {
 767:         hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
 768:         if (hp) {
 769:             if ((cp = index(hp->h_name, '.')) &&
 770:                 !strcmp(cp + 1, domain))
 771:                 *cp = 0;
 772:             cp = hp->h_name;
 773:         }
 774:     }
 775:     if (cp)
 776:         (void) strcpy(line, cp);
 777:     else {
 778:         in.s_addr = ntohl(in.s_addr);
 779: #define C(x)    ((x) & 0xff)
 780:         Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
 781:             C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
 782:     }
 783:     return (line);
 784: }

Defined functions

deltaT defined in line 577; used 1 times
in_cksum defined in line 693; never used
inetname defined in line 747; used 2 times
main defined in line 271; never used
packet_ok defined in line 610; used 1 times
pr_type defined in line 591; used 1 times
print defined in line 666; used 1 times
send_probe defined in line 544; used 1 times
tvsub defined in line 731; used 1 times
wait_for_reply defined in line 523; used 1 times

Defined variables

datalen defined in line 251; used 14 times
hnamebuf defined in line 255; used 2 times
hostname defined in line 254; used 4 times
ident defined in line 259; used 3 times
max_ttl defined in line 258; used 4 times
nflag defined in line 265; used 4 times
nprobes defined in line 257; used 4 times
options defined in line 262; used 6 times
outpacket defined in line 243; used 8 times
packet defined in line 242; used 5 times
port defined in line 260; used 4 times
rcsid defined in line 2; never used
s defined in line 246; used 5 times
sndsock defined in line 247; used 7 times
source defined in line 253; used 6 times
tz defined in line 248; used 3 times
usage defined in line 267; used 1 times
verbose defined in line 263; used 4 times
waittime defined in line 264; used 3 times
whereto defined in line 250; used 3 times

Defined struct's

opacket defined in line 234; used 12 times

Defined macros

C defined in line 779; used 4 times
FD_CLR defined in line 218; never used
FD_ISSET defined in line 219; never used
FD_SET defined in line 217; used 2 times
FD_SETSIZE defined in line 216; never used
FD_ZERO defined in line 220; used 1 times
Fprintf defined in line 223; used 10 times
MAXHOSTNAMELEN defined in line 211; used 4 times
MAXPACKET defined in line 209; used 2 times
NFDBITS defined in line 215; used 7 times
Printf defined in line 225; used 20 times
Sprintf defined in line 224; used 1 times
Last modified: 1989-05-24
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6441
Valid CSS Valid XHTML 1.0 Strict