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.4 (Berkeley) 05/15/90";
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 #include <netdb.h>
204 
205 #include <stdio.h>
206 #include <errno.h>
207 #include <string.h>
208 
209 #define	MAXPACKET	65535	/* max ip packet size */
210 #ifndef MAXHOSTNAMELEN
211 #define MAXHOSTNAMELEN	64
212 #endif
213 
214 #ifndef FD_SET
215 #define NFDBITS         (8*sizeof(fd_set))
216 #define FD_SETSIZE      NFDBITS
217 #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
218 #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
219 #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
220 #define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
221 #endif
222 
223 #define Fprintf (void)fprintf
224 #define Sprintf (void)sprintf
225 #define Printf (void)printf
226 extern	int errno;
227 extern  char *malloc();
228 extern  char *inet_ntoa();
229 extern  u_long inet_addr();
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 char *inetname();
245 
246 int s;				/* receive (icmp) socket file descriptor */
247 int sndsock;			/* send (udp) socket file descriptor */
248 struct timezone tz;		/* leftover */
249 
250 struct sockaddr whereto;	/* Who to try to reach */
251 int datalen;			/* How much data */
252 
253 char *source = 0;
254 char *hostname;
255 
256 int nprobes = 3;
257 int max_ttl = 30;
258 u_short ident;
259 u_short port = 32768+666;	/* start udp dest port # for probe packets */
260 int options;			/* socket options */
261 int verbose;
262 int waittime = 5;		/* time to wait for response (in seconds) */
263 int nflag;			/* print addresses numerically */
264 
265 main(argc, argv)
266 	char *argv[];
267 {
268 	extern char *optarg;
269 	extern int optind;
270 	struct hostent *hp;
271 	struct protoent *pe;
272 	struct sockaddr_in from, *to;
273 	int ch, i, on, probe, seq, tos, ttl;
274 
275 	on = 1;
276 	seq = tos = 0;
277 	to = (struct sockaddr_in *)&whereto;
278 	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
279 		switch(ch) {
280 		case 'd':
281 			options |= SO_DEBUG;
282 			break;
283 		case 'm':
284 			max_ttl = atoi(optarg);
285 			if (max_ttl <= 1) {
286 				Fprintf(stderr,
287 				    "traceroute: max ttl must be >1.\n");
288 				exit(1);
289 			}
290 			break;
291 		case 'n':
292 			nflag++;
293 			break;
294 		case 'p':
295 			port = atoi(optarg);
296 			if (port < 1) {
297 				Fprintf(stderr,
298 				    "traceroute: port must be >0.\n");
299 				exit(1);
300 			}
301 			break;
302 		case 'q':
303 			nprobes = atoi(optarg);
304 			if (nprobes < 1) {
305 				Fprintf(stderr,
306 				    "traceroute: nprobes must be >0.\n");
307 				exit(1);
308 			}
309 			break;
310 		case 'r':
311 			options |= SO_DONTROUTE;
312 			break;
313 		case 's':
314 			/*
315 			 * set the ip source address of the outbound
316 			 * probe (e.g., on a multi-homed host).
317 			 */
318 			source = optarg;
319 			break;
320 		case 't':
321 			tos = atoi(optarg);
322 			if (tos < 0 || tos > 255) {
323 				Fprintf(stderr,
324 				    "traceroute: tos must be 0 to 255.\n");
325 				exit(1);
326 			}
327 			break;
328 		case 'v':
329 			verbose++;
330 			break;
331 		case 'w':
332 			waittime = atoi(optarg);
333 			if (waittime <= 1) {
334 				Fprintf(stderr,
335 				    "traceroute: wait must be >1 sec.\n");
336 				exit(1);
337 			}
338 			break;
339 		default:
340 			usage();
341 		}
342 	argc -= optind;
343 	argv += optind;
344 
345 	if (argc < 1)
346 		usage();
347 
348 	setlinebuf (stdout);
349 
350 	(void) bzero((char *)&whereto, sizeof(struct sockaddr));
351 	to->sin_family = AF_INET;
352 	to->sin_addr.s_addr = inet_addr(*argv);
353 	if (to->sin_addr.s_addr != -1)
354 		hostname = *argv;
355 	else {
356 		hp = gethostbyname(*argv);
357 		if (hp) {
358 			to->sin_family = hp->h_addrtype;
359 			bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
360 			hostname = hp->h_name;
361 		} else {
362 			(void)fprintf(stderr,
363 			    "traceroute: unknown host %s\n", *argv);
364 			exit(1);
365 		}
366 	}
367 	if (*++argv)
368 		datalen = atoi(*argv);
369 	if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
370 		Fprintf(stderr,
371 		    "traceroute: packet size must be 0 <= s < %ld.\n",
372 		    MAXPACKET - sizeof(struct opacket));
373 		exit(1);
374 	}
375 	datalen += sizeof(struct opacket);
376 	outpacket = (struct opacket *)malloc((unsigned)datalen);
377 	if (! outpacket) {
378 		perror("traceroute: malloc");
379 		exit(1);
380 	}
381 	(void) bzero((char *)outpacket, datalen);
382 	outpacket->ip.ip_dst = to->sin_addr;
383 	outpacket->ip.ip_tos = tos;
384 
385 	ident = (getpid() & 0xffff) | 0x8000;
386 
387 	if ((pe = getprotobyname("icmp")) == NULL) {
388 		Fprintf(stderr, "icmp: unknown protocol\n");
389 		exit(10);
390 	}
391 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
392 		perror("traceroute: icmp socket");
393 		exit(5);
394 	}
395 	if (options & SO_DEBUG)
396 		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
397 				  (char *)&on, sizeof(on));
398 	if (options & SO_DONTROUTE)
399 		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
400 				  (char *)&on, sizeof(on));
401 
402 	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
403 		perror("traceroute: raw socket");
404 		exit(5);
405 	}
406 #ifdef SO_SNDBUF
407 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
408 		       sizeof(datalen)) < 0) {
409 		perror("traceroute: SO_SNDBUF");
410 		exit(6);
411 	}
412 #endif SO_SNDBUF
413 #ifdef IP_HDRINCL
414 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
415 		       sizeof(on)) < 0) {
416 		perror("traceroute: IP_HDRINCL");
417 		exit(6);
418 	}
419 #endif IP_HDRINCL
420 	if (options & SO_DEBUG)
421 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
422 				  (char *)&on, sizeof(on));
423 	if (options & SO_DONTROUTE)
424 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
425 				  (char *)&on, sizeof(on));
426 
427 	if (source) {
428 		(void) bzero((char *)&from, sizeof(struct sockaddr));
429 		from.sin_family = AF_INET;
430 		from.sin_addr.s_addr = inet_addr(source);
431 		if (from.sin_addr.s_addr == -1) {
432 			Printf("traceroute: unknown host %s\n", source);
433 			exit(1);
434 		}
435 		outpacket->ip.ip_src = from.sin_addr;
436 #ifndef IP_HDRINCL
437 		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
438 			perror ("traceroute: bind:");
439 			exit (1);
440 		}
441 #endif IP_HDRINCL
442 	}
443 
444 	Fprintf(stderr, "traceroute to %s (%s)", hostname,
445 		inet_ntoa(to->sin_addr));
446 	if (source)
447 		Fprintf(stderr, " from %s", source);
448 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
449 	(void) fflush(stderr);
450 
451 	for (ttl = 1; ttl <= max_ttl; ++ttl) {
452 		u_long lastaddr = 0;
453 		int got_there = 0;
454 		int unreachable = 0;
455 
456 		Printf("%2d ", ttl);
457 		for (probe = 0; probe < nprobes; ++probe) {
458 			int cc;
459 			struct timeval tv;
460 			struct ip *ip;
461 
462 			(void) gettimeofday(&tv, &tz);
463 			send_probe(++seq, ttl);
464 			while (cc = wait_for_reply(s, &from)) {
465 				if ((i = packet_ok(packet, cc, &from, seq))) {
466 					int dt = deltaT(&tv);
467 					if (from.sin_addr.s_addr != lastaddr) {
468 						print(packet, cc, &from);
469 						lastaddr = from.sin_addr.s_addr;
470 					}
471 					Printf("  %d ms", dt);
472 					switch(i - 1) {
473 					case ICMP_UNREACH_PORT:
474 #ifndef ARCHAIC
475 						ip = (struct ip *)packet;
476 						if (ip->ip_ttl <= 1)
477 							Printf(" !");
478 #endif ARCHAIC
479 						++got_there;
480 						break;
481 					case ICMP_UNREACH_NET:
482 						++unreachable;
483 						Printf(" !N");
484 						break;
485 					case ICMP_UNREACH_HOST:
486 						++unreachable;
487 						Printf(" !H");
488 						break;
489 					case ICMP_UNREACH_PROTOCOL:
490 						++got_there;
491 						Printf(" !P");
492 						break;
493 					case ICMP_UNREACH_NEEDFRAG:
494 						++unreachable;
495 						Printf(" !F");
496 						break;
497 					case ICMP_UNREACH_SRCFAIL:
498 						++unreachable;
499 						Printf(" !S");
500 						break;
501 					}
502 					break;
503 				}
504 			}
505 			if (cc == 0)
506 				Printf(" *");
507 			(void) fflush(stdout);
508 		}
509 		putchar('\n');
510 		if (got_there || unreachable >= nprobes-1)
511 			exit(0);
512 	}
513 }
514 
515 wait_for_reply(sock, from)
516 	int sock;
517 	struct sockaddr_in *from;
518 {
519 	fd_set fds;
520 	struct timeval wait;
521 	int cc = 0;
522 	int fromlen = sizeof (*from);
523 
524 	FD_ZERO(&fds);
525 	FD_SET(sock, &fds);
526 	wait.tv_sec = waittime; wait.tv_usec = 0;
527 
528 	if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
529 		cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
530 			    (struct sockaddr *)from, &fromlen);
531 
532 	return(cc);
533 }
534 
535 
536 send_probe(seq, ttl)
537 {
538 	struct opacket *op = outpacket;
539 	struct ip *ip = &op->ip;
540 	struct udphdr *up = &op->udp;
541 	int i;
542 
543 	ip->ip_off = 0;
544 	ip->ip_p = IPPROTO_UDP;
545 	ip->ip_len = datalen;
546 	ip->ip_ttl = ttl;
547 
548 	up->uh_sport = htons(ident);
549 	up->uh_dport = htons(port+seq);
550 	up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
551 	up->uh_sum = 0;
552 
553 	op->seq = seq;
554 	op->ttl = ttl;
555 	(void) gettimeofday(&op->tv, &tz);
556 
557 	i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
558 		   sizeof(struct sockaddr));
559 	if (i < 0 || i != datalen)  {
560 		if (i<0)
561 			perror("sendto");
562 		Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
563 			datalen, i);
564 		(void) fflush(stdout);
565 	}
566 }
567 
568 
569 deltaT(tp)
570 	struct timeval *tp;
571 {
572 	struct timeval tv;
573 
574 	(void) gettimeofday(&tv, &tz);
575 	tvsub(&tv, tp);
576 	return (tv.tv_sec*1000 + (tv.tv_usec + 500)/1000);
577 }
578 
579 
580 /*
581  * Convert an ICMP "type" field to a printable string.
582  */
583 char *
584 pr_type(t)
585 	u_char t;
586 {
587 	static char *ttab[] = {
588 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
589 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
590 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
591 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
592 	"Info Reply"
593 	};
594 
595 	if(t > 16)
596 		return("OUT-OF-RANGE");
597 
598 	return(ttab[t]);
599 }
600 
601 
602 packet_ok(buf, cc, from, seq)
603 	u_char *buf;
604 	int cc;
605 	struct sockaddr_in *from;
606 	int seq;
607 {
608 	register struct icmp *icp;
609 	u_char type, code;
610 	int hlen;
611 #ifndef ARCHAIC
612 	struct ip *ip;
613 
614 	ip = (struct ip *) buf;
615 	hlen = ip->ip_hl << 2;
616 	if (cc < hlen + ICMP_MINLEN) {
617 		if (verbose)
618 			Printf("packet too short (%d bytes) from %s\n", cc,
619 				inet_ntoa(from->sin_addr));
620 		return (0);
621 	}
622 	cc -= hlen;
623 	icp = (struct icmp *)(buf + hlen);
624 #else
625 	icp = (struct icmp *)buf;
626 #endif ARCHAIC
627 	type = icp->icmp_type; code = icp->icmp_code;
628 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
629 	    type == ICMP_UNREACH) {
630 		struct ip *hip;
631 		struct udphdr *up;
632 
633 		hip = &icp->icmp_ip;
634 		hlen = hip->ip_hl << 2;
635 		up = (struct udphdr *)((u_char *)hip + hlen);
636 		if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
637 		    up->uh_sport == htons(ident) &&
638 		    up->uh_dport == htons(port+seq))
639 			return (type == ICMP_TIMXCEED? -1 : code+1);
640 	}
641 #ifndef ARCHAIC
642 	if (verbose) {
643 		int i;
644 		u_long *lp = (u_long *)&icp->icmp_ip;
645 
646 		Printf("\n%d bytes from %s to %s", cc,
647 			inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
648 		Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
649 		       icp->icmp_code);
650 		for (i = 4; i < cc ; i += sizeof(long))
651 			Printf("%2d: x%8.8lx\n", i, *lp++);
652 	}
653 #endif ARCHAIC
654 	return(0);
655 }
656 
657 
658 print(buf, cc, from)
659 	u_char *buf;
660 	int cc;
661 	struct sockaddr_in *from;
662 {
663 	struct ip *ip;
664 	int hlen;
665 
666 	ip = (struct ip *) buf;
667 	hlen = ip->ip_hl << 2;
668 	cc -= hlen;
669 
670 	if (nflag)
671 		Printf(" %s", inet_ntoa(from->sin_addr));
672 	else
673 		Printf(" %s (%s)", inetname(from->sin_addr),
674 		       inet_ntoa(from->sin_addr));
675 
676 	if (verbose)
677 		Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
678 }
679 
680 
681 #ifdef notyet
682 /*
683  * Checksum routine for Internet Protocol family headers (C Version)
684  */
685 in_cksum(addr, len)
686 u_short *addr;
687 int len;
688 {
689 	register int nleft = len;
690 	register u_short *w = addr;
691 	register u_short answer;
692 	register int sum = 0;
693 
694 	/*
695 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
696 	 *  we add sequential 16 bit words to it, and at the end, fold
697 	 *  back all the carry bits from the top 16 bits into the lower
698 	 *  16 bits.
699 	 */
700 	while (nleft > 1)  {
701 		sum += *w++;
702 		nleft -= 2;
703 	}
704 
705 	/* mop up an odd byte, if necessary */
706 	if (nleft == 1)
707 		sum += *(u_char *)w;
708 
709 	/*
710 	 * add back carry outs from top 16 bits to low 16 bits
711 	 */
712 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
713 	sum += (sum >> 16);			/* add carry */
714 	answer = ~sum;				/* truncate to 16 bits */
715 	return (answer);
716 }
717 #endif notyet
718 
719 /*
720  * Subtract 2 timeval structs:  out = out - in.
721  * Out is assumed to be >= in.
722  */
723 tvsub(out, in)
724 register struct timeval *out, *in;
725 {
726 	if ((out->tv_usec -= in->tv_usec) < 0)   {
727 		out->tv_sec--;
728 		out->tv_usec += 1000000;
729 	}
730 	out->tv_sec -= in->tv_sec;
731 }
732 
733 
734 /*
735  * Construct an Internet address representation.
736  * If the nflag has been supplied, give
737  * numeric value, otherwise try for symbolic name.
738  */
739 char *
740 inetname(in)
741 	struct in_addr in;
742 {
743 	register char *cp;
744 	static char line[50];
745 	struct hostent *hp;
746 	static char domain[MAXHOSTNAMELEN + 1];
747 	static int first = 1;
748 
749 	if (first && !nflag) {
750 		first = 0;
751 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
752 		    (cp = index(domain, '.')))
753 			(void) strcpy(domain, cp + 1);
754 		else
755 			domain[0] = 0;
756 	}
757 	cp = 0;
758 	if (!nflag && in.s_addr != INADDR_ANY) {
759 		hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
760 		if (hp) {
761 			if ((cp = index(hp->h_name, '.')) &&
762 			    !strcmp(cp + 1, domain))
763 				*cp = 0;
764 			cp = hp->h_name;
765 		}
766 	}
767 	if (cp)
768 		(void) strcpy(line, cp);
769 	else {
770 		in.s_addr = ntohl(in.s_addr);
771 #define C(x)	((x) & 0xff)
772 		Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
773 			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
774 	}
775 	return (line);
776 }
777 
778 usage()
779 {
780 	(void)fprintf(stderr,
781 "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
782 [-s src_addr] [-t tos] [-w wait] host [data size]\n");
783 	exit(1);
784 }
785