xref: /haiku/src/bin/network/traceroute/traceroute.c (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Van Jacobson.
7  *
8  * 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 /*
38  * traceroute host  - trace the route ip packets follow going to "host".
39  *
40  * Attempt to trace the route an ip packet would follow to some
41  * internet host.  We find out intermediate hops by launching probe
42  * packets with a small ttl (time to live) then listening for an
43  * icmp "time exceeded" reply from a gateway.  We start our probes
44  * with a ttl of one and increase by one until we get an icmp "port
45  * unreachable" (which means we got to "host") or hit a max (which
46  * defaults to 64 hops & can be changed with the -m flag).  Three
47  * probes (change with -q flag) are sent at each ttl setting and a
48  * line is printed showing the ttl, address of the gateway and
49  * round trip time of each probe.  If the probe answers come from
50  * different gateways, the address of each responding system will
51  * be printed.  If there is no response within a 5 sec. timeout
52  * interval (changed with the -w flag), a "*" is printed for that
53  * probe.
54  *
55  * Probe packets are UDP format.  We don't want the destination
56  * host to process them so the destination port is set to an
57  * unlikely value (if some clod on the destination is using that
58  * value, it can be changed with the -p flag).
59  *
60  * A sample use might be:
61  *
62  *     [yak 71]% traceroute nis.nsf.net.
63  *     traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
64  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
65  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
66  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
67  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
68  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
69  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
70  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
71  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
72  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
73  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
74  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
75  *
76  * Note that lines 2 & 3 are the same.  This is due to a buggy
77  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
78  * packets with a zero ttl.
79  *
80  * A more interesting example is:
81  *
82  *     [yak 72]% traceroute allspice.lcs.mit.edu.
83  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
84  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
85  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
86  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
87  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
88  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
89  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
90  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
91  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
92  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
93  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
94  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
95  *     12  * * *
96  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
97  *     14  * * *
98  *     15  * * *
99  *     16  * * *
100  *     17  * * *
101  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
102  *
103  * (I start to see why I'm having so much trouble with mail to
104  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
105  * either don't send ICMP "time exceeded" messages or send them
106  * with a ttl too small to reach us.  14 - 17 are running the
107  * MIT C Gateway code that doesn't send "time exceeded"s.  God
108  * only knows what's going on with 12.
109  *
110  * The silent gateway 12 in the above may be the result of a bug in
111  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
112  * sends an unreachable message using whatever ttl remains in the
113  * original datagram.  Since, for gateways, the remaining ttl is
114  * zero, the icmp "time exceeded" is guaranteed to not make it back
115  * to us.  The behavior of this bug is slightly more interesting
116  * when it appears on the destination system:
117  *
118  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
119  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
120  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
121  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
122  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
123  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
124  *      7  * * *
125  *      8  * * *
126  *      9  * * *
127  *     10  * * *
128  *     11  * * *
129  *     12  * * *
130  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
131  *
132  * Notice that there are 12 "gateways" (13 is the final
133  * destination) and exactly the last half of them are "missing".
134  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
135  * is using the ttl from our arriving datagram as the ttl in its
136  * icmp reply.  So, the reply will time out on the return path
137  * (with no notice sent to anyone since icmp's aren't sent for
138  * icmp's) until we probe with a ttl that's at least twice the path
139  * length.  I.e., rip is really only 7 hops away.  A reply that
140  * returns with a ttl of 1 is a clue this problem exists.
141  * Traceroute prints a "!" after the time if the ttl is <= 1.
142  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
143  * non-standard (HPUX) software, expect to see this problem
144  * frequently and/or take care picking the target host of your
145  * probes.
146  *
147  * Other possible annotations after the time are !H, !N, !P (got a host,
148  * network or protocol unreachable, respectively), !S or !F (source
149  * route failed or fragmentation needed -- neither of these should
150  * ever occur and the associated gateway is busted if you see one).  If
151  * almost all the probes result in some kind of unreachable, traceroute
152  * will give up and exit.
153  *
154  * Notes
155  * -----
156  * This program must be run by root or be setuid.  (I suggest that
157  * you *don't* make it setuid -- casual use could result in a lot
158  * of unnecessary traffic on our poor, congested nets.)
159  *
160  * This program requires a kernel mod that does not appear in any
161  * system available from Berkeley:  A raw ip socket using proto
162  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
163  * opposed to data to be wrapped in a ip datagram).  See the README
164  * file that came with the source to this program for a description
165  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
166  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
167  * MODIFIED TO RUN THIS PROGRAM.
168  *
169  * The udp port usage may appear bizarre (well, ok, it is bizarre).
170  * The problem is that an icmp message only contains 8 bytes of
171  * data from the original datagram.  8 bytes is the size of a udp
172  * header so, if we want to associate replies with the original
173  * datagram, the necessary information must be encoded into the
174  * udp header (the ip id could be used but there's no way to
175  * interlock with the kernel's assignment of ip id's and, anyway,
176  * it would have taken a lot more kernel hacking to allow this
177  * code to set the ip id).  So, to allow two or more users to
178  * use traceroute simultaneously, we use this task's pid as the
179  * source port (the high bit is set to move the port number out
180  * of the "likely" range).  To keep track of which probe is being
181  * replied to (so times and/or hop counts don't get confused by a
182  * reply that was delayed in transit), we increment the destination
183  * port number before each probe.
184  *
185  * Don't use this as a coding example.  I was trying to find a
186  * routing problem and this code sort-of popped out after 48 hours
187  * without sleep.  I was amazed it ever compiled, much less ran.
188  *
189  * I stole the idea for this program from Steve Deering.  Since
190  * the first release, I've learned that had I attended the right
191  * IETF working group meetings, I also could have stolen it from Guy
192  * Almes or Matt Mathis.  I don't know (or care) who came up with
193  * the idea first.  I envy the originators' perspicacity and I'm
194  * glad they didn't keep the idea a secret.
195  *
196  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
197  * enhancements to the original distribution.
198  *
199  * I've hacked up a round-trip-route version of this that works by
200  * sending a loose-source-routed udp datagram through the destination
201  * back to yourself.  Unfortunately, SO many gateways botch source
202  * routing, the thing is almost worthless.  Maybe one day...
203  *
204  *  -- Van Jacobson (van@helios.ee.lbl.gov)
205  *     Tue Dec 20 03:50:13 PST 1988
206  */
207 
208 #include <sys/param.h>
209 #include <sys/time.h>
210 #include <sys/socket.h>
211 #include <sys/ioctl.h>
212 
213 #include <netinet/in.h>
214 #include <netinet/ip.h>
215 #include <netinet/ip_icmp.h>
216 #include <netinet/ip_var.h>
217 #include <netinet/udp.h>
218 #include <sys/select.h>
219 
220 #include <arpa/inet.h>
221 
222 #include <ctype.h>
223 #include <errno.h>
224 #include <netdb.h>
225 #include <stdio.h>
226 #include <stdlib.h>
227 #include <string.h>
228 #include <unistd.h>
229 
230 #define Fprintf (void)fprintf
231 #define Printf (void)printf
232 
233 #define	MAX_LSRR	((MAX_IPOPTLEN - 4) / 4)
234 
235 /*
236  * Format of the data in a (udp) probe packet.
237  */
238 struct packetdata {
239 	u_char		seq;		/* sequence number of this packet */
240 	u_char		ttl;		/* ttl packet left with */
241 	uint32_t	sec;		/* time packet left */
242 	uint32_t	usec;
243 };
244 
245 struct in_addr gateway[MAX_LSRR + 1];
246 int lsrrlen = 0;
247 int32_t sec_perturb;
248 int32_t usec_perturb;
249 
250 u_char packet[512], *outpacket;	/* last inbound (icmp) packet */
251 
252 int wait_for_reply (int, struct sockaddr_in *, struct timeval *);
253 void send_probe    (int, int, int, struct sockaddr_in *);
254 int packet_ok      (u_char *, int, struct sockaddr_in *, int, int);
255 void print         (u_char *, int, struct sockaddr_in *);
256 char *inetname     (struct in_addr);
257 u_short compute_in_cksum(uint16_t *, int);
258 void usage         (void);
259 
260 int s;				/* receive (icmp) socket file descriptor */
261 int sndsock;			/* send (udp) socket file descriptor */
262 struct timezone tz;		/* leftover */
263 
264 int datalen;			/* How much data */
265 int headerlen;			/* How long packet's header is */
266 
267 char *source = 0;
268 char *hostname;
269 
270 int nprobes = 3;
271 int max_ttl = IPDEFTTL;
272 int first_ttl = 1;
273 u_short ident;
274 u_short port = 32768+666;	/* start udp dest port # for probe packets */
275 u_char	proto = IPPROTO_UDP;
276 u_char  icmp_type = ICMP_ECHO; /* default ICMP code/type */
277 u_char  icmp_code = 0;
278 int options;			/* socket options */
279 int verbose;
280 int waittime = 5;		/* time to wait for response (in seconds) */
281 int nflag;			/* print addresses numerically */
282 int dump;
283 
284 /* arc4random is defined in stdlib.h on OpenBSD, so we'll just forward
285  * declare the prototype here to stop the compiler moaning.
286  */
287 uint32_t arc4random(void);
288 
289 static void err(int exitval, char *where)
290 {
291 	printf("error: %s: error %d [%s]\n", where, errno, strerror(errno));
292 	exit(exitval);
293 }
294 
295 static void errx(int exitval, char *fmt_string, char *value)
296 {
297 	printf("error: ");
298 	printf(fmt_string, value);
299 	exit(exitval);
300 }
301 
302 
303 int main(int argc, char **argv)
304 {
305 	struct hostent *hp;
306 	struct protoent *pe;
307 	struct sockaddr_in from, to;
308 	int ch, i, lsrr, on, probe, seq, tos, ttl, ttl_flag, incflag = 1;
309 	struct ip *ip;
310 	uint32_t tmprnd;
311 	int sump = 0;
312 
313 	if ((pe = getprotobyname("icmp")) == NULL) {
314 		Fprintf(stderr, "icmp: unknown protocol\n");
315 		exit(10);
316 	}
317 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
318 		err(5, "icmp socket");
319 	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
320 		err(5, "raw socket");
321 
322 	/* revoke privs */
323 //	seteuid(getuid());
324 //	setuid(getuid());
325 
326 	ttl_flag = 0;
327 	lsrr = 0;
328 	on = 1;
329 	seq = tos = 0;
330 	while ((ch = getopt(argc, argv, "SDIdg:f:m:np:q:rs:t:w:vlP:c")) != -1)
331 		switch (ch) {
332 		case 'S':
333 			sump = 1;
334 			break;
335 		case 'f':
336 			first_ttl = atoi(optarg);
337 			if (first_ttl < 1 || first_ttl > max_ttl) {
338 				printf("min ttl must be 1 to %d.", max_ttl);
339 				exit(1);
340 			}
341 			break;
342 		case 'c':
343 			incflag = 0;
344 			break;
345 		case 'd':
346 			options |= SO_DEBUG;
347 			break;
348 		case 'D':
349 			dump = 1;
350 			break;
351 		case 'g':
352 			if (lsrr >= MAX_LSRR) {
353 				printf("too many gateways; max %d", MAX_LSRR);
354 				exit(1);
355 			}
356 			if (inet_aton(optarg, &gateway[lsrr]) == 0) {
357 				hp = gethostbyname(optarg);
358 				if (hp == 0)
359 					errx(1, "unknown host %s", optarg);
360 				memcpy(&gateway[lsrr], hp->h_addr, hp->h_length);
361 			}
362 			if (++lsrr == 1)
363 				lsrrlen = 4;
364 			lsrrlen += 4;
365 			break;
366 		case 'I':
367 			proto = IPPROTO_ICMP;
368 			break;
369 		case 'l':
370 			ttl_flag++;
371 			break;
372 		case 'm':
373 			max_ttl = atoi(optarg);
374 			if (max_ttl < first_ttl || max_ttl > MAXTTL) {
375 				printf("max ttl must be %d to %d.", first_ttl,
376 				    MAXTTL);
377 				exit(1);
378 			}
379 			break;
380 		case 'n':
381 			nflag++;
382 			break;
383 		case 'p':
384 			port = atoi(optarg);
385 			if (port < 1)
386 				err(1, "port must be >0.");
387 			break;
388 		case 'P':
389 			proto = atoi(optarg);
390 			if (proto < 1) {
391 				struct protoent *pent;
392 				pent = getprotobyname(optarg);
393 				if (pent)
394 					proto = pent->p_proto;
395 				else
396 					err(1, "proto must be >=1, or a name.");
397 			}
398 			break;
399 		case 'q':
400 			nprobes = atoi(optarg);
401 			if (nprobes < 1)
402 				err(1, "nprobes must be >0.");
403 			break;
404 		case 'r':
405 			options |= SO_DONTROUTE;
406 			break;
407 		case 's':
408 			/*
409 			 * set the ip source address of the outbound
410 			 * probe (e.g., on a multi-homed host).
411 			 */
412 			source = optarg;
413 			break;
414 		case 't':
415 			tos = atoi(optarg);
416 			if (tos < 0 || tos > 255)
417 				err(1, "tos must be 0 to 255.");
418 			break;
419 		case 'v':
420 			verbose++;
421 			break;
422 		case 'w':
423 			waittime = atoi(optarg);
424 			if (waittime <= 1)
425 				err(1, "wait must be >1 sec.");
426 			break;
427 		default:
428 			usage();
429 		}
430 	argc -= optind;
431 	argv += optind;
432 
433 	if (argc < 1)
434 		usage();
435 
436 	setlinebuf (stdout);
437 
438 	(void) memset(&to, 0, sizeof(struct sockaddr));
439 	to.sin_family = AF_INET;
440 	if (inet_aton(*argv, &to.sin_addr) != 0)
441 		hostname = *argv;
442 	else {
443 		hp = gethostbyname(*argv);
444 		if (hp == 0)
445 			errx(1, "unknown host %s", *argv);
446 		to.sin_family = hp->h_addrtype;
447 		memcpy(&to.sin_addr, hp->h_addr, hp->h_length);
448 		if ((hostname = strdup(hp->h_name)) == NULL)
449 			err(1, "malloc");
450 	}
451 	if (*++argv)
452 		datalen = atoi(*argv);
453 
454 	switch (proto) {
455 	case IPPROTO_UDP:
456 		headerlen = (sizeof(struct ip) + lsrrlen +
457 		    sizeof(struct udphdr) + sizeof(struct packetdata));
458 		break;
459 	case IPPROTO_ICMP:
460 		headerlen = (sizeof(struct ip) + lsrrlen +
461 		    sizeof(struct icmp) + sizeof(struct packetdata));
462 		break;
463 	default:
464 		headerlen = (sizeof(struct ip) + lsrrlen +
465 		    sizeof(struct packetdata));
466 	}
467 
468 	if (datalen < 0 || datalen > IP_MAXPACKET - headerlen) {
469 		printf("packet size must be 0 to %d.",
470 		    IP_MAXPACKET - headerlen);
471 		exit(1);
472 	}
473 
474 	datalen += headerlen;
475 
476 	outpacket = (u_char *)malloc(datalen);
477 	if (outpacket == 0)
478 		err(1, "malloc");
479 	(void) memset(outpacket, 0, datalen);
480 
481 	ip = (struct ip *)outpacket;
482 	if (lsrr != 0) {
483 		u_char *p;
484 		p = (u_char *)(ip + 1);
485 		*p++ = IPOPT_NOP;
486 		*p++ = IPOPT_LSRR;
487 		*p++ = lsrrlen - 1;
488 		*p++ = IPOPT_MINOFF;
489 		gateway[lsrr] = to.sin_addr;
490 		for (i = 1; i <= lsrr; i++) {
491 			*(struct in_addr *)p = gateway[i];
492 			p = (u_char*)((struct in_addr *)p + 1);
493 		}
494 		ip->ip_dst = gateway[0];
495 	} else
496 		ip->ip_dst = to.sin_addr;
497 	ip->ip_off = htons(0);
498 	ip->ip_hl = (sizeof(struct ip) + lsrrlen) >> 2;
499 	ip->ip_p = proto;
500 	ip->ip_v = IPVERSION;
501 	ip->ip_tos = tos;
502 
503 	ident = (getpid() & 0xffff) | 0x8000;
504 	tmprnd = arc4random();
505 	sec_perturb = (tmprnd & 0x80000000) ? -(tmprnd & 0x7ff) :
506 						(tmprnd & 0x7ff);
507 	usec_perturb = arc4random();
508 
509 	if (options & SO_DEBUG)
510 		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
511 				  (char *)&on, sizeof(on));
512 	if (options & SO_DONTROUTE)
513 		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
514 				  (char *)&on, sizeof(on));
515 #ifdef SO_SNDBUF
516 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
517 	    sizeof(datalen)) < 0)
518 		err(6, "SO_SNDBUF");
519 #endif /* SO_SNDBUF */
520 #ifdef IP_HDRINCL
521 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
522 	    sizeof(on)) < 0)
523 		err(6, "IP_HDRINCL");
524 #endif /* IP_HDRINCL */
525 	if (options & SO_DEBUG)
526 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
527 				  (char *)&on, sizeof(on));
528 	if (options & SO_DONTROUTE)
529 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
530 				  (char *)&on, sizeof(on));
531 
532 	if (source) {
533 		(void) memset(&from, 0, sizeof(struct sockaddr));
534 		from.sin_family = AF_INET;
535 		if (inet_aton(source, &from.sin_addr) == 0)
536 			errx(1, "unknown host %s", source);
537 		ip->ip_src = from.sin_addr;
538 		if (getuid() != 0 &&
539 		    (ntohl(from.sin_addr.s_addr) & 0xff000000U) == 0x7f000000U &&
540 		    (ntohl(to.sin_addr.s_addr) & 0xff000000U) != 0x7f000000U)
541 			err(1, "source is on 127/8, destination is not");
542 
543 		if (getuid() &&
544 		    bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
545 			err(1, "bind");
546 	}
547 
548 	Fprintf(stderr, "traceroute to %s (%s)", hostname,
549 		inet_ntoa(to.sin_addr));
550 	if (source)
551 		Fprintf(stderr, " from %s", source);
552 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
553 	(void) fflush(stderr);
554 
555 	if (first_ttl > 1)
556 		Printf("Skipping %d intermediate hops\n", first_ttl - 1);
557 
558 	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
559 		in_addr_t lastaddr = 0;
560 		int got_there = 0;
561 		int unreachable = 0;
562 		int timeout = 0;
563 		uint64_t dt;
564 		int loss;
565 
566 		Printf("%2d ", ttl);
567 		for (probe = 0, loss = 0; probe < nprobes; ++probe) {
568 			int cc;
569 			struct timeval t1, t2;
570 			struct timezone tz;
571 			int code;
572 
573 			(void) gettimeofday(&t1, &tz);
574 			send_probe(++seq, ttl, incflag, &to);
575 			while ((cc = wait_for_reply(s, &from, &t1))) {
576 				(void) gettimeofday(&t2, &tz);
577 				if (t2.tv_sec - t1.tv_sec > waittime) {
578 					cc = 0;
579 					break;
580 				}
581 				i = packet_ok(packet, cc, &from, seq, incflag);
582 				/* Skip short packet */
583 				if (i == 0)
584 					continue;
585 				if (from.sin_addr.s_addr != lastaddr) {
586 					print(packet, cc, &from);
587 					lastaddr = from.sin_addr.s_addr;
588 				}
589 				dt = (uint64_t)(t2.tv_sec - t1.tv_sec) * 1000000
590 					+ (uint64_t)(t2.tv_usec - t1.tv_usec);
591 				Printf("  %u", (u_int)(dt / 1000));
592 				if (dt % 1000)
593 					Printf(".%u", (u_int)(dt % 1000));
594 				Printf(" ms");
595 				ip = (struct ip *)packet;
596 				if (ttl_flag)
597 					Printf(" (%d)", ip->ip_ttl);
598 				if (i == -2) {
599 #ifndef ARCHAIC
600 					ip = (struct ip *)packet;
601 					if (ip->ip_ttl <= 1)
602 						Printf(" !");
603 #endif
604 					++got_there;
605 					break;
606 				}
607 				/* time exceeded in transit */
608 				if (i == -1)
609 					break;
610 				code = i - 1;
611 				switch (code) {
612 				case ICMP_UNREACH_PORT:
613 #ifndef ARCHAIC
614 					ip = (struct ip *)packet;
615 					if (ip->ip_ttl <= 1)
616 						Printf(" !");
617 #endif /* ARCHAIC */
618 					++got_there;
619 					break;
620 				case ICMP_UNREACH_NET:
621 					++unreachable;
622 					Printf(" !N");
623 					break;
624 				case ICMP_UNREACH_HOST:
625 					++unreachable;
626 					Printf(" !H");
627 					break;
628 				case ICMP_UNREACH_PROTOCOL:
629 					++got_there;
630 					Printf(" !P");
631 					break;
632 				case ICMP_UNREACH_NEEDFRAG:
633 					++unreachable;
634 					Printf(" !F");
635 					break;
636 				case ICMP_UNREACH_SRCFAIL:
637 					++unreachable;
638 					Printf(" !S");
639 					break;
640 				case ICMP_UNREACH_FILTER_PROHIB:
641 				case ICMP_UNREACH_NET_PROHIB: /*misuse*/
642 					++unreachable;
643 					Printf(" !A");
644 					break;
645 				case ICMP_UNREACH_HOST_PROHIB:
646 					++unreachable;
647 					Printf(" !C");
648 					break;
649 				case ICMP_UNREACH_NET_UNKNOWN:
650 				case ICMP_UNREACH_HOST_UNKNOWN:
651 					++unreachable;
652 					Printf(" !U");
653 					break;
654 				case ICMP_UNREACH_ISOLATED:
655 					++unreachable;
656 					Printf(" !I");
657 					break;
658 				case ICMP_UNREACH_TOSNET:
659 				case ICMP_UNREACH_TOSHOST:
660 					++unreachable;
661 					Printf(" !T");
662 					break;
663 				default:
664 					++unreachable;
665 					Printf(" !<%d>", i - 1);
666 					break;
667 				}
668 				break;
669 			}
670 			if (cc == 0) {
671 				Printf(" *");
672 				timeout++;
673 				loss++;
674 			}
675 			(void) fflush(stdout);
676 		}
677 		if (sump)
678 			Printf(" (%d%% loss)", (loss * 100) / nprobes);
679 		putchar('\n');
680 		if (got_there || (unreachable && (unreachable + timeout) >= nprobes))
681 			break;
682 	}
683 	exit(0);
684 }
685 
686 int
687 wait_for_reply(sock, from, sent)
688 	int sock;
689 	struct sockaddr_in *from;
690 	struct timeval *sent;
691 {
692 	struct timeval now, wait;
693 	int cc = 0, fdsn;
694 	size_t fromlen = sizeof (*from);
695 	fd_set *fdsp;
696 
697 	fdsn = _howmany(sock+1, NFDBITS) * sizeof(fd_mask);
698 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
699 		err(1, "malloc");
700 	memset(fdsp, 0, fdsn);
701 	FD_SET(sock, fdsp);
702 	gettimeofday(&now, NULL);
703 	wait.tv_sec = (sent->tv_sec + waittime) - now.tv_sec;
704 	wait.tv_usec =  sent->tv_usec - now.tv_usec;
705 	if (wait.tv_usec < 0) {
706 		wait.tv_usec += 1000000;
707 		wait.tv_sec--;
708 	}
709 	if (wait.tv_sec < 0)
710 		wait.tv_sec = wait.tv_usec = 0;
711 
712 	if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
713 		cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
714 			    (struct sockaddr *)from, &fromlen);
715 
716 	free(fdsp);
717 	return (cc);
718 }
719 
720 static void
721 dump_packet()
722 {
723 	u_char *p;
724 	int i;
725 
726 	Fprintf(stderr, "packet data:");
727 	for (p = outpacket, i = 0; i < datalen; i++) {
728 		if ((i % 24) == 0)
729 			Fprintf(stderr, "\n ");
730 		Fprintf(stderr, " %02x", *p++);
731 	}
732 	Fprintf(stderr, "\n");
733 }
734 
735 void
736 send_probe(seq, ttl, iflag, to)
737 	int seq, ttl, iflag;
738 	struct sockaddr_in *to;
739 {
740 	struct ip *ip = (struct ip *)outpacket;
741 	u_char *p = (u_char *)(ip + 1);
742 	struct udphdr *up = (struct udphdr *)(p + lsrrlen);
743 	struct icmp *icmpp = (struct icmp *)(p + lsrrlen);
744 	struct packetdata *op;
745 	int i;
746 	struct timeval tv;
747 
748 	ip->ip_len = htons(datalen);
749 	ip->ip_ttl = ttl;
750 	ip->ip_id = htons(ident+seq);
751 
752 	switch(proto) {
753 	   case IPPROTO_ICMP:
754 		icmpp->icmp_type = icmp_type;
755 		icmpp->icmp_code = icmp_code;
756 		icmpp->icmp_seq = htons(seq);
757 		icmpp->icmp_id = htons(ident);
758 		op = (struct packetdata *)(icmpp + 1);
759 		break;
760 	   case IPPROTO_UDP:
761 		up->uh_sport = htons(ident);
762 		if (iflag)
763 			up->uh_dport = htons(port+seq);
764 		else
765 			up->uh_dport = htons(port);
766 		up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) -
767 		    lsrrlen));
768 		up->uh_sum = 0;
769 		op = (struct packetdata *)(up + 1);
770 		break;
771 	default:
772 		op = (struct packetdata *)(ip + 1);
773 		break;
774 	}
775 	op->seq = seq;
776 	op->ttl = ttl;
777 	(void) gettimeofday(&tv, &tz);
778 
779 	/*
780 	 * We don't want hostiles snooping the net to get any useful
781 	 * information about us. Send the timestamp in network byte order,
782 	 * and perturb the timestamp enough that they won't know our
783 	 * real clock ticker. We don't want to perturb the time by too
784 	 * much: being off by a suspiciously large amount might indicate
785 	 * OpenBSD.
786 	 *
787 	 * The timestamps in the packet are currently unused. If future
788 	 * work wants to use them they will have to subtract out the
789 	 * perturbation first.
790 	 */
791 	(void) gettimeofday(&tv, &tz);
792 	op->sec = htonl(tv.tv_sec + sec_perturb);
793 	op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000);
794 
795 	if (proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) {
796 		icmpp->icmp_cksum = 0;
797 		icmpp->icmp_cksum = compute_in_cksum((u_short *)icmpp,
798 					datalen - sizeof(struct ip) - lsrrlen);
799 		if (icmpp->icmp_cksum == 0) icmpp->icmp_cksum = 0xffff;
800 	}
801 
802 	if (dump)
803 		dump_packet();
804 
805 	i = sendto(sndsock, outpacket, datalen, 0, (struct sockaddr *)to,
806 		   sizeof(struct sockaddr_in));
807 	if (i < 0 || i != datalen)  {
808 		if (i<0)
809 			perror("sendto");
810 		//Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
811 		//	datalen, i);
812 		(void) fflush(stdout);
813 	}
814 }
815 
816 /*
817  * Convert an ICMP "type" field to a printable string.
818  */
819 static char *
820 pr_type(t)
821 	u_char t;
822 {
823 	static char *ttab[] = {
824 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
825 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
826 	"Echo",		"Router Advert",	"Router Solicit",	"Time Exceeded",
827 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
828 	"Info Reply", "Mask Request", "Mask Reply"
829 	};
830 
831 	if (t > 18)
832 		return ("OUT-OF-RANGE");
833 
834 	return (ttab[t]);
835 }
836 
837 
838 int
839 packet_ok(buf, cc, from, seq, iflag)
840 	u_char *buf;
841 	int cc;
842 	struct sockaddr_in *from;
843 	int seq;
844 	int iflag;
845 {
846 	register struct icmp *icp;
847 	u_char type, code;
848 	int hlen;
849 #ifndef ARCHAIC
850 	struct ip *ip;
851 
852 	ip = (struct ip *) buf;
853 	hlen = ip->ip_hl << 2;
854 	if (cc < hlen + ICMP_MINLEN) {
855 		if (verbose)
856 			Printf("packet too short (%d bytes) from %s\n", cc,
857 				inet_ntoa(from->sin_addr));
858 		return (0);
859 	}
860 	cc -= hlen;
861 	icp = (struct icmp *)(buf + hlen);
862 #else
863 	icp = (struct icmp *)buf;
864 #endif /* ARCHAIC */
865 	type = icp->icmp_type; code = icp->icmp_code;
866 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
867 	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY ) {
868 		struct ip *hip;
869 		struct udphdr *up;
870 		struct icmp *icmpp;
871 
872 		hip = &icp->icmp_ip;
873 		hlen = hip->ip_hl << 2;
874 
875 		switch(proto) {
876 		  case IPPROTO_ICMP:
877 
878 			if (icmp_type == ICMP_ECHO &&
879 			    type == ICMP_ECHOREPLY &&
880 			    icp->icmp_id == htons(ident) &&
881 			    icp->icmp_seq == htons(seq))
882 				return (-2); /* we got there */
883 
884 			icmpp = (struct icmp *)((u_char *)hip + hlen);
885 			if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP &&
886 			    icmpp->icmp_id == htons(ident) &&
887 			    icmpp->icmp_seq == htons(seq))
888 				return (type == ICMP_TIMXCEED? -1 : code + 1);
889 			break;
890 
891 		  case IPPROTO_UDP:
892 			up = (struct udphdr *)((u_char *)hip + hlen);
893 			if (hlen + 12 <= cc && hip->ip_p == proto &&
894 			    up->uh_sport == htons(ident) &&
895 			    ((iflag && up->uh_dport == htons(port + seq)) ||
896 			    (!iflag && up->uh_dport == htons(port))))
897 				return (type == ICMP_TIMXCEED? -1 : code + 1);
898 			break;
899 		default:
900 			/* this is some odd, user specified proto,
901 			 * how do we check it?
902 			 */
903 			if (hip->ip_p == proto)
904 				return (type == ICMP_TIMXCEED? -1 : code + 1);
905 		}
906 	}
907 #ifndef ARCHAIC
908 	if (verbose) {
909 		int i;
910 		in_addr_t *lp = (in_addr_t *)&icp->icmp_ip;
911 
912 		Printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr));
913 		Printf(" to %s", inet_ntoa(ip->ip_dst));
914 		Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
915 		    icp->icmp_code);
916 		for (i = 4; i < cc ; i += sizeof(in_addr_t))
917 			Printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++);
918 	}
919 #endif /* ARCHAIC */
920 	return (0);
921 }
922 
923 
924 void
925 print(buf, cc, from)
926 	u_char *buf;
927 	int cc;
928 	struct sockaddr_in *from;
929 {
930 	struct ip *ip;
931 	int hlen;
932 
933 	ip = (struct ip *) buf;
934 	hlen = ip->ip_hl << 2;
935 	cc -= hlen;
936 
937 	if (nflag)
938 		Printf(" %s", inet_ntoa(from->sin_addr));
939 	else
940 		Printf(" %s (%s)", inetname(from->sin_addr),
941 		    inet_ntoa(from->sin_addr));
942 
943 	if (verbose)
944 		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
945 }
946 
947 
948 /*
949  * Checksum routine for Internet Protocol family headers (C Version)
950  */
951 u_short
952 compute_in_cksum(addr, len)
953 	u_short *addr;
954 	int len;
955 {
956 	register int nleft = len;
957 	register u_short *w = addr;
958 	register u_short answer;
959 	register int sum = 0;
960 
961 	/*
962 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
963 	 *  we add sequential 16 bit words to it, and at the end, fold
964 	 *  back all the carry bits from the top 16 bits into the lower
965 	 *  16 bits.
966 	 */
967 	while (nleft > 1)  {
968 		sum += *w++;
969 		nleft -= 2;
970 	}
971 
972 	/* mop up an odd byte, if necessary */
973 	if (nleft == 1)
974 		sum += *(u_char *)w;
975 
976 	/*
977 	 * add back carry outs from top 16 bits to low 16 bits
978 	 */
979 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
980 	sum += (sum >> 16);			/* add carry */
981 	answer = ~sum;				/* truncate to 16 bits */
982 	return (answer);
983 }
984 
985 /*
986  * Construct an Internet address representation.
987  * If the nflag has been supplied, give
988  * numeric value, otherwise try for symbolic name.
989  */
990 char *
991 inetname(in)
992 	struct in_addr in;
993 {
994 	register char *cp;
995 	register struct hostent *hp;
996 	static int first = 1;
997 	static char domain[MAXHOSTNAMELEN], line[MAXHOSTNAMELEN];
998 
999 	if (first && !nflag) {
1000 		first = 0;
1001 		if (gethostname(domain, sizeof domain) == 0 &&
1002 		    (cp = strchr(domain, '.')) != NULL) {
1003 			strncpy(cp + 1, domain, sizeof(domain));
1004 		}
1005 	}
1006 	if (!nflag && in.s_addr != INADDR_ANY) {
1007 		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
1008 		if (hp != NULL) {
1009 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
1010 			    strcmp(cp + 1, domain) == 0)
1011 				*cp = '\0';
1012 			strncpy(hp->h_name, line, sizeof(line));
1013 			return (line);
1014 		}
1015 	}
1016 	return (inet_ntoa(in));
1017 }
1018 
1019 void
1020 usage()
1021 {
1022 	extern char *__progname;
1023 	fprintf(stderr,
1024 		"usage: %s [-SDIdnrvc] [-g gateway_addr] ... [-m max_ttl] [-p port#]\n"
1025 		"\t[-P proto] [-q nqueries] [-s src_addr] [-t tos]\n"
1026 		"\t[-w wait] [-f first_ttl] host [data size]\n", __progname);
1027 	exit(1);
1028 }
1029