141127Sbostic /*-
2*61891Sbostic  * Copyright (c) 1990, 1993
3*61891Sbostic  *	The Regents of the University of California.  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
12*61891Sbostic static char copyright[] =
13*61891Sbostic "@(#) Copyright (c) 1990, 1993\n\
14*61891Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1541127Sbostic #endif /* not lint */
1641125Sbostic 
1741127Sbostic #ifndef lint
18*61891Sbostic static char sccsid[] = "@(#)traceroute.c	8.1 (Berkeley) 06/06/93";
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 
19242065Sbostic #include <sys/param.h>
19341125Sbostic #include <sys/time.h>
19441125Sbostic #include <sys/socket.h>
19541125Sbostic #include <sys/file.h>
19641125Sbostic #include <sys/ioctl.h>
19741125Sbostic 
19841125Sbostic #include <netinet/in_systm.h>
19941125Sbostic #include <netinet/in.h>
20041125Sbostic #include <netinet/ip.h>
20141125Sbostic #include <netinet/ip_icmp.h>
20241125Sbostic #include <netinet/udp.h>
20353667Sbostic 
20453667Sbostic #include <arpa/inet.h>
20553667Sbostic 
20641125Sbostic #include <netdb.h>
20742065Sbostic #include <stdio.h>
20842065Sbostic #include <errno.h>
20953667Sbostic #include <stdlib.h>
21042065Sbostic #include <string.h>
21153667Sbostic #include <unistd.h>
21242065Sbostic 
21341125Sbostic #define	MAXPACKET	65535	/* max ip packet size */
21441125Sbostic #ifndef MAXHOSTNAMELEN
21541125Sbostic #define MAXHOSTNAMELEN	64
21641125Sbostic #endif
21741125Sbostic 
21841125Sbostic #ifndef FD_SET
21941125Sbostic #define NFDBITS         (8*sizeof(fd_set))
22041125Sbostic #define FD_SETSIZE      NFDBITS
22141125Sbostic #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
22241125Sbostic #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
22341125Sbostic #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
22441125Sbostic #define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
22541125Sbostic #endif
22641125Sbostic 
22741125Sbostic #define Fprintf (void)fprintf
22841125Sbostic #define Sprintf (void)sprintf
22941125Sbostic #define Printf (void)printf
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 
24553667Sbostic int wait_for_reply __P((int, struct sockaddr_in *));
24653667Sbostic void send_probe __P((int, int));
24753667Sbostic double deltaT __P((struct timeval *, struct timeval *));
24853667Sbostic int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
24953667Sbostic void print __P((u_char *, int, struct sockaddr_in *));
25053667Sbostic void tvsub __P((struct timeval *, struct timeval *));
25153667Sbostic char *inetname __P((struct in_addr));
25253667Sbostic void usage __P(());
25353667Sbostic 
25441125Sbostic int s;				/* receive (icmp) socket file descriptor */
25541125Sbostic int sndsock;			/* send (udp) socket file descriptor */
25641125Sbostic struct timezone tz;		/* leftover */
25741125Sbostic 
25841125Sbostic struct sockaddr whereto;	/* Who to try to reach */
25941125Sbostic int datalen;			/* How much data */
26041125Sbostic 
26141125Sbostic char *source = 0;
26241125Sbostic char *hostname;
26341125Sbostic 
26441125Sbostic int nprobes = 3;
26541125Sbostic int max_ttl = 30;
26641125Sbostic u_short ident;
26741125Sbostic u_short port = 32768+666;	/* start udp dest port # for probe packets */
26841125Sbostic int options;			/* socket options */
26941125Sbostic int verbose;
27041125Sbostic int waittime = 5;		/* time to wait for response (in seconds) */
27141125Sbostic int nflag;			/* print addresses numerically */
27241125Sbostic 
27353667Sbostic int
main(argc,argv)27441125Sbostic main(argc, argv)
27553667Sbostic 	int argc;
27641125Sbostic 	char *argv[];
27741125Sbostic {
27841128Sbostic 	extern char *optarg;
27941128Sbostic 	extern int optind;
28041128Sbostic 	struct hostent *hp;
28141125Sbostic 	struct protoent *pe;
28241128Sbostic 	struct sockaddr_in from, *to;
28341128Sbostic 	int ch, i, on, probe, seq, tos, ttl;
28441125Sbostic 
28541128Sbostic 	on = 1;
28641128Sbostic 	seq = tos = 0;
28741128Sbostic 	to = (struct sockaddr_in *)&whereto;
28841128Sbostic 	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
28941128Sbostic 		switch(ch) {
29041128Sbostic 		case 'd':
29141128Sbostic 			options |= SO_DEBUG;
29241128Sbostic 			break;
29341128Sbostic 		case 'm':
29441128Sbostic 			max_ttl = atoi(optarg);
29541128Sbostic 			if (max_ttl <= 1) {
29641128Sbostic 				Fprintf(stderr,
29741128Sbostic 				    "traceroute: max ttl must be >1.\n");
29841128Sbostic 				exit(1);
29941125Sbostic 			}
30041128Sbostic 			break;
30141128Sbostic 		case 'n':
30241128Sbostic 			nflag++;
30341128Sbostic 			break;
30441128Sbostic 		case 'p':
30541128Sbostic 			port = atoi(optarg);
30641128Sbostic 			if (port < 1) {
30741128Sbostic 				Fprintf(stderr,
30841128Sbostic 				    "traceroute: port must be >0.\n");
30941128Sbostic 				exit(1);
31041128Sbostic 			}
31141128Sbostic 			break;
31241128Sbostic 		case 'q':
31341128Sbostic 			nprobes = atoi(optarg);
31441128Sbostic 			if (nprobes < 1) {
31541128Sbostic 				Fprintf(stderr,
31641128Sbostic 				    "traceroute: nprobes must be >0.\n");
31741128Sbostic 				exit(1);
31841128Sbostic 			}
31941128Sbostic 			break;
32041128Sbostic 		case 'r':
32141128Sbostic 			options |= SO_DONTROUTE;
32241128Sbostic 			break;
32341128Sbostic 		case 's':
32441128Sbostic 			/*
32541128Sbostic 			 * set the ip source address of the outbound
32641128Sbostic 			 * probe (e.g., on a multi-homed host).
32741128Sbostic 			 */
32841128Sbostic 			source = optarg;
32941128Sbostic 			break;
33041128Sbostic 		case 't':
33141128Sbostic 			tos = atoi(optarg);
33241128Sbostic 			if (tos < 0 || tos > 255) {
33341128Sbostic 				Fprintf(stderr,
33441128Sbostic 				    "traceroute: tos must be 0 to 255.\n");
33541128Sbostic 				exit(1);
33641128Sbostic 			}
33741128Sbostic 			break;
33841128Sbostic 		case 'v':
33941128Sbostic 			verbose++;
34041128Sbostic 			break;
34141128Sbostic 		case 'w':
34241128Sbostic 			waittime = atoi(optarg);
34341128Sbostic 			if (waittime <= 1) {
34441128Sbostic 				Fprintf(stderr,
34541128Sbostic 				    "traceroute: wait must be >1 sec.\n");
34641128Sbostic 				exit(1);
34741128Sbostic 			}
34841128Sbostic 			break;
34941128Sbostic 		default:
35041128Sbostic 			usage();
35141128Sbostic 		}
35241128Sbostic 	argc -= optind;
35341128Sbostic 	argv += optind;
35441128Sbostic 
35553667Sbostic 	if (argc < 1)
35641128Sbostic 		usage();
35741128Sbostic 
35841125Sbostic 	setlinebuf (stdout);
35941125Sbostic 
36041125Sbostic 	(void) bzero((char *)&whereto, sizeof(struct sockaddr));
36141125Sbostic 	to->sin_family = AF_INET;
36241128Sbostic 	to->sin_addr.s_addr = inet_addr(*argv);
36353667Sbostic 	if (to->sin_addr.s_addr != -1)
36441128Sbostic 		hostname = *argv;
36541128Sbostic 	else {
36641128Sbostic 		hp = gethostbyname(*argv);
36741125Sbostic 		if (hp) {
36841125Sbostic 			to->sin_family = hp->h_addrtype;
36941125Sbostic 			bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
37041125Sbostic 			hostname = hp->h_name;
37141125Sbostic 		} else {
37241128Sbostic 			(void)fprintf(stderr,
37341128Sbostic 			    "traceroute: unknown host %s\n", *argv);
37441125Sbostic 			exit(1);
37541125Sbostic 		}
37641125Sbostic 	}
37753667Sbostic 	if (*++argv)
37841128Sbostic 		datalen = atoi(*argv);
37941125Sbostic 	if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
38041128Sbostic 		Fprintf(stderr,
38141128Sbostic 		    "traceroute: packet size must be 0 <= s < %ld.\n",
38241128Sbostic 		    MAXPACKET - sizeof(struct opacket));
38341125Sbostic 		exit(1);
38441125Sbostic 	}
38541125Sbostic 	datalen += sizeof(struct opacket);
38641125Sbostic 	outpacket = (struct opacket *)malloc((unsigned)datalen);
38741125Sbostic 	if (! outpacket) {
38841125Sbostic 		perror("traceroute: malloc");
38941125Sbostic 		exit(1);
39041125Sbostic 	}
39141125Sbostic 	(void) bzero((char *)outpacket, datalen);
39241125Sbostic 	outpacket->ip.ip_dst = to->sin_addr;
39341125Sbostic 	outpacket->ip.ip_tos = tos;
39459018Sandrew 	outpacket->ip.ip_v = IPVERSION;
39559018Sandrew 	outpacket->ip.ip_id = 0;
39641125Sbostic 
39741125Sbostic 	ident = (getpid() & 0xffff) | 0x8000;
39841125Sbostic 
39941125Sbostic 	if ((pe = getprotobyname("icmp")) == NULL) {
40041125Sbostic 		Fprintf(stderr, "icmp: unknown protocol\n");
40141125Sbostic 		exit(10);
40241125Sbostic 	}
40341125Sbostic 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
40441125Sbostic 		perror("traceroute: icmp socket");
40541125Sbostic 		exit(5);
40641125Sbostic 	}
40741125Sbostic 	if (options & SO_DEBUG)
40841125Sbostic 		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
40941125Sbostic 				  (char *)&on, sizeof(on));
41041125Sbostic 	if (options & SO_DONTROUTE)
41141125Sbostic 		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
41241125Sbostic 				  (char *)&on, sizeof(on));
41341125Sbostic 
41441125Sbostic 	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
41541125Sbostic 		perror("traceroute: raw socket");
41641125Sbostic 		exit(5);
41741125Sbostic 	}
41841125Sbostic #ifdef SO_SNDBUF
41941125Sbostic 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
42041125Sbostic 		       sizeof(datalen)) < 0) {
42141125Sbostic 		perror("traceroute: SO_SNDBUF");
42241125Sbostic 		exit(6);
42341125Sbostic 	}
42441125Sbostic #endif SO_SNDBUF
42541125Sbostic #ifdef IP_HDRINCL
42641125Sbostic 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
42741125Sbostic 		       sizeof(on)) < 0) {
42841125Sbostic 		perror("traceroute: IP_HDRINCL");
42941125Sbostic 		exit(6);
43041125Sbostic 	}
43141125Sbostic #endif IP_HDRINCL
43241125Sbostic 	if (options & SO_DEBUG)
43341125Sbostic 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
43441125Sbostic 				  (char *)&on, sizeof(on));
43541125Sbostic 	if (options & SO_DONTROUTE)
43641125Sbostic 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
43741125Sbostic 				  (char *)&on, sizeof(on));
43841125Sbostic 
43941125Sbostic 	if (source) {
44041125Sbostic 		(void) bzero((char *)&from, sizeof(struct sockaddr));
44141125Sbostic 		from.sin_family = AF_INET;
44241125Sbostic 		from.sin_addr.s_addr = inet_addr(source);
44341125Sbostic 		if (from.sin_addr.s_addr == -1) {
44441125Sbostic 			Printf("traceroute: unknown host %s\n", source);
44541125Sbostic 			exit(1);
44641125Sbostic 		}
44741125Sbostic 		outpacket->ip.ip_src = from.sin_addr;
44841125Sbostic #ifndef IP_HDRINCL
44941125Sbostic 		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
45041125Sbostic 			perror ("traceroute: bind:");
45141125Sbostic 			exit (1);
45241125Sbostic 		}
45341125Sbostic #endif IP_HDRINCL
45441125Sbostic 	}
45541125Sbostic 
45641125Sbostic 	Fprintf(stderr, "traceroute to %s (%s)", hostname,
45741125Sbostic 		inet_ntoa(to->sin_addr));
45841125Sbostic 	if (source)
45941125Sbostic 		Fprintf(stderr, " from %s", source);
46041125Sbostic 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
46141125Sbostic 	(void) fflush(stderr);
46241125Sbostic 
46341125Sbostic 	for (ttl = 1; ttl <= max_ttl; ++ttl) {
46441125Sbostic 		u_long lastaddr = 0;
46541125Sbostic 		int got_there = 0;
46641125Sbostic 		int unreachable = 0;
46741125Sbostic 
46841125Sbostic 		Printf("%2d ", ttl);
46941125Sbostic 		for (probe = 0; probe < nprobes; ++probe) {
47041125Sbostic 			int cc;
47153667Sbostic 			struct timeval t1, t2;
47253667Sbostic 			struct timezone tz;
47341125Sbostic 			struct ip *ip;
47441125Sbostic 
47553667Sbostic 			(void) gettimeofday(&t1, &tz);
47641125Sbostic 			send_probe(++seq, ttl);
47741125Sbostic 			while (cc = wait_for_reply(s, &from)) {
47853667Sbostic 				(void) gettimeofday(&t2, &tz);
47941125Sbostic 				if ((i = packet_ok(packet, cc, &from, seq))) {
48041125Sbostic 					if (from.sin_addr.s_addr != lastaddr) {
48141125Sbostic 						print(packet, cc, &from);
48241125Sbostic 						lastaddr = from.sin_addr.s_addr;
48341125Sbostic 					}
48453667Sbostic 					Printf("  %g ms", deltaT(&t1, &t2));
48541125Sbostic 					switch(i - 1) {
48641125Sbostic 					case ICMP_UNREACH_PORT:
48741125Sbostic #ifndef ARCHAIC
48841125Sbostic 						ip = (struct ip *)packet;
48941125Sbostic 						if (ip->ip_ttl <= 1)
49041125Sbostic 							Printf(" !");
49141125Sbostic #endif ARCHAIC
49241125Sbostic 						++got_there;
49341125Sbostic 						break;
49441125Sbostic 					case ICMP_UNREACH_NET:
49541125Sbostic 						++unreachable;
49641125Sbostic 						Printf(" !N");
49741125Sbostic 						break;
49841125Sbostic 					case ICMP_UNREACH_HOST:
49941125Sbostic 						++unreachable;
50041125Sbostic 						Printf(" !H");
50141125Sbostic 						break;
50241125Sbostic 					case ICMP_UNREACH_PROTOCOL:
50341125Sbostic 						++got_there;
50441125Sbostic 						Printf(" !P");
50541125Sbostic 						break;
50641125Sbostic 					case ICMP_UNREACH_NEEDFRAG:
50741125Sbostic 						++unreachable;
50841125Sbostic 						Printf(" !F");
50941125Sbostic 						break;
51041125Sbostic 					case ICMP_UNREACH_SRCFAIL:
51141125Sbostic 						++unreachable;
51241125Sbostic 						Printf(" !S");
51341125Sbostic 						break;
51441125Sbostic 					}
51541125Sbostic 					break;
51641125Sbostic 				}
51741125Sbostic 			}
51841125Sbostic 			if (cc == 0)
51941125Sbostic 				Printf(" *");
52041125Sbostic 			(void) fflush(stdout);
52141125Sbostic 		}
52241125Sbostic 		putchar('\n');
52341125Sbostic 		if (got_there || unreachable >= nprobes-1)
52441125Sbostic 			exit(0);
52541125Sbostic 	}
52641125Sbostic }
52741125Sbostic 
52853667Sbostic int
wait_for_reply(sock,from)52941125Sbostic wait_for_reply(sock, from)
53041125Sbostic 	int sock;
53141125Sbostic 	struct sockaddr_in *from;
53241125Sbostic {
53341125Sbostic 	fd_set fds;
53441125Sbostic 	struct timeval wait;
53541125Sbostic 	int cc = 0;
53641125Sbostic 	int fromlen = sizeof (*from);
53741125Sbostic 
53841125Sbostic 	FD_ZERO(&fds);
53941125Sbostic 	FD_SET(sock, &fds);
54041125Sbostic 	wait.tv_sec = waittime; wait.tv_usec = 0;
54141125Sbostic 
54241125Sbostic 	if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
54341125Sbostic 		cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
54441125Sbostic 			    (struct sockaddr *)from, &fromlen);
54541125Sbostic 
54641125Sbostic 	return(cc);
54741125Sbostic }
54841125Sbostic 
54941125Sbostic 
55053667Sbostic void
send_probe(seq,ttl)55141125Sbostic send_probe(seq, ttl)
55253667Sbostic 	int seq, ttl;
55341125Sbostic {
55441125Sbostic 	struct opacket *op = outpacket;
55541125Sbostic 	struct ip *ip = &op->ip;
55641125Sbostic 	struct udphdr *up = &op->udp;
55741125Sbostic 	int i;
55841125Sbostic 
55941125Sbostic 	ip->ip_off = 0;
56059018Sandrew 	ip->ip_hl = sizeof(*ip) >> 2;
56141125Sbostic 	ip->ip_p = IPPROTO_UDP;
56241125Sbostic 	ip->ip_len = datalen;
56341125Sbostic 	ip->ip_ttl = ttl;
56459258Ssklower 	ip->ip_v = IPVERSION;
56559258Ssklower 	ip->ip_id = htons(ident+seq);
56641125Sbostic 
56741125Sbostic 	up->uh_sport = htons(ident);
56841125Sbostic 	up->uh_dport = htons(port+seq);
56941125Sbostic 	up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
57041125Sbostic 	up->uh_sum = 0;
57141125Sbostic 
57241125Sbostic 	op->seq = seq;
57341125Sbostic 	op->ttl = ttl;
57441125Sbostic 	(void) gettimeofday(&op->tv, &tz);
57541125Sbostic 
57641125Sbostic 	i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
57741125Sbostic 		   sizeof(struct sockaddr));
57841125Sbostic 	if (i < 0 || i != datalen)  {
57941125Sbostic 		if (i<0)
58041125Sbostic 			perror("sendto");
58141125Sbostic 		Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
58241125Sbostic 			datalen, i);
58341125Sbostic 		(void) fflush(stdout);
58441125Sbostic 	}
58541125Sbostic }
58641125Sbostic 
58741125Sbostic 
58853667Sbostic double
deltaT(t1p,t2p)58953667Sbostic deltaT(t1p, t2p)
59053667Sbostic 	struct timeval *t1p, *t2p;
59141125Sbostic {
59253667Sbostic 	register double dt;
59341125Sbostic 
59453667Sbostic 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
59553667Sbostic 	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
59653667Sbostic 	return (dt);
59741125Sbostic }
59841125Sbostic 
59941125Sbostic 
60041125Sbostic /*
60141125Sbostic  * Convert an ICMP "type" field to a printable string.
60241125Sbostic  */
60341125Sbostic char *
pr_type(t)60441125Sbostic pr_type(t)
60541125Sbostic 	u_char t;
60641125Sbostic {
60741125Sbostic 	static char *ttab[] = {
60841125Sbostic 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
60941125Sbostic 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
61041125Sbostic 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
61141125Sbostic 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
61241125Sbostic 	"Info Reply"
61341125Sbostic 	};
61441125Sbostic 
61541125Sbostic 	if(t > 16)
61641125Sbostic 		return("OUT-OF-RANGE");
61741125Sbostic 
61841125Sbostic 	return(ttab[t]);
61941125Sbostic }
62041125Sbostic 
62141125Sbostic 
62253667Sbostic int
packet_ok(buf,cc,from,seq)62341125Sbostic packet_ok(buf, cc, from, seq)
62441125Sbostic 	u_char *buf;
62541125Sbostic 	int cc;
62641125Sbostic 	struct sockaddr_in *from;
62741125Sbostic 	int seq;
62841125Sbostic {
62941125Sbostic 	register struct icmp *icp;
63041125Sbostic 	u_char type, code;
63141125Sbostic 	int hlen;
63241125Sbostic #ifndef ARCHAIC
63341125Sbostic 	struct ip *ip;
63441125Sbostic 
63541125Sbostic 	ip = (struct ip *) buf;
63641125Sbostic 	hlen = ip->ip_hl << 2;
63741125Sbostic 	if (cc < hlen + ICMP_MINLEN) {
63841125Sbostic 		if (verbose)
63941125Sbostic 			Printf("packet too short (%d bytes) from %s\n", cc,
64041125Sbostic 				inet_ntoa(from->sin_addr));
64141125Sbostic 		return (0);
64241125Sbostic 	}
64341125Sbostic 	cc -= hlen;
64441125Sbostic 	icp = (struct icmp *)(buf + hlen);
64541125Sbostic #else
64641125Sbostic 	icp = (struct icmp *)buf;
64741125Sbostic #endif ARCHAIC
64841125Sbostic 	type = icp->icmp_type; code = icp->icmp_code;
64941125Sbostic 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
65041125Sbostic 	    type == ICMP_UNREACH) {
65141125Sbostic 		struct ip *hip;
65241125Sbostic 		struct udphdr *up;
65341125Sbostic 
65441125Sbostic 		hip = &icp->icmp_ip;
65541125Sbostic 		hlen = hip->ip_hl << 2;
65641125Sbostic 		up = (struct udphdr *)((u_char *)hip + hlen);
65741125Sbostic 		if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
65841125Sbostic 		    up->uh_sport == htons(ident) &&
65941125Sbostic 		    up->uh_dport == htons(port+seq))
66041125Sbostic 			return (type == ICMP_TIMXCEED? -1 : code+1);
66141125Sbostic 	}
66241125Sbostic #ifndef ARCHAIC
66341125Sbostic 	if (verbose) {
66441125Sbostic 		int i;
66541125Sbostic 		u_long *lp = (u_long *)&icp->icmp_ip;
66641125Sbostic 
66741125Sbostic 		Printf("\n%d bytes from %s to %s", cc,
66841125Sbostic 			inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
66941125Sbostic 		Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
67041125Sbostic 		       icp->icmp_code);
67141125Sbostic 		for (i = 4; i < cc ; i += sizeof(long))
67241125Sbostic 			Printf("%2d: x%8.8lx\n", i, *lp++);
67341125Sbostic 	}
67441125Sbostic #endif ARCHAIC
67541125Sbostic 	return(0);
67641125Sbostic }
67741125Sbostic 
67841125Sbostic 
67953667Sbostic void
print(buf,cc,from)68041125Sbostic print(buf, cc, from)
68141125Sbostic 	u_char *buf;
68241125Sbostic 	int cc;
68341125Sbostic 	struct sockaddr_in *from;
68441125Sbostic {
68541125Sbostic 	struct ip *ip;
68641125Sbostic 	int hlen;
68741125Sbostic 
68841125Sbostic 	ip = (struct ip *) buf;
68941125Sbostic 	hlen = ip->ip_hl << 2;
69041125Sbostic 	cc -= hlen;
69141125Sbostic 
69241125Sbostic 	if (nflag)
69341125Sbostic 		Printf(" %s", inet_ntoa(from->sin_addr));
69441125Sbostic 	else
69541125Sbostic 		Printf(" %s (%s)", inetname(from->sin_addr),
69641125Sbostic 		       inet_ntoa(from->sin_addr));
69741125Sbostic 
69841125Sbostic 	if (verbose)
69941125Sbostic 		Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
70041125Sbostic }
70141125Sbostic 
70241125Sbostic 
70341125Sbostic #ifdef notyet
70441125Sbostic /*
70541125Sbostic  * Checksum routine for Internet Protocol family headers (C Version)
70641125Sbostic  */
70753667Sbostic u_short
in_cksum(addr,len)70841125Sbostic in_cksum(addr, len)
70953667Sbostic 	u_short *addr;
71053667Sbostic 	int len;
71141125Sbostic {
71241125Sbostic 	register int nleft = len;
71341125Sbostic 	register u_short *w = addr;
71441125Sbostic 	register u_short answer;
71541125Sbostic 	register int sum = 0;
71641125Sbostic 
71741125Sbostic 	/*
71841125Sbostic 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
71941125Sbostic 	 *  we add sequential 16 bit words to it, and at the end, fold
72041125Sbostic 	 *  back all the carry bits from the top 16 bits into the lower
72141125Sbostic 	 *  16 bits.
72241125Sbostic 	 */
72341125Sbostic 	while (nleft > 1)  {
72441125Sbostic 		sum += *w++;
72541125Sbostic 		nleft -= 2;
72641125Sbostic 	}
72741125Sbostic 
72841125Sbostic 	/* mop up an odd byte, if necessary */
72941125Sbostic 	if (nleft == 1)
73041125Sbostic 		sum += *(u_char *)w;
73141125Sbostic 
73241125Sbostic 	/*
73341125Sbostic 	 * add back carry outs from top 16 bits to low 16 bits
73441125Sbostic 	 */
73541125Sbostic 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
73641125Sbostic 	sum += (sum >> 16);			/* add carry */
73741125Sbostic 	answer = ~sum;				/* truncate to 16 bits */
73841125Sbostic 	return (answer);
73941125Sbostic }
74041125Sbostic #endif notyet
74141125Sbostic 
74241125Sbostic /*
74341125Sbostic  * Subtract 2 timeval structs:  out = out - in.
74441125Sbostic  * Out is assumed to be >= in.
74541125Sbostic  */
74653667Sbostic void
tvsub(out,in)74741125Sbostic tvsub(out, in)
74853667Sbostic 	register struct timeval *out, *in;
74941125Sbostic {
75041125Sbostic 	if ((out->tv_usec -= in->tv_usec) < 0)   {
75141125Sbostic 		out->tv_sec--;
75241125Sbostic 		out->tv_usec += 1000000;
75341125Sbostic 	}
75441125Sbostic 	out->tv_sec -= in->tv_sec;
75541125Sbostic }
75641125Sbostic 
75741125Sbostic 
75841125Sbostic /*
75941125Sbostic  * Construct an Internet address representation.
76053667Sbostic  * If the nflag has been supplied, give
76141125Sbostic  * numeric value, otherwise try for symbolic name.
76241125Sbostic  */
76341125Sbostic char *
inetname(in)76441125Sbostic inetname(in)
76541125Sbostic 	struct in_addr in;
76641125Sbostic {
76741125Sbostic 	register char *cp;
76841125Sbostic 	static char line[50];
76941125Sbostic 	struct hostent *hp;
77041125Sbostic 	static char domain[MAXHOSTNAMELEN + 1];
77141125Sbostic 	static int first = 1;
77241125Sbostic 
77341125Sbostic 	if (first && !nflag) {
77441125Sbostic 		first = 0;
77541125Sbostic 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
77641125Sbostic 		    (cp = index(domain, '.')))
77741125Sbostic 			(void) strcpy(domain, cp + 1);
77841125Sbostic 		else
77941125Sbostic 			domain[0] = 0;
78041125Sbostic 	}
78141125Sbostic 	cp = 0;
78241125Sbostic 	if (!nflag && in.s_addr != INADDR_ANY) {
78341125Sbostic 		hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
78441125Sbostic 		if (hp) {
78541125Sbostic 			if ((cp = index(hp->h_name, '.')) &&
78641125Sbostic 			    !strcmp(cp + 1, domain))
78741125Sbostic 				*cp = 0;
78841125Sbostic 			cp = hp->h_name;
78941125Sbostic 		}
79041125Sbostic 	}
79141125Sbostic 	if (cp)
79241125Sbostic 		(void) strcpy(line, cp);
79341125Sbostic 	else {
79441125Sbostic 		in.s_addr = ntohl(in.s_addr);
79541125Sbostic #define C(x)	((x) & 0xff)
79641125Sbostic 		Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
79741125Sbostic 			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
79841125Sbostic 	}
79941125Sbostic 	return (line);
80041125Sbostic }
80141128Sbostic 
80253667Sbostic void
usage()80341128Sbostic usage()
80441128Sbostic {
80553667Sbostic 	(void)fprintf(stderr,
80641128Sbostic "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
80741128Sbostic [-s src_addr] [-t tos] [-w wait] host [data size]\n");
80841128Sbostic 	exit(1);
80941128Sbostic }
810