# 2.11BSD#431 - /usr/src/usr.sbin/traceroute/traceroute.c

##### Functions

    deltaT            X
    in_cksum          X
    inetname          X
    main              X
    packet_ok         X
    pr_type           X
    print             X
    send_probe        X
    tvsub             X
    wait_for_reply    X

##### Variables

    datalen           X
    hnamebuf          X
    hostname          X
    ident             X
    max_ttl           X
    nflag             X
    nprobes           X
    options           X
    outpacket         X
    packet            X
    port              X
    s                 X
    sndsock           X
    source            X
    tz                X
    usage             X
    verbose           X
    waittime          X
    whereto           X

##### Macros

    C                 X
    FD_CLR            X
    FD_ISSET          X
    FD_SET            X
    FD_SETSIZE        X
    FD_ZERO           X
    Fprintf           X
    MAXHOSTNAMELEN    X
    MAXPACKET         X
    NFDBITS           X
    Printf            X
    Sprintf           X

##### struct's

    opacket           X

       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 line 474

in_cksum defined in line 693; never used
inetname defined in line 747; used 2 times

- in line 244, 681

main defined in line 271; never used
packet_ok defined in line 610; used 1 times

- in line 473

pr_type defined in line 591; used 1 times

- in line 656

print defined in line 666; used 1 times

- in line 476

send_probe defined in line 544; used 1 times

- in line 471

tvsub defined in line 731; used 1 times

- in line 583

wait_for_reply defined in line 523; used 1 times

- in line 472

#### Defined variables

datalen defined in line 251; used 14 times

- in line 377-389(6), 415-416(2), 456, 553-558(2), 565-571(3)

hnamebuf defined in line 255; used 2 times

- in line 362-363(2)

hostname defined in line 254; used 4 times

- in line 363, 369, 452, 570

ident defined in line 259; used 3 times

- in line 393, 556, 645

max_ttl defined in line 258; used 4 times

- in line 293-294(2), 456-459(2)

nflag defined in line 265; used 4 times

- in line 300, 678, 757, 766

nprobes defined in line 257; used 4 times

- in line 312-313(2), 465, 518

options defined in line 262; used 6 times

- in line 289, 319, 403-406(2), 428-431(2)

outpacket defined in line 243; used 8 times

- in line 384-391(5), 443, 546, 565

packet defined in line 242; used 5 times

- in line 473-476(2), 483, 537(2)

port defined in line 260; used 4 times

- in line 304-305(2), 557, 646

rcsid defined in line 2; never used
s defined in line 246; used 5 times

- in line 399-407(3), 472, 537

sndsock defined in line 247; used 7 times

- in line 410-415(2), 422, 429-432(2), 445, 565

source defined in line 253; used 6 times

- in line 327, 435-440(3), 454-455(2)

tz defined in line 248; used 3 times

- in line 470, 563, 582

usage defined in line 267; used 1 times

- in line 353

verbose defined in line 263; used 4 times

- in line 338, 625, 650, 684

waittime defined in line 264; used 3 times

- in line 342-343(2), 534

whereto defined in line 250; used 3 times

- in line 276, 358, 565

#### Defined struct's

opacket defined in line 234; used 12 times

- in line 243(2), 378-384(8), 546(2)

#### Defined macros

C defined in line 779; used 4 times

- in line 780-781(4)

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

- in line 214, 533

FD_SETSIZE defined in line 216; never used
FD_ZERO defined in line 220; used 1 times

- in line 532

Fprintf defined in line 223; used 10 times

- in line 295, 306, 314, 333, 344, 379, 396, 452-456(3)

MAXHOSTNAMELEN defined in line 211; used 4 times

- in line 210, 255, 754-759(2)

MAXPACKET defined in line 209; used 2 times

- in line 378-380(2)

NFDBITS defined in line 215; used 7 times

- in line 216-219(7)

Printf defined in line 225; used 20 times

- in line 353, 371, 440, 464, 479, 485, 491-507(5), 514, 570, 626, 654-659(3), 679-685(3)

Sprintf defined in line 224; used 1 times

- in line 780

Last modified: 1989-05-24 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3239 |