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