141127Sbostic /*-
241127Sbostic  * Copyright (c) 1990 The Regents of the University of California.
341127Sbostic  * All rights reserved.
441127Sbostic  *
541127Sbostic  * This code is derived from software contributed to Berkeley by
641127Sbostic  * Van Jacobson.
741127Sbostic  *
841127Sbostic  * %sccs.include.redist.c%
941127Sbostic  */
1041127Sbostic 
1141125Sbostic #ifndef lint
1241127Sbostic char copyright[] =
1341127Sbostic "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
1441127Sbostic  All rights reserved.\n";
1541127Sbostic #endif /* not lint */
1641125Sbostic 
1741127Sbostic #ifndef lint
18*41128Sbostic static char sccsid[] = "@(#)traceroute.c	5.3 (Berkeley) 04/28/90";
1941127Sbostic #endif /* not lint */
2041127Sbostic 
2141125Sbostic /*
2241125Sbostic  * traceroute host  - trace the route ip packets follow going to "host".
2341125Sbostic  *
2441125Sbostic  * Attempt to trace the route an ip packet would follow to some
2541125Sbostic  * internet host.  We find out intermediate hops by launching probe
2641125Sbostic  * packets with a small ttl (time to live) then listening for an
2741125Sbostic  * icmp "time exceeded" reply from a gateway.  We start our probes
2841125Sbostic  * with a ttl of one and increase by one until we get an icmp "port
2941125Sbostic  * unreachable" (which means we got to "host") or hit a max (which
3041125Sbostic  * defaults to 30 hops & can be changed with the -m flag).  Three
3141125Sbostic  * probes (change with -q flag) are sent at each ttl setting and a
3241125Sbostic  * line is printed showing the ttl, address of the gateway and
3341125Sbostic  * round trip time of each probe.  If the probe answers come from
3441125Sbostic  * different gateways, the address of each responding system will
3541125Sbostic  * be printed.  If there is no response within a 5 sec. timeout
3641125Sbostic  * interval (changed with the -w flag), a "*" is printed for that
3741125Sbostic  * probe.
3841125Sbostic  *
3941125Sbostic  * Probe packets are UDP format.  We don't want the destination
4041125Sbostic  * host to process them so the destination port is set to an
4141125Sbostic  * unlikely value (if some clod on the destination is using that
4241125Sbostic  * value, it can be changed with the -p flag).
4341125Sbostic  *
4441125Sbostic  * A sample use might be:
4541125Sbostic  *
4641125Sbostic  *     [yak 71]% traceroute nis.nsf.net.
4741125Sbostic  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
4841125Sbostic  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
4941125Sbostic  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
5041125Sbostic  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
5141125Sbostic  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
5241125Sbostic  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
5341125Sbostic  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
5441125Sbostic  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
5541125Sbostic  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
5641125Sbostic  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
5741125Sbostic  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
5841125Sbostic  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
5941125Sbostic  *
6041125Sbostic  * Note that lines 2 & 3 are the same.  This is due to a buggy
6141125Sbostic  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
6241125Sbostic  * packets with a zero ttl.
6341125Sbostic  *
6441125Sbostic  * A more interesting example is:
6541125Sbostic  *
6641125Sbostic  *     [yak 72]% traceroute allspice.lcs.mit.edu.
6741125Sbostic  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
6841125Sbostic  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
6941125Sbostic  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
7041125Sbostic  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
7141125Sbostic  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
7241125Sbostic  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
7341125Sbostic  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
7441125Sbostic  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
7541125Sbostic  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
7641125Sbostic  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
7741125Sbostic  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
7841125Sbostic  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
7941125Sbostic  *     12  * * *
8041125Sbostic  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
8141125Sbostic  *     14  * * *
8241125Sbostic  *     15  * * *
8341125Sbostic  *     16  * * *
8441125Sbostic  *     17  * * *
8541125Sbostic  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
8641125Sbostic  *
8741125Sbostic  * (I start to see why I'm having so much trouble with mail to
8841125Sbostic  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
8941125Sbostic  * either don't send ICMP "time exceeded" messages or send them
9041125Sbostic  * with a ttl too small to reach us.  14 - 17 are running the
9141125Sbostic  * MIT C Gateway code that doesn't send "time exceeded"s.  God
9241125Sbostic  * only knows what's going on with 12.
9341125Sbostic  *
9441125Sbostic  * The silent gateway 12 in the above may be the result of a bug in
9541125Sbostic  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
9641125Sbostic  * sends an unreachable message using whatever ttl remains in the
9741125Sbostic  * original datagram.  Since, for gateways, the remaining ttl is
9841125Sbostic  * zero, the icmp "time exceeded" is guaranteed to not make it back
9941125Sbostic  * to us.  The behavior of this bug is slightly more interesting
10041125Sbostic  * when it appears on the destination system:
10141125Sbostic  *
10241125Sbostic  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
10341125Sbostic  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
10441125Sbostic  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
10541125Sbostic  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
10641125Sbostic  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
10741125Sbostic  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
10841125Sbostic  *      7  * * *
10941125Sbostic  *      8  * * *
11041125Sbostic  *      9  * * *
11141125Sbostic  *     10  * * *
11241125Sbostic  *     11  * * *
11341125Sbostic  *     12  * * *
11441125Sbostic  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
11541125Sbostic  *
11641125Sbostic  * Notice that there are 12 "gateways" (13 is the final
11741125Sbostic  * destination) and exactly the last half of them are "missing".
11841125Sbostic  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
11941125Sbostic  * is using the ttl from our arriving datagram as the ttl in its
12041125Sbostic  * icmp reply.  So, the reply will time out on the return path
12141125Sbostic  * (with no notice sent to anyone since icmp's aren't sent for
12241125Sbostic  * icmp's) until we probe with a ttl that's at least twice the path
12341125Sbostic  * length.  I.e., rip is really only 7 hops away.  A reply that
12441125Sbostic  * returns with a ttl of 1 is a clue this problem exists.
12541125Sbostic  * Traceroute prints a "!" after the time if the ttl is <= 1.
12641125Sbostic  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
12741125Sbostic  * non-standard (HPUX) software, expect to see this problem
12841125Sbostic  * frequently and/or take care picking the target host of your
12941125Sbostic  * probes.
13041125Sbostic  *
13141125Sbostic  * Other possible annotations after the time are !H, !N, !P (got a host,
13241125Sbostic  * network or protocol unreachable, respectively), !S or !F (source
13341125Sbostic  * route failed or fragmentation needed -- neither of these should
13441125Sbostic  * ever occur and the associated gateway is busted if you see one).  If
13541125Sbostic  * almost all the probes result in some kind of unreachable, traceroute
13641125Sbostic  * will give up and exit.
13741125Sbostic  *
13841125Sbostic  * Notes
13941125Sbostic  * -----
14041125Sbostic  * This program must be run by root or be setuid.  (I suggest that
14141125Sbostic  * you *don't* make it setuid -- casual use could result in a lot
14241125Sbostic  * of unnecessary traffic on our poor, congested nets.)
14341125Sbostic  *
14441125Sbostic  * This program requires a kernel mod that does not appear in any
14541125Sbostic  * system available from Berkeley:  A raw ip socket using proto
14641125Sbostic  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
14741125Sbostic  * opposed to data to be wrapped in a ip datagram).  See the README
14841125Sbostic  * file that came with the source to this program for a description
14941125Sbostic  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
15041125Sbostic  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
15141125Sbostic  * MODIFIED TO RUN THIS PROGRAM.
15241125Sbostic  *
15341125Sbostic  * The udp port usage may appear bizarre (well, ok, it is bizarre).
15441125Sbostic  * The problem is that an icmp message only contains 8 bytes of
15541125Sbostic  * data from the original datagram.  8 bytes is the size of a udp
15641125Sbostic  * header so, if we want to associate replies with the original
15741125Sbostic  * datagram, the necessary information must be encoded into the
15841125Sbostic  * udp header (the ip id could be used but there's no way to
15941125Sbostic  * interlock with the kernel's assignment of ip id's and, anyway,
16041125Sbostic  * it would have taken a lot more kernel hacking to allow this
16141125Sbostic  * code to set the ip id).  So, to allow two or more users to
16241125Sbostic  * use traceroute simultaneously, we use this task's pid as the
16341125Sbostic  * source port (the high bit is set to move the port number out
16441125Sbostic  * of the "likely" range).  To keep track of which probe is being
16541125Sbostic  * replied to (so times and/or hop counts don't get confused by a
16641125Sbostic  * reply that was delayed in transit), we increment the destination
16741125Sbostic  * port number before each probe.
16841125Sbostic  *
16941125Sbostic  * Don't use this as a coding example.  I was trying to find a
17041125Sbostic  * routing problem and this code sort-of popped out after 48 hours
17141125Sbostic  * without sleep.  I was amazed it ever compiled, much less ran.
17241125Sbostic  *
17341125Sbostic  * I stole the idea for this program from Steve Deering.  Since
17441125Sbostic  * the first release, I've learned that had I attended the right
17541125Sbostic  * IETF working group meetings, I also could have stolen it from Guy
17641125Sbostic  * Almes or Matt Mathis.  I don't know (or care) who came up with
17741125Sbostic  * the idea first.  I envy the originators' perspicacity and I'm
17841125Sbostic  * glad they didn't keep the idea a secret.
17941125Sbostic  *
18041125Sbostic  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
18141125Sbostic  * enhancements to the original distribution.
18241125Sbostic  *
18341125Sbostic  * I've hacked up a round-trip-route version of this that works by
18441125Sbostic  * sending a loose-source-routed udp datagram through the destination
18541125Sbostic  * back to yourself.  Unfortunately, SO many gateways botch source
18641125Sbostic  * routing, the thing is almost worthless.  Maybe one day...
18741125Sbostic  *
18841125Sbostic  *  -- Van Jacobson (van@helios.ee.lbl.gov)
18941125Sbostic  *     Tue Dec 20 03:50:13 PST 1988
19041125Sbostic  */
19141125Sbostic 
19241125Sbostic #include <stdio.h>
19341125Sbostic #include <errno.h>
19441125Sbostic #include <strings.h>
19541125Sbostic #include <sys/time.h>
19641125Sbostic 
19741125Sbostic #include <sys/param.h>
19841125Sbostic #include <sys/socket.h>
19941125Sbostic #include <sys/file.h>
20041125Sbostic #include <sys/ioctl.h>
20141125Sbostic 
20241125Sbostic #include <netinet/in_systm.h>
20341125Sbostic #include <netinet/in.h>
20441125Sbostic #include <netinet/ip.h>
20541125Sbostic #include <netinet/ip_icmp.h>
20641125Sbostic #include <netinet/udp.h>
20741125Sbostic #include <netdb.h>
20841125Sbostic 
20941125Sbostic #define	MAXPACKET	65535	/* max ip packet size */
21041125Sbostic #ifndef MAXHOSTNAMELEN
21141125Sbostic #define MAXHOSTNAMELEN	64
21241125Sbostic #endif
21341125Sbostic 
21441125Sbostic #ifndef FD_SET
21541125Sbostic #define NFDBITS         (8*sizeof(fd_set))
21641125Sbostic #define FD_SETSIZE      NFDBITS
21741125Sbostic #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
21841125Sbostic #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
21941125Sbostic #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
22041125Sbostic #define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
22141125Sbostic #endif
22241125Sbostic 
22341125Sbostic #define Fprintf (void)fprintf
22441125Sbostic #define Sprintf (void)sprintf
22541125Sbostic #define Printf (void)printf
22641125Sbostic extern	int errno;
22741125Sbostic extern  char *malloc();
22841125Sbostic extern  char *inet_ntoa();
22941125Sbostic extern  u_long inet_addr();
23041125Sbostic 
23141125Sbostic /*
23241125Sbostic  * format of a (udp) probe packet.
23341125Sbostic  */
23441125Sbostic struct opacket {
23541125Sbostic 	struct ip ip;
23641125Sbostic 	struct udphdr udp;
23741125Sbostic 	u_char seq;		/* sequence number of this packet */
23841125Sbostic 	u_char ttl;		/* ttl packet left with */
23941125Sbostic 	struct timeval tv;	/* time packet left */
24041125Sbostic };
24141125Sbostic 
24241125Sbostic u_char	packet[512];		/* last inbound (icmp) packet */
24341125Sbostic struct opacket	*outpacket;	/* last output (udp) packet */
24441125Sbostic char *inetname();
24541125Sbostic 
24641125Sbostic int s;				/* receive (icmp) socket file descriptor */
24741125Sbostic int sndsock;			/* send (udp) socket file descriptor */
24841125Sbostic struct timezone tz;		/* leftover */
24941125Sbostic 
25041125Sbostic struct sockaddr whereto;	/* Who to try to reach */
25141125Sbostic int datalen;			/* How much data */
25241125Sbostic 
25341125Sbostic char *source = 0;
25441125Sbostic char *hostname;
25541125Sbostic 
25641125Sbostic int nprobes = 3;
25741125Sbostic int max_ttl = 30;
25841125Sbostic u_short ident;
25941125Sbostic u_short port = 32768+666;	/* start udp dest port # for probe packets */
26041125Sbostic int options;			/* socket options */
26141125Sbostic int verbose;
26241125Sbostic int waittime = 5;		/* time to wait for response (in seconds) */
26341125Sbostic int nflag;			/* print addresses numerically */
26441125Sbostic 
26541125Sbostic main(argc, argv)
26641125Sbostic 	char *argv[];
26741125Sbostic {
268*41128Sbostic 	extern char *optarg;
269*41128Sbostic 	extern int optind;
270*41128Sbostic 	struct hostent *hp;
27141125Sbostic 	struct protoent *pe;
272*41128Sbostic 	struct sockaddr_in from, *to;
273*41128Sbostic 	int ch, i, on, probe, seq, tos, ttl;
27441125Sbostic 
275*41128Sbostic 	on = 1;
276*41128Sbostic 	seq = tos = 0;
277*41128Sbostic 	to = (struct sockaddr_in *)&whereto;
278*41128Sbostic 	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
279*41128Sbostic 		switch(ch) {
280*41128Sbostic 		case 'd':
281*41128Sbostic 			options |= SO_DEBUG;
282*41128Sbostic 			break;
283*41128Sbostic 		case 'm':
284*41128Sbostic 			max_ttl = atoi(optarg);
285*41128Sbostic 			if (max_ttl <= 1) {
286*41128Sbostic 				Fprintf(stderr,
287*41128Sbostic 				    "traceroute: max ttl must be >1.\n");
288*41128Sbostic 				exit(1);
28941125Sbostic 			}
290*41128Sbostic 			break;
291*41128Sbostic 		case 'n':
292*41128Sbostic 			nflag++;
293*41128Sbostic 			break;
294*41128Sbostic 		case 'p':
295*41128Sbostic 			port = atoi(optarg);
296*41128Sbostic 			if (port < 1) {
297*41128Sbostic 				Fprintf(stderr,
298*41128Sbostic 				    "traceroute: port must be >0.\n");
299*41128Sbostic 				exit(1);
300*41128Sbostic 			}
301*41128Sbostic 			break;
302*41128Sbostic 		case 'q':
303*41128Sbostic 			nprobes = atoi(optarg);
304*41128Sbostic 			if (nprobes < 1) {
305*41128Sbostic 				Fprintf(stderr,
306*41128Sbostic 				    "traceroute: nprobes must be >0.\n");
307*41128Sbostic 				exit(1);
308*41128Sbostic 			}
309*41128Sbostic 			break;
310*41128Sbostic 		case 'r':
311*41128Sbostic 			options |= SO_DONTROUTE;
312*41128Sbostic 			break;
313*41128Sbostic 		case 's':
314*41128Sbostic 			/*
315*41128Sbostic 			 * set the ip source address of the outbound
316*41128Sbostic 			 * probe (e.g., on a multi-homed host).
317*41128Sbostic 			 */
318*41128Sbostic 			source = optarg;
319*41128Sbostic 			break;
320*41128Sbostic 		case 't':
321*41128Sbostic 			tos = atoi(optarg);
322*41128Sbostic 			if (tos < 0 || tos > 255) {
323*41128Sbostic 				Fprintf(stderr,
324*41128Sbostic 				    "traceroute: tos must be 0 to 255.\n");
325*41128Sbostic 				exit(1);
326*41128Sbostic 			}
327*41128Sbostic 			break;
328*41128Sbostic 		case 'v':
329*41128Sbostic 			verbose++;
330*41128Sbostic 			break;
331*41128Sbostic 		case 'w':
332*41128Sbostic 			waittime = atoi(optarg);
333*41128Sbostic 			if (waittime <= 1) {
334*41128Sbostic 				Fprintf(stderr,
335*41128Sbostic 				    "traceroute: wait must be >1 sec.\n");
336*41128Sbostic 				exit(1);
337*41128Sbostic 			}
338*41128Sbostic 			break;
339*41128Sbostic 		default:
340*41128Sbostic 			usage();
341*41128Sbostic 		}
342*41128Sbostic 	argc -= optind;
343*41128Sbostic 	argv += optind;
344*41128Sbostic 
345*41128Sbostic 	if (argc < 1)
346*41128Sbostic 		usage();
347*41128Sbostic 
34841125Sbostic 	setlinebuf (stdout);
34941125Sbostic 
35041125Sbostic 	(void) bzero((char *)&whereto, sizeof(struct sockaddr));
35141125Sbostic 	to->sin_family = AF_INET;
352*41128Sbostic 	to->sin_addr.s_addr = inet_addr(*argv);
353*41128Sbostic 	if (to->sin_addr.s_addr != -1)
354*41128Sbostic 		hostname = *argv;
355*41128Sbostic 	else {
356*41128Sbostic 		hp = gethostbyname(*argv);
35741125Sbostic 		if (hp) {
35841125Sbostic 			to->sin_family = hp->h_addrtype;
35941125Sbostic 			bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
36041125Sbostic 			hostname = hp->h_name;
36141125Sbostic 		} else {
362*41128Sbostic 			(void)fprintf(stderr,
363*41128Sbostic 			    "traceroute: unknown host %s\n", *argv);
36441125Sbostic 			exit(1);
36541125Sbostic 		}
36641125Sbostic 	}
367*41128Sbostic 	if (*++argv)
368*41128Sbostic 		datalen = atoi(*argv);
36941125Sbostic 	if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
370*41128Sbostic 		Fprintf(stderr,
371*41128Sbostic 		    "traceroute: packet size must be 0 <= s < %ld.\n",
372*41128Sbostic 		    MAXPACKET - sizeof(struct opacket));
37341125Sbostic 		exit(1);
37441125Sbostic 	}
37541125Sbostic 	datalen += sizeof(struct opacket);
37641125Sbostic 	outpacket = (struct opacket *)malloc((unsigned)datalen);
37741125Sbostic 	if (! outpacket) {
37841125Sbostic 		perror("traceroute: malloc");
37941125Sbostic 		exit(1);
38041125Sbostic 	}
38141125Sbostic 	(void) bzero((char *)outpacket, datalen);
38241125Sbostic 	outpacket->ip.ip_dst = to->sin_addr;
38341125Sbostic 	outpacket->ip.ip_tos = tos;
38441125Sbostic 
38541125Sbostic 	ident = (getpid() & 0xffff) | 0x8000;
38641125Sbostic 
38741125Sbostic 	if ((pe = getprotobyname("icmp")) == NULL) {
38841125Sbostic 		Fprintf(stderr, "icmp: unknown protocol\n");
38941125Sbostic 		exit(10);
39041125Sbostic 	}
39141125Sbostic 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
39241125Sbostic 		perror("traceroute: icmp socket");
39341125Sbostic 		exit(5);
39441125Sbostic 	}
39541125Sbostic 	if (options & SO_DEBUG)
39641125Sbostic 		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
39741125Sbostic 				  (char *)&on, sizeof(on));
39841125Sbostic 	if (options & SO_DONTROUTE)
39941125Sbostic 		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
40041125Sbostic 				  (char *)&on, sizeof(on));
40141125Sbostic 
40241125Sbostic 	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
40341125Sbostic 		perror("traceroute: raw socket");
40441125Sbostic 		exit(5);
40541125Sbostic 	}
40641125Sbostic #ifdef SO_SNDBUF
40741125Sbostic 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
40841125Sbostic 		       sizeof(datalen)) < 0) {
40941125Sbostic 		perror("traceroute: SO_SNDBUF");
41041125Sbostic 		exit(6);
41141125Sbostic 	}
41241125Sbostic #endif SO_SNDBUF
41341125Sbostic #ifdef IP_HDRINCL
41441125Sbostic 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
41541125Sbostic 		       sizeof(on)) < 0) {
41641125Sbostic 		perror("traceroute: IP_HDRINCL");
41741125Sbostic 		exit(6);
41841125Sbostic 	}
41941125Sbostic #endif IP_HDRINCL
42041125Sbostic 	if (options & SO_DEBUG)
42141125Sbostic 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
42241125Sbostic 				  (char *)&on, sizeof(on));
42341125Sbostic 	if (options & SO_DONTROUTE)
42441125Sbostic 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
42541125Sbostic 				  (char *)&on, sizeof(on));
42641125Sbostic 
42741125Sbostic 	if (source) {
42841125Sbostic 		(void) bzero((char *)&from, sizeof(struct sockaddr));
42941125Sbostic 		from.sin_family = AF_INET;
43041125Sbostic 		from.sin_addr.s_addr = inet_addr(source);
43141125Sbostic 		if (from.sin_addr.s_addr == -1) {
43241125Sbostic 			Printf("traceroute: unknown host %s\n", source);
43341125Sbostic 			exit(1);
43441125Sbostic 		}
43541125Sbostic 		outpacket->ip.ip_src = from.sin_addr;
43641125Sbostic #ifndef IP_HDRINCL
43741125Sbostic 		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
43841125Sbostic 			perror ("traceroute: bind:");
43941125Sbostic 			exit (1);
44041125Sbostic 		}
44141125Sbostic #endif IP_HDRINCL
44241125Sbostic 	}
44341125Sbostic 
44441125Sbostic 	Fprintf(stderr, "traceroute to %s (%s)", hostname,
44541125Sbostic 		inet_ntoa(to->sin_addr));
44641125Sbostic 	if (source)
44741125Sbostic 		Fprintf(stderr, " from %s", source);
44841125Sbostic 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
44941125Sbostic 	(void) fflush(stderr);
45041125Sbostic 
45141125Sbostic 	for (ttl = 1; ttl <= max_ttl; ++ttl) {
45241125Sbostic 		u_long lastaddr = 0;
45341125Sbostic 		int got_there = 0;
45441125Sbostic 		int unreachable = 0;
45541125Sbostic 
45641125Sbostic 		Printf("%2d ", ttl);
45741125Sbostic 		for (probe = 0; probe < nprobes; ++probe) {
45841125Sbostic 			int cc;
45941125Sbostic 			struct timeval tv;
46041125Sbostic 			struct ip *ip;
46141125Sbostic 
46241125Sbostic 			(void) gettimeofday(&tv, &tz);
46341125Sbostic 			send_probe(++seq, ttl);
46441125Sbostic 			while (cc = wait_for_reply(s, &from)) {
46541125Sbostic 				if ((i = packet_ok(packet, cc, &from, seq))) {
46641125Sbostic 					int dt = deltaT(&tv);
46741125Sbostic 					if (from.sin_addr.s_addr != lastaddr) {
46841125Sbostic 						print(packet, cc, &from);
46941125Sbostic 						lastaddr = from.sin_addr.s_addr;
47041125Sbostic 					}
47141125Sbostic 					Printf("  %d ms", dt);
47241125Sbostic 					switch(i - 1) {
47341125Sbostic 					case ICMP_UNREACH_PORT:
47441125Sbostic #ifndef ARCHAIC
47541125Sbostic 						ip = (struct ip *)packet;
47641125Sbostic 						if (ip->ip_ttl <= 1)
47741125Sbostic 							Printf(" !");
47841125Sbostic #endif ARCHAIC
47941125Sbostic 						++got_there;
48041125Sbostic 						break;
48141125Sbostic 					case ICMP_UNREACH_NET:
48241125Sbostic 						++unreachable;
48341125Sbostic 						Printf(" !N");
48441125Sbostic 						break;
48541125Sbostic 					case ICMP_UNREACH_HOST:
48641125Sbostic 						++unreachable;
48741125Sbostic 						Printf(" !H");
48841125Sbostic 						break;
48941125Sbostic 					case ICMP_UNREACH_PROTOCOL:
49041125Sbostic 						++got_there;
49141125Sbostic 						Printf(" !P");
49241125Sbostic 						break;
49341125Sbostic 					case ICMP_UNREACH_NEEDFRAG:
49441125Sbostic 						++unreachable;
49541125Sbostic 						Printf(" !F");
49641125Sbostic 						break;
49741125Sbostic 					case ICMP_UNREACH_SRCFAIL:
49841125Sbostic 						++unreachable;
49941125Sbostic 						Printf(" !S");
50041125Sbostic 						break;
50141125Sbostic 					}
50241125Sbostic 					break;
50341125Sbostic 				}
50441125Sbostic 			}
50541125Sbostic 			if (cc == 0)
50641125Sbostic 				Printf(" *");
50741125Sbostic 			(void) fflush(stdout);
50841125Sbostic 		}
50941125Sbostic 		putchar('\n');
51041125Sbostic 		if (got_there || unreachable >= nprobes-1)
51141125Sbostic 			exit(0);
51241125Sbostic 	}
51341125Sbostic }
51441125Sbostic 
51541125Sbostic wait_for_reply(sock, from)
51641125Sbostic 	int sock;
51741125Sbostic 	struct sockaddr_in *from;
51841125Sbostic {
51941125Sbostic 	fd_set fds;
52041125Sbostic 	struct timeval wait;
52141125Sbostic 	int cc = 0;
52241125Sbostic 	int fromlen = sizeof (*from);
52341125Sbostic 
52441125Sbostic 	FD_ZERO(&fds);
52541125Sbostic 	FD_SET(sock, &fds);
52641125Sbostic 	wait.tv_sec = waittime; wait.tv_usec = 0;
52741125Sbostic 
52841125Sbostic 	if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
52941125Sbostic 		cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
53041125Sbostic 			    (struct sockaddr *)from, &fromlen);
53141125Sbostic 
53241125Sbostic 	return(cc);
53341125Sbostic }
53441125Sbostic 
53541125Sbostic 
53641125Sbostic send_probe(seq, ttl)
53741125Sbostic {
53841125Sbostic 	struct opacket *op = outpacket;
53941125Sbostic 	struct ip *ip = &op->ip;
54041125Sbostic 	struct udphdr *up = &op->udp;
54141125Sbostic 	int i;
54241125Sbostic 
54341125Sbostic 	ip->ip_off = 0;
54441125Sbostic 	ip->ip_p = IPPROTO_UDP;
54541125Sbostic 	ip->ip_len = datalen;
54641125Sbostic 	ip->ip_ttl = ttl;
54741125Sbostic 
54841125Sbostic 	up->uh_sport = htons(ident);
54941125Sbostic 	up->uh_dport = htons(port+seq);
55041125Sbostic 	up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
55141125Sbostic 	up->uh_sum = 0;
55241125Sbostic 
55341125Sbostic 	op->seq = seq;
55441125Sbostic 	op->ttl = ttl;
55541125Sbostic 	(void) gettimeofday(&op->tv, &tz);
55641125Sbostic 
55741125Sbostic 	i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
55841125Sbostic 		   sizeof(struct sockaddr));
55941125Sbostic 	if (i < 0 || i != datalen)  {
56041125Sbostic 		if (i<0)
56141125Sbostic 			perror("sendto");
56241125Sbostic 		Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
56341125Sbostic 			datalen, i);
56441125Sbostic 		(void) fflush(stdout);
56541125Sbostic 	}
56641125Sbostic }
56741125Sbostic 
56841125Sbostic 
56941125Sbostic deltaT(tp)
57041125Sbostic 	struct timeval *tp;
57141125Sbostic {
57241125Sbostic 	struct timeval tv;
57341125Sbostic 
57441125Sbostic 	(void) gettimeofday(&tv, &tz);
57541125Sbostic 	tvsub(&tv, tp);
57641125Sbostic 	return (tv.tv_sec*1000 + (tv.tv_usec + 500)/1000);
57741125Sbostic }
57841125Sbostic 
57941125Sbostic 
58041125Sbostic /*
58141125Sbostic  * Convert an ICMP "type" field to a printable string.
58241125Sbostic  */
58341125Sbostic char *
58441125Sbostic pr_type(t)
58541125Sbostic 	u_char t;
58641125Sbostic {
58741125Sbostic 	static char *ttab[] = {
58841125Sbostic 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
58941125Sbostic 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
59041125Sbostic 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
59141125Sbostic 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
59241125Sbostic 	"Info Reply"
59341125Sbostic 	};
59441125Sbostic 
59541125Sbostic 	if(t > 16)
59641125Sbostic 		return("OUT-OF-RANGE");
59741125Sbostic 
59841125Sbostic 	return(ttab[t]);
59941125Sbostic }
60041125Sbostic 
60141125Sbostic 
60241125Sbostic packet_ok(buf, cc, from, seq)
60341125Sbostic 	u_char *buf;
60441125Sbostic 	int cc;
60541125Sbostic 	struct sockaddr_in *from;
60641125Sbostic 	int seq;
60741125Sbostic {
60841125Sbostic 	register struct icmp *icp;
60941125Sbostic 	u_char type, code;
61041125Sbostic 	int hlen;
61141125Sbostic #ifndef ARCHAIC
61241125Sbostic 	struct ip *ip;
61341125Sbostic 
61441125Sbostic 	ip = (struct ip *) buf;
61541125Sbostic 	hlen = ip->ip_hl << 2;
61641125Sbostic 	if (cc < hlen + ICMP_MINLEN) {
61741125Sbostic 		if (verbose)
61841125Sbostic 			Printf("packet too short (%d bytes) from %s\n", cc,
61941125Sbostic 				inet_ntoa(from->sin_addr));
62041125Sbostic 		return (0);
62141125Sbostic 	}
62241125Sbostic 	cc -= hlen;
62341125Sbostic 	icp = (struct icmp *)(buf + hlen);
62441125Sbostic #else
62541125Sbostic 	icp = (struct icmp *)buf;
62641125Sbostic #endif ARCHAIC
62741125Sbostic 	type = icp->icmp_type; code = icp->icmp_code;
62841125Sbostic 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
62941125Sbostic 	    type == ICMP_UNREACH) {
63041125Sbostic 		struct ip *hip;
63141125Sbostic 		struct udphdr *up;
63241125Sbostic 
63341125Sbostic 		hip = &icp->icmp_ip;
63441125Sbostic 		hlen = hip->ip_hl << 2;
63541125Sbostic 		up = (struct udphdr *)((u_char *)hip + hlen);
63641125Sbostic 		if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
63741125Sbostic 		    up->uh_sport == htons(ident) &&
63841125Sbostic 		    up->uh_dport == htons(port+seq))
63941125Sbostic 			return (type == ICMP_TIMXCEED? -1 : code+1);
64041125Sbostic 	}
64141125Sbostic #ifndef ARCHAIC
64241125Sbostic 	if (verbose) {
64341125Sbostic 		int i;
64441125Sbostic 		u_long *lp = (u_long *)&icp->icmp_ip;
64541125Sbostic 
64641125Sbostic 		Printf("\n%d bytes from %s to %s", cc,
64741125Sbostic 			inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
64841125Sbostic 		Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
64941125Sbostic 		       icp->icmp_code);
65041125Sbostic 		for (i = 4; i < cc ; i += sizeof(long))
65141125Sbostic 			Printf("%2d: x%8.8lx\n", i, *lp++);
65241125Sbostic 	}
65341125Sbostic #endif ARCHAIC
65441125Sbostic 	return(0);
65541125Sbostic }
65641125Sbostic 
65741125Sbostic 
65841125Sbostic print(buf, cc, from)
65941125Sbostic 	u_char *buf;
66041125Sbostic 	int cc;
66141125Sbostic 	struct sockaddr_in *from;
66241125Sbostic {
66341125Sbostic 	struct ip *ip;
66441125Sbostic 	int hlen;
66541125Sbostic 
66641125Sbostic 	ip = (struct ip *) buf;
66741125Sbostic 	hlen = ip->ip_hl << 2;
66841125Sbostic 	cc -= hlen;
66941125Sbostic 
67041125Sbostic 	if (nflag)
67141125Sbostic 		Printf(" %s", inet_ntoa(from->sin_addr));
67241125Sbostic 	else
67341125Sbostic 		Printf(" %s (%s)", inetname(from->sin_addr),
67441125Sbostic 		       inet_ntoa(from->sin_addr));
67541125Sbostic 
67641125Sbostic 	if (verbose)
67741125Sbostic 		Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
67841125Sbostic }
67941125Sbostic 
68041125Sbostic 
68141125Sbostic #ifdef notyet
68241125Sbostic /*
68341125Sbostic  * Checksum routine for Internet Protocol family headers (C Version)
68441125Sbostic  */
68541125Sbostic in_cksum(addr, len)
68641125Sbostic u_short *addr;
68741125Sbostic int len;
68841125Sbostic {
68941125Sbostic 	register int nleft = len;
69041125Sbostic 	register u_short *w = addr;
69141125Sbostic 	register u_short answer;
69241125Sbostic 	register int sum = 0;
69341125Sbostic 
69441125Sbostic 	/*
69541125Sbostic 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
69641125Sbostic 	 *  we add sequential 16 bit words to it, and at the end, fold
69741125Sbostic 	 *  back all the carry bits from the top 16 bits into the lower
69841125Sbostic 	 *  16 bits.
69941125Sbostic 	 */
70041125Sbostic 	while (nleft > 1)  {
70141125Sbostic 		sum += *w++;
70241125Sbostic 		nleft -= 2;
70341125Sbostic 	}
70441125Sbostic 
70541125Sbostic 	/* mop up an odd byte, if necessary */
70641125Sbostic 	if (nleft == 1)
70741125Sbostic 		sum += *(u_char *)w;
70841125Sbostic 
70941125Sbostic 	/*
71041125Sbostic 	 * add back carry outs from top 16 bits to low 16 bits
71141125Sbostic 	 */
71241125Sbostic 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
71341125Sbostic 	sum += (sum >> 16);			/* add carry */
71441125Sbostic 	answer = ~sum;				/* truncate to 16 bits */
71541125Sbostic 	return (answer);
71641125Sbostic }
71741125Sbostic #endif notyet
71841125Sbostic 
71941125Sbostic /*
72041125Sbostic  * Subtract 2 timeval structs:  out = out - in.
72141125Sbostic  * Out is assumed to be >= in.
72241125Sbostic  */
72341125Sbostic tvsub(out, in)
72441125Sbostic register struct timeval *out, *in;
72541125Sbostic {
72641125Sbostic 	if ((out->tv_usec -= in->tv_usec) < 0)   {
72741125Sbostic 		out->tv_sec--;
72841125Sbostic 		out->tv_usec += 1000000;
72941125Sbostic 	}
73041125Sbostic 	out->tv_sec -= in->tv_sec;
73141125Sbostic }
73241125Sbostic 
73341125Sbostic 
73441125Sbostic /*
73541125Sbostic  * Construct an Internet address representation.
73641125Sbostic  * If the nflag has been supplied, give
73741125Sbostic  * numeric value, otherwise try for symbolic name.
73841125Sbostic  */
73941125Sbostic char *
74041125Sbostic inetname(in)
74141125Sbostic 	struct in_addr in;
74241125Sbostic {
74341125Sbostic 	register char *cp;
74441125Sbostic 	static char line[50];
74541125Sbostic 	struct hostent *hp;
74641125Sbostic 	static char domain[MAXHOSTNAMELEN + 1];
74741125Sbostic 	static int first = 1;
74841125Sbostic 
74941125Sbostic 	if (first && !nflag) {
75041125Sbostic 		first = 0;
75141125Sbostic 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
75241125Sbostic 		    (cp = index(domain, '.')))
75341125Sbostic 			(void) strcpy(domain, cp + 1);
75441125Sbostic 		else
75541125Sbostic 			domain[0] = 0;
75641125Sbostic 	}
75741125Sbostic 	cp = 0;
75841125Sbostic 	if (!nflag && in.s_addr != INADDR_ANY) {
75941125Sbostic 		hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
76041125Sbostic 		if (hp) {
76141125Sbostic 			if ((cp = index(hp->h_name, '.')) &&
76241125Sbostic 			    !strcmp(cp + 1, domain))
76341125Sbostic 				*cp = 0;
76441125Sbostic 			cp = hp->h_name;
76541125Sbostic 		}
76641125Sbostic 	}
76741125Sbostic 	if (cp)
76841125Sbostic 		(void) strcpy(line, cp);
76941125Sbostic 	else {
77041125Sbostic 		in.s_addr = ntohl(in.s_addr);
77141125Sbostic #define C(x)	((x) & 0xff)
77241125Sbostic 		Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
77341125Sbostic 			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
77441125Sbostic 	}
77541125Sbostic 	return (line);
77641125Sbostic }
777*41128Sbostic 
778*41128Sbostic usage()
779*41128Sbostic {
780*41128Sbostic 	(void)fprintf(stderr,
781*41128Sbostic "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
782*41128Sbostic [-s src_addr] [-t tos] [-w wait] host [data size]\n");
783*41128Sbostic 	exit(1);
784*41128Sbostic }
785