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