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