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