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