Annotation of 43BSDReno/usr.sbin/traceroute/traceroute.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.