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