Home | History | Annotate | Line # | Download | only in traceroute
traceroute.c revision 1.6
      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.6 1995/01/04 04:47:42 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 
    402 	outpacket = (u_char *)malloc(datalen);
    403 	if (outpacket == 0)
    404 		err(1, "malloc");
    405 	(void) bzero(outpacket, datalen);
    406 
    407 	ip = (struct ip *)outpacket;
    408 	if (lsrr != 0) {
    409 		u_char *p;
    410 		p = (u_char *)(ip + 1);
    411 		*p++ = IPOPT_NOP;
    412 		*p++ = IPOPT_LSRR;
    413 		*p++ = lsrrlen - 1;
    414 		*p++ = IPOPT_MINOFF;
    415 		gateway[lsrr] = to.sin_addr;
    416 		for (i = 1; i <= lsrr; i++)
    417 			*((struct in_addr *)p)++ = gateway[i];
    418 		ip->ip_dst = gateway[0];
    419 	} else
    420 		ip->ip_dst = to.sin_addr;
    421 	ip->ip_off = 0;
    422 	ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2;
    423 	ip->ip_p = IPPROTO_UDP;
    424 	ip->ip_v = IPVERSION;
    425 	ip->ip_tos = tos;
    426 
    427 	ident = (getpid() & 0xffff) | 0x8000;
    428 
    429 	if ((pe = getprotobyname("icmp")) == NULL) {
    430 		Fprintf(stderr, "icmp: unknown protocol\n");
    431 		exit(10);
    432 	}
    433 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
    434 		err(5, "icmp socket");
    435 	if (options & SO_DEBUG)
    436 		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
    437 				  (char *)&on, sizeof(on));
    438 	if (options & SO_DONTROUTE)
    439 		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
    440 				  (char *)&on, sizeof(on));
    441 
    442 	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
    443 		err(5, "raw socket");
    444 
    445 #ifdef SO_SNDBUF
    446 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
    447 		       sizeof(datalen)) < 0)
    448 		err(6, "SO_SNDBUF");
    449 #endif SO_SNDBUF
    450 #ifdef IP_HDRINCL
    451 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
    452 		       sizeof(on)) < 0)
    453 		err(6, "IP_HDRINCL");
    454 #endif IP_HDRINCL
    455 	if (options & SO_DEBUG)
    456 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
    457 				  (char *)&on, sizeof(on));
    458 	if (options & SO_DONTROUTE)
    459 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
    460 				  (char *)&on, sizeof(on));
    461 
    462 	if (source) {
    463 		(void) bzero((char *)&from, sizeof(struct sockaddr));
    464 		from.sin_family = AF_INET;
    465 		from.sin_addr.s_addr = inet_addr(source);
    466 		if (from.sin_addr.s_addr == -1)
    467 			errx(1, "unknown host %s", source);
    468 		ip->ip_src = from.sin_addr;
    469 #ifndef IP_HDRINCL
    470 		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
    471 			err(1, "bind");
    472 #endif IP_HDRINCL
    473 	}
    474 
    475 	Fprintf(stderr, "traceroute to %s (%s)", hostname,
    476 		inet_ntoa(to.sin_addr));
    477 	if (source)
    478 		Fprintf(stderr, " from %s", source);
    479 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
    480 	(void) fflush(stderr);
    481 
    482 	for (ttl = 1; ttl <= max_ttl; ++ttl) {
    483 		u_long lastaddr = 0;
    484 		int got_there = 0;
    485 		int unreachable = 0;
    486 
    487 		Printf("%2d ", ttl);
    488 		for (probe = 0; probe < nprobes; ++probe) {
    489 			int cc;
    490 			struct timeval t1, t2;
    491 			struct timezone tz;
    492 
    493 			(void) gettimeofday(&t1, &tz);
    494 			send_probe(++seq, ttl, &to);
    495 			while (cc = wait_for_reply(s, &from)) {
    496 				(void) gettimeofday(&t2, &tz);
    497 				if ((i = packet_ok(packet, cc, &from, seq))) {
    498 					if (from.sin_addr.s_addr != lastaddr) {
    499 						print(packet, cc, &from);
    500 						lastaddr = from.sin_addr.s_addr;
    501 					}
    502 					Printf("  %g ms", deltaT(&t1, &t2));
    503 					switch(i - 1) {
    504 					case ICMP_UNREACH_PORT:
    505 #ifndef ARCHAIC
    506 						ip = (struct ip *)packet;
    507 						if (ip->ip_ttl <= 1)
    508 							Printf(" !");
    509 #endif ARCHAIC
    510 						++got_there;
    511 						break;
    512 					case ICMP_UNREACH_NET:
    513 						++unreachable;
    514 						Printf(" !N");
    515 						break;
    516 					case ICMP_UNREACH_HOST:
    517 						++unreachable;
    518 						Printf(" !H");
    519 						break;
    520 					case ICMP_UNREACH_PROTOCOL:
    521 						++got_there;
    522 						Printf(" !P");
    523 						break;
    524 					case ICMP_UNREACH_NEEDFRAG:
    525 						++unreachable;
    526 						Printf(" !F");
    527 						break;
    528 					case ICMP_UNREACH_SRCFAIL:
    529 						++unreachable;
    530 						Printf(" !S");
    531 						break;
    532 					}
    533 					break;
    534 				}
    535 			}
    536 			if (cc == 0)
    537 				Printf(" *");
    538 			(void) fflush(stdout);
    539 		}
    540 		putchar('\n');
    541 		if (got_there || unreachable >= nprobes)
    542 			exit(0);
    543 	}
    544 }
    545 
    546 int
    547 wait_for_reply(sock, from)
    548 	int sock;
    549 	struct sockaddr_in *from;
    550 {
    551 	fd_set fds;
    552 	struct timeval wait;
    553 	int cc = 0;
    554 	int fromlen = sizeof (*from);
    555 
    556 	FD_ZERO(&fds);
    557 	FD_SET(sock, &fds);
    558 	wait.tv_sec = waittime; wait.tv_usec = 0;
    559 
    560 	if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
    561 		cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
    562 			    (struct sockaddr *)from, &fromlen);
    563 
    564 	return(cc);
    565 }
    566 
    567 void
    568 dump_packet()
    569 {
    570 	u_char *p;
    571 	int i;
    572 
    573 	Fprintf(stderr, "packet data:");
    574 	for (p = outpacket, i = 0; i < datalen; i++) {
    575 		if ((i % 24) == 0)
    576 			Fprintf(stderr, "\n ");
    577 		Fprintf(stderr, " %02x", *p++);
    578 	}
    579 	Fprintf(stderr, "\n");
    580 }
    581 
    582 void
    583 send_probe(seq, ttl, to)
    584 	int seq, ttl;
    585 	struct sockaddr_in *to;
    586 {
    587 	struct ip *ip = (struct ip *)outpacket;
    588 	u_char *p = (u_char *)(ip + 1);
    589 	struct udphdr *up = (struct udphdr *)(p + lsrrlen);
    590 	struct packetdata *op = (struct packetdata *)(up + 1);
    591 	int i;
    592 
    593 	ip->ip_len = datalen;
    594 	ip->ip_ttl = ttl;
    595 	ip->ip_id = htons(ident+seq);
    596 
    597 	up->uh_sport = htons(ident);
    598 	up->uh_dport = htons(port+seq);
    599 	up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) - lsrrlen));
    600 	up->uh_sum = 0;
    601 
    602 	op->seq = seq;
    603 	op->ttl = ttl;
    604 	(void) gettimeofday(&op->tv, &tz);
    605 
    606 	if (dump)
    607 		dump_packet();
    608 
    609 	i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to,
    610 		   sizeof(struct sockaddr_in));
    611 	if (i < 0 || i != datalen)  {
    612 		if (i<0)
    613 			perror("sendto");
    614 		Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
    615 			datalen, i);
    616 		(void) fflush(stdout);
    617 	}
    618 }
    619 
    620 
    621 double
    622 deltaT(t1p, t2p)
    623 	struct timeval *t1p, *t2p;
    624 {
    625 	register double dt;
    626 
    627 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
    628 	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
    629 	return (dt);
    630 }
    631 
    632 
    633 /*
    634  * Convert an ICMP "type" field to a printable string.
    635  */
    636 char *
    637 pr_type(t)
    638 	u_char t;
    639 {
    640 	static char *ttab[] = {
    641 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
    642 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
    643 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
    644 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
    645 	"Info Reply"
    646 	};
    647 
    648 	if(t > 16)
    649 		return("OUT-OF-RANGE");
    650 
    651 	return(ttab[t]);
    652 }
    653 
    654 
    655 int
    656 packet_ok(buf, cc, from, seq)
    657 	u_char *buf;
    658 	int cc;
    659 	struct sockaddr_in *from;
    660 	int seq;
    661 {
    662 	register struct icmp *icp;
    663 	u_char type, code;
    664 	int hlen;
    665 #ifndef ARCHAIC
    666 	struct ip *ip;
    667 
    668 	ip = (struct ip *) buf;
    669 	hlen = ip->ip_hl << 2;
    670 	if (cc < hlen + ICMP_MINLEN) {
    671 		if (verbose)
    672 			Printf("packet too short (%d bytes) from %s\n", cc,
    673 				inet_ntoa(from->sin_addr));
    674 		return (0);
    675 	}
    676 	cc -= hlen;
    677 	icp = (struct icmp *)(buf + hlen);
    678 #else
    679 	icp = (struct icmp *)buf;
    680 #endif ARCHAIC
    681 	type = icp->icmp_type; code = icp->icmp_code;
    682 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
    683 	    type == ICMP_UNREACH) {
    684 		struct ip *hip;
    685 		struct udphdr *up;
    686 
    687 		hip = &icp->icmp_ip;
    688 		hlen = hip->ip_hl << 2;
    689 		up = (struct udphdr *)((u_char *)hip + hlen);
    690 		if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
    691 		    up->uh_sport == htons(ident) &&
    692 		    up->uh_dport == htons(port+seq))
    693 			return (type == ICMP_TIMXCEED? -1 : code+1);
    694 	}
    695 #ifndef ARCHAIC
    696 	if (verbose) {
    697 		int i;
    698 		u_long *lp = (u_long *)&icp->icmp_ip;
    699 
    700 		Printf("\n%d bytes from %s to %s", cc,
    701 			inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
    702 		Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
    703 		       icp->icmp_code);
    704 		for (i = 4; i < cc ; i += sizeof(long))
    705 			Printf("%2d: x%8.8lx\n", i, *lp++);
    706 	}
    707 #endif ARCHAIC
    708 	return(0);
    709 }
    710 
    711 
    712 void
    713 print(buf, cc, from)
    714 	u_char *buf;
    715 	int cc;
    716 	struct sockaddr_in *from;
    717 {
    718 	struct ip *ip;
    719 	int hlen;
    720 
    721 	ip = (struct ip *) buf;
    722 	hlen = ip->ip_hl << 2;
    723 	cc -= hlen;
    724 
    725 	if (nflag)
    726 		Printf(" %s", inet_ntoa(from->sin_addr));
    727 	else
    728 		Printf(" %s (%s)", inetname(from->sin_addr),
    729 		       inet_ntoa(from->sin_addr));
    730 
    731 	if (verbose)
    732 		Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
    733 }
    734 
    735 
    736 #ifdef notyet
    737 /*
    738  * Checksum routine for Internet Protocol family headers (C Version)
    739  */
    740 u_short
    741 in_cksum(addr, len)
    742 	u_short *addr;
    743 	int len;
    744 {
    745 	register int nleft = len;
    746 	register u_short *w = addr;
    747 	register u_short answer;
    748 	register int sum = 0;
    749 
    750 	/*
    751 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
    752 	 *  we add sequential 16 bit words to it, and at the end, fold
    753 	 *  back all the carry bits from the top 16 bits into the lower
    754 	 *  16 bits.
    755 	 */
    756 	while (nleft > 1)  {
    757 		sum += *w++;
    758 		nleft -= 2;
    759 	}
    760 
    761 	/* mop up an odd byte, if necessary */
    762 	if (nleft == 1)
    763 		sum += *(u_char *)w;
    764 
    765 	/*
    766 	 * add back carry outs from top 16 bits to low 16 bits
    767 	 */
    768 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
    769 	sum += (sum >> 16);			/* add carry */
    770 	answer = ~sum;				/* truncate to 16 bits */
    771 	return (answer);
    772 }
    773 #endif notyet
    774 
    775 /*
    776  * Subtract 2 timeval structs:  out = out - in.
    777  * Out is assumed to be >= in.
    778  */
    779 void
    780 tvsub(out, in)
    781 	register struct timeval *out, *in;
    782 {
    783 	if ((out->tv_usec -= in->tv_usec) < 0)   {
    784 		out->tv_sec--;
    785 		out->tv_usec += 1000000;
    786 	}
    787 	out->tv_sec -= in->tv_sec;
    788 }
    789 
    790 
    791 /*
    792  * Construct an Internet address representation.
    793  * If the nflag has been supplied, give
    794  * numeric value, otherwise try for symbolic name.
    795  */
    796 char *
    797 inetname(in)
    798 	struct in_addr in;
    799 {
    800 	register char *cp;
    801 	static char line[50];
    802 	struct hostent *hp;
    803 	static char domain[MAXHOSTNAMELEN + 1];
    804 	static int first = 1;
    805 
    806 	if (first && !nflag) {
    807 		first = 0;
    808 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
    809 		    (cp = index(domain, '.')))
    810 			(void) strcpy(domain, cp + 1);
    811 		else
    812 			domain[0] = 0;
    813 	}
    814 	cp = 0;
    815 	if (!nflag && in.s_addr != INADDR_ANY) {
    816 		hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
    817 		if (hp) {
    818 			if ((cp = index(hp->h_name, '.')) &&
    819 			    !strcmp(cp + 1, domain))
    820 				*cp = 0;
    821 			cp = hp->h_name;
    822 		}
    823 	}
    824 	if (cp)
    825 		(void) strcpy(line, cp);
    826 	else {
    827 		in.s_addr = ntohl(in.s_addr);
    828 #define C(x)	((x) & 0xff)
    829 		Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
    830 			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
    831 	}
    832 	return (line);
    833 }
    834 
    835 void
    836 usage()
    837 {
    838 	(void)fprintf(stderr,
    839 "usage: traceroute [-dDnrv] [-g gateway_addr] ... [-m max_ttl] [-p port#]\n\t\
    840 [-q nqueries] [-s src_addr] [-t tos] [-w wait] host [data size]\n");
    841 	exit(1);
    842 }
    843