xref: /haiku/src/bin/network/traceroute/traceroute.c (revision 21258e2674226d6aa732321b6f8494841895af5f)
1 /*
2  * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #ifndef lint
23 static const char copyright[] =
24     "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
25 The Regents of the University of California.  All rights reserved.\n";
26 static const char rcsid[] =
27     "@(#)$Id: traceroute.c 20492 2007-04-01 11:51:14Z axeld $ (LBL)";
28 #endif
29 
30 /*
31  * traceroute host  - trace the route ip packets follow going to "host".
32  *
33  * Attempt to trace the route an ip packet would follow to some
34  * internet host.  We find out intermediate hops by launching probe
35  * packets with a small ttl (time to live) then listening for an
36  * icmp "time exceeded" reply from a gateway.  We start our probes
37  * with a ttl of one and increase by one until we get an icmp "port
38  * unreachable" (which means we got to "host") or hit a max (which
39  * defaults to 30 hops & can be changed with the -m flag).  Three
40  * probes (change with -q flag) are sent at each ttl setting and a
41  * line is printed showing the ttl, address of the gateway and
42  * round trip time of each probe.  If the probe answers come from
43  * different gateways, the address of each responding system will
44  * be printed.  If there is no response within a 5 sec. timeout
45  * interval (changed with the -w flag), a "*" is printed for that
46  * probe.
47  *
48  * Probe packets are UDP format.  We don't want the destination
49  * host to process them so the destination port is set to an
50  * unlikely value (if some clod on the destination is using that
51  * value, it can be changed with the -p flag).
52  *
53  * A sample use might be:
54  *
55  *     [yak 71]% traceroute nis.nsf.net.
56  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
57  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
58  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
59  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
60  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
61  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
62  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
63  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
64  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
65  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
66  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
67  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
68  *
69  * Note that lines 2 & 3 are the same.  This is due to a buggy
70  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
71  * packets with a zero ttl.
72  *
73  * A more interesting example is:
74  *
75  *     [yak 72]% traceroute allspice.lcs.mit.edu.
76  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
77  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
78  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
79  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
80  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
81  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
82  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
83  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
84  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
85  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
86  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
87  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
88  *     12  * * *
89  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
90  *     14  * * *
91  *     15  * * *
92  *     16  * * *
93  *     17  * * *
94  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
95  *
96  * (I start to see why I'm having so much trouble with mail to
97  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
98  * either don't send ICMP "time exceeded" messages or send them
99  * with a ttl too small to reach us.  14 - 17 are running the
100  * MIT C Gateway code that doesn't send "time exceeded"s.  God
101  * only knows what's going on with 12.
102  *
103  * The silent gateway 12 in the above may be the result of a bug in
104  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
105  * sends an unreachable message using whatever ttl remains in the
106  * original datagram.  Since, for gateways, the remaining ttl is
107  * zero, the icmp "time exceeded" is guaranteed to not make it back
108  * to us.  The behavior of this bug is slightly more interesting
109  * when it appears on the destination system:
110  *
111  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
112  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
113  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
114  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
115  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
116  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
117  *      7  * * *
118  *      8  * * *
119  *      9  * * *
120  *     10  * * *
121  *     11  * * *
122  *     12  * * *
123  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
124  *
125  * Notice that there are 12 "gateways" (13 is the final
126  * destination) and exactly the last half of them are "missing".
127  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
128  * is using the ttl from our arriving datagram as the ttl in its
129  * icmp reply.  So, the reply will time out on the return path
130  * (with no notice sent to anyone since icmp's aren't sent for
131  * icmp's) until we probe with a ttl that's at least twice the path
132  * length.  I.e., rip is really only 7 hops away.  A reply that
133  * returns with a ttl of 1 is a clue this problem exists.
134  * Traceroute prints a "!" after the time if the ttl is <= 1.
135  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
136  * non-standard (HPUX) software, expect to see this problem
137  * frequently and/or take care picking the target host of your
138  * probes.
139  *
140  * Other possible annotations after the time are !H, !N, !P (got a host,
141  * network or protocol unreachable, respectively), !S or !F (source
142  * route failed or fragmentation needed -- neither of these should
143  * ever occur and the associated gateway is busted if you see one).  If
144  * almost all the probes result in some kind of unreachable, traceroute
145  * will give up and exit.
146  *
147  * Notes
148  * -----
149  * This program must be run by root or be setuid.  (I suggest that
150  * you *don't* make it setuid -- casual use could result in a lot
151  * of unnecessary traffic on our poor, congested nets.)
152  *
153  * This program requires a kernel mod that does not appear in any
154  * system available from Berkeley:  A raw ip socket using proto
155  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
156  * opposed to data to be wrapped in a ip datagram).  See the README
157  * file that came with the source to this program for a description
158  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
159  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
160  * MODIFIED TO RUN THIS PROGRAM.
161  *
162  * The udp port usage may appear bizarre (well, ok, it is bizarre).
163  * The problem is that an icmp message only contains 8 bytes of
164  * data from the original datagram.  8 bytes is the size of a udp
165  * header so, if we want to associate replies with the original
166  * datagram, the necessary information must be encoded into the
167  * udp header (the ip id could be used but there's no way to
168  * interlock with the kernel's assignment of ip id's and, anyway,
169  * it would have taken a lot more kernel hacking to allow this
170  * code to set the ip id).  So, to allow two or more users to
171  * use traceroute simultaneously, we use this task's pid as the
172  * source port (the high bit is set to move the port number out
173  * of the "likely" range).  To keep track of which probe is being
174  * replied to (so times and/or hop counts don't get confused by a
175  * reply that was delayed in transit), we increment the destination
176  * port number before each probe.
177  *
178  * Don't use this as a coding example.  I was trying to find a
179  * routing problem and this code sort-of popped out after 48 hours
180  * without sleep.  I was amazed it ever compiled, much less ran.
181  *
182  * I stole the idea for this program from Steve Deering.  Since
183  * the first release, I've learned that had I attended the right
184  * IETF working group meetings, I also could have stolen it from Guy
185  * Almes or Matt Mathis.  I don't know (or care) who came up with
186  * the idea first.  I envy the originators' perspicacity and I'm
187  * glad they didn't keep the idea a secret.
188  *
189  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
190  * enhancements to the original distribution.
191  *
192  * I've hacked up a round-trip-route version of this that works by
193  * sending a loose-source-routed udp datagram through the destination
194  * back to yourself.  Unfortunately, SO many gateways botch source
195  * routing, the thing is almost worthless.  Maybe one day...
196  *
197  *  -- Van Jacobson (van@ee.lbl.gov)
198  *     Tue Dec 20 03:50:13 PST 1988
199  */
200 
201 #include <sys/param.h>
202 #include <sys/ioctl.h>
203 #ifdef HAVE_SYS_SELECT_H
204 #include <sys/select.h>
205 #endif
206 #include <sys/socket.h>
207 #include <sys/time.h>
208 
209 #include <netinet/in.h>
210 #include <netinet/ip.h>
211 #include <netinet/ip_var.h>
212 #include <netinet/ip_icmp.h>
213 #include <netinet/udp.h>
214 
215 #include <arpa/inet.h>
216 
217 #include <ctype.h>
218 #include <errno.h>
219 #include <fcntl.h>
220 #ifdef HAVE_MALLOC_H
221 #include <malloc.h>
222 #endif
223 #include <memory.h>
224 #include <netdb.h>
225 #include <stdio.h>
226 #include <stdlib.h>
227 #include <string.h>
228 #include <unistd.h>
229 
230 #include "gnuc.h"
231 #ifdef HAVE_OS_PROTO_H
232 #include "os-proto.h"
233 #endif
234 
235 /* rfc1716 */
236 #ifndef ICMP_UNREACH_FILTER_PROHIB
237 #define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
238 #endif
239 #ifndef ICMP_UNREACH_HOST_PRECEDENCE
240 #define ICMP_UNREACH_HOST_PRECEDENCE	14	/* host precedence violation */
241 #endif
242 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
243 #define ICMP_UNREACH_PRECEDENCE_CUTOFF	15	/* precedence cutoff */
244 #endif
245 
246 #include "findsaddr.h"
247 #include "ifaddrlist.h"
248 #include "traceroute.h"
249 
250 /* Maximum number of gateways (include room for one noop) */
251 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
252 
253 #ifndef MAXHOSTNAMELEN
254 #define MAXHOSTNAMELEN	64
255 #endif
256 
257 #define Fprintf (void)fprintf
258 #define Printf (void)printf
259 
260 /* Host name and address list */
261 struct hostinfo {
262 	char *name;
263 	int n;
264 	u_int32_t *addrs;
265 };
266 
267 /* Data section of the probe packet */
268 struct outdata {
269 	u_char seq;		/* sequence number of this packet */
270 	u_char ttl;		/* ttl packet left with */
271 	struct timeval tv;	/* time packet left */
272 };
273 
274 #ifndef HAVE_ICMP_NEXTMTU
275 /* Path MTU Discovery (RFC1191) */
276 struct my_pmtu {
277 	u_short ipm_void;
278 	u_short ipm_nextmtu;
279 };
280 #endif
281 
282 u_char	packet[512];		/* last inbound (icmp) packet */
283 
284 struct ip *outip;		/* last output (udp) packet */
285 struct udphdr *outudp;		/* last output (udp) packet */
286 struct outdata *outdata;	/* last output (udp) packet */
287 
288 struct icmp *outicmp;		/* last output (icmp) packet */
289 
290 /* loose source route gateway list (including room for final destination) */
291 u_int32_t gwlist[NGATEWAYS + 1];
292 
293 int s;				/* receive (icmp) socket file descriptor */
294 int sndsock;			/* send (udp/icmp) socket file descriptor */
295 
296 struct sockaddr whereto;	/* Who to try to reach */
297 struct sockaddr wherefrom;	/* Who we are */
298 int packlen;			/* total length of packet */
299 int minpacket;			/* min ip packet size */
300 int maxpacket = 32 * 1024;	/* max ip packet size */
301 int pmtu;			/* Path MTU Discovery (RFC1191) */
302 u_int pausemsecs;
303 
304 char *prog;
305 char *source;
306 char *hostname;
307 char *device;
308 static const char devnull[] = "/dev/null";
309 
310 int nprobes = 3;
311 int max_ttl = 30;
312 int first_ttl = 1;
313 u_short ident;
314 u_short port = 32768 + 666;	/* start udp dest port # for probe packets */
315 
316 int options;			/* socket options */
317 int verbose;
318 int waittime = 5;		/* time to wait for response (in seconds) */
319 int nflag;			/* print addresses numerically */
320 int useicmp;			/* use icmp echo instead of udp packets */
321 #ifdef CANT_HACK_IPCKSUM
322 int doipcksum = 0;		/* don't calculate ip checksums by default */
323 #else
324 int doipcksum = 1;		/* calculate ip checksums by default */
325 #endif
326 int optlen;			/* length of ip options */
327 
328 extern int optind;
329 extern int opterr;
330 extern char *optarg;
331 
332 /* Forwards */
333 double	deltaT(struct timeval *, struct timeval *);
334 void	freehostinfo(struct hostinfo *);
335 void	getaddr(u_int32_t *, char *);
336 struct	hostinfo *gethostinfo(char *);
337 u_short	in_cksum(u_short *, int);
338 char	*inetname(struct in_addr);
339 int	main(int, char **);
340 int	packet_ok(u_char *, int, struct sockaddr_in *, int);
341 char	*pr_type(u_char);
342 void	print(u_char *, int, struct sockaddr_in *);
343 void	send_probe(int, int, struct timeval *);
344 int	str2val(const char *, const char *, int, int);
345 void	tvsub(struct timeval *, struct timeval *);
346 __dead	void usage(void);
347 int	wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
348 #ifndef HAVE_USLEEP
349 int	usleep(u_int);
350 #endif
351 
352 int
353 main(int argc, char **argv)
354 {
355 	register int op, code, n;
356 	register char *cp;
357 	register const char *err;
358 	register u_char *outp;
359 	register u_int32_t *ap;
360 	register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
361 	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
362 	register struct hostinfo *hi;
363 	int on = 1;
364 	register struct protoent *pe;
365 	register int ttl, probe, i;
366 	register int seq = 0;
367 	int tos = 0, settos = 0;
368 	register int lsrr = 0;
369 	register u_short off = 0;
370 	struct ifaddrlist *al;
371 	char errbuf[132];
372 
373 	if (argv[0] == NULL)
374 		prog = "traceroute";
375 	else if ((cp = strrchr(argv[0], '/')) != NULL)
376 		prog = cp + 1;
377 	else
378 		prog = argv[0];
379 
380 	opterr = 0;
381 	while ((op = getopt(argc, argv, "dFInrvxf:g:i:m:p:q:s:t:w:z:")) != EOF)
382 		switch (op) {
383 
384 		case 'd':
385 			options |= SO_DEBUG;
386 			break;
387 
388 		case 'f':
389 			first_ttl = str2val(optarg, "first ttl", 1, 255);
390 			break;
391 
392 		case 'F':
393 			off = IP_DF;
394 			break;
395 
396 		case 'g':
397 			if (lsrr >= NGATEWAYS) {
398 				Fprintf(stderr,
399 				    "%s: No more than %d gateways\n",
400 				    prog, NGATEWAYS);
401 				exit(1);
402 			}
403 			getaddr(gwlist + lsrr, optarg);
404 			++lsrr;
405 			break;
406 
407 		case 'i':
408 			device = optarg;
409 			break;
410 
411 		case 'I':
412 			++useicmp;
413 			break;
414 
415 		case 'm':
416 			max_ttl = str2val(optarg, "max ttl", 1, 255);
417 			break;
418 
419 		case 'n':
420 			++nflag;
421 			break;
422 
423 		case 'p':
424 			port = (u_short)str2val(optarg, "port",
425 			    1, (1 << 16) - 1);
426 			break;
427 
428 		case 'q':
429 			nprobes = str2val(optarg, "nprobes", 1, -1);
430 			break;
431 
432 		case 'r':
433 			options |= SO_DONTROUTE;
434 			break;
435 
436 		case 's':
437 			/*
438 			 * set the ip source address of the outbound
439 			 * probe (e.g., on a multi-homed host).
440 			 */
441 			source = optarg;
442 			break;
443 
444 		case 't':
445 			tos = str2val(optarg, "tos", 0, 255);
446 			++settos;
447 			break;
448 
449 		case 'v':
450 			++verbose;
451 			break;
452 
453 		case 'x':
454 			doipcksum = (doipcksum == 0);
455 			break;
456 
457 		case 'w':
458 			waittime = str2val(optarg, "wait time",
459 			    2, 24 * 60 * 60);
460 			break;
461 
462 		case 'z':
463 			pausemsecs = str2val(optarg, "pause msecs",
464 			    0, 60 * 60 * 1000);
465 			break;
466 
467 		default:
468 			usage();
469 		}
470 
471 	if (first_ttl > max_ttl) {
472 		Fprintf(stderr,
473 		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
474 		    prog, first_ttl, max_ttl);
475 		exit(1);
476 	}
477 
478 	if (!doipcksum)
479 		Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
480 
481 	if (lsrr > 0)
482 		optlen = (lsrr + 1) * sizeof(gwlist[0]);
483 	minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
484 	if (useicmp)
485 		minpacket += 8;			/* XXX magic number */
486 	else
487 		minpacket += sizeof(*outudp);
488 	packlen = minpacket;			/* minimum sized packet */
489 
490 	/* Process destination and optional packet size */
491 	switch (argc - optind) {
492 
493 	case 2:
494 		packlen = str2val(argv[optind + 1],
495 		    "packet length", minpacket, maxpacket);
496 		/* Fall through */
497 
498 	case 1:
499 		hostname = argv[optind];
500 		hi = gethostinfo(hostname);
501 		setsin(to, hi->addrs[0]);
502 		if (hi->n > 1)
503 			Fprintf(stderr,
504 		    "%s: Warning: %s has multiple addresses; using %s\n",
505 				prog, hostname, inet_ntoa(to->sin_addr));
506 		hostname = hi->name;
507 		hi->name = NULL;
508 		freehostinfo(hi);
509 		break;
510 
511 	default:
512 		usage();
513 	}
514 
515 #ifdef HAVE_SETLINEBUF
516 	setlinebuf (stdout);
517 #else
518 	setvbuf(stdout, NULL, _IOLBF, 0);
519 #endif
520 
521 	outip = (struct ip *)malloc((unsigned)packlen);
522 	if (outip == NULL) {
523 		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
524 		exit(1);
525 	}
526 	memset((char *)outip, 0, packlen);
527 
528 	outip->ip_v = IPVERSION;
529 	if (settos)
530 		outip->ip_tos = tos;
531 #ifdef BYTESWAP_IP_HDR
532 	outip->ip_len = htons(packlen);
533 	outip->ip_off = htons(off);
534 #else
535 	outip->ip_len = packlen;
536 	outip->ip_off = off;
537 #endif
538 	outp = (u_char *)(outip + 1);
539 #ifdef HAVE_RAW_OPTIONS
540 	if (lsrr > 0) {
541 		register u_char *optlist;
542 
543 		optlist = outp;
544 		outp += optlen;
545 
546 		/* final hop */
547 		gwlist[lsrr] = to->sin_addr.s_addr;
548 
549 		outip->ip_dst.s_addr = gwlist[0];
550 
551 		/* force 4 byte alignment */
552 		optlist[0] = IPOPT_NOP;
553 		/* loose source route option */
554 		optlist[1] = IPOPT_LSRR;
555 		i = lsrr * sizeof(gwlist[0]);
556 		optlist[2] = i + 3;
557 		/* Pointer to LSRR addresses */
558 		optlist[3] = IPOPT_MINOFF;
559 		memcpy(optlist + 4, gwlist + 1, i);
560 	} else
561 #endif
562 		outip->ip_dst = to->sin_addr;
563 
564 	outip->ip_hl = (outp - (u_char *)outip) >> 2;
565 	ident = (getpid() & 0xffff) | 0x8000;
566 	if (useicmp) {
567 		outip->ip_p = IPPROTO_ICMP;
568 
569 		outicmp = (struct icmp *)outp;
570 		outicmp->icmp_type = ICMP_ECHO;
571 		outicmp->icmp_id = htons(ident);
572 
573 		outdata = (struct outdata *)(outp + 8);	/* XXX magic number */
574 	} else {
575 		outip->ip_p = IPPROTO_UDP;
576 
577 		outudp = (struct udphdr *)outp;
578 		outudp->uh_sport = htons(ident);
579 		outudp->uh_ulen =
580 		    htons((u_short)(packlen - (sizeof(*outip) + optlen)));
581 		outdata = (struct outdata *)(outudp + 1);
582 	}
583 
584 	cp = "icmp";
585 	if ((pe = getprotobyname(cp)) == NULL) {
586 		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
587 		exit(1);
588 	}
589 
590 	/* Insure the socket fds won't be 0, 1 or 2 */
591 	if (open(devnull, O_RDONLY) < 0 ||
592 	    open(devnull, O_RDONLY) < 0 ||
593 	    open(devnull, O_RDONLY) < 0) {
594 		Fprintf(stderr, "%s: open \"%s\": %s\n",
595 		    prog, devnull, strerror(errno));
596 		exit(1);
597 	}
598 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
599 		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
600 		exit(1);
601 	}
602 	if (options & SO_DEBUG)
603 		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
604 		    sizeof(on));
605 	if (options & SO_DONTROUTE)
606 		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
607 		    sizeof(on));
608 
609 #ifndef __hpux
610 	sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
611 #else
612 	sndsock = socket(AF_INET, SOCK_RAW,
613 	    useicmp ? IPPROTO_ICMP : IPPROTO_UDP);
614 #endif
615 	if (sndsock < 0) {
616 		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
617 		exit(1);
618 	}
619 
620 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
621 	if (lsrr > 0) {
622 		u_char optlist[MAX_IPOPTLEN];
623 
624 		cp = "ip";
625 		if ((pe = getprotobyname(cp)) == NULL) {
626 			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
627 			exit(1);
628 		}
629 
630 		/* final hop */
631 		gwlist[lsrr] = to->sin_addr.s_addr;
632 		++lsrr;
633 
634 		/* force 4 byte alignment */
635 		optlist[0] = IPOPT_NOP;
636 		/* loose source route option */
637 		optlist[1] = IPOPT_LSRR;
638 		i = lsrr * sizeof(gwlist[0]);
639 		optlist[2] = i + 3;
640 		/* Pointer to LSRR addresses */
641 		optlist[3] = IPOPT_MINOFF;
642 		memcpy(optlist + 4, gwlist, i);
643 
644 		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
645 		    (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
646 			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
647 			    prog, strerror(errno));
648 			exit(1);
649 		    }
650 	}
651 #endif
652 
653 #ifdef SO_SNDBUF
654 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
655 	    sizeof(packlen)) < 0) {
656 		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
657 		exit(1);
658 	}
659 #endif
660 #ifdef IP_HDRINCL
661 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
662 	    sizeof(on)) < 0) {
663 		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
664 		exit(1);
665 	}
666 #else
667 #ifdef IP_TOS
668 	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
669 	    (char *)&tos, sizeof(tos)) < 0) {
670 		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
671 		    prog, tos, strerror(errno));
672 		exit(1);
673 	}
674 #endif
675 #endif
676 	if (options & SO_DEBUG)
677 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
678 		    sizeof(on));
679 	if (options & SO_DONTROUTE)
680 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
681 		    sizeof(on));
682 
683 	/* Get the interface address list */
684 	n = ifaddrlist(&al, errbuf);
685 	if (n < 0) {
686 		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
687 		exit(1);
688 	}
689 	if (n == 0) {
690 		Fprintf(stderr,
691 		    "%s: Can't find any network interfaces\n", prog);
692 		exit(1);
693 	}
694 
695 	/* Look for a specific device */
696 	if (device != NULL) {
697 		for (i = n; i > 0; --i, ++al)
698 			if (strcmp(device, al->device) == 0)
699 				break;
700 		if (i <= 0) {
701 			Fprintf(stderr, "%s: Can't find interface %.32s\n",
702 			    prog, device);
703 			exit(1);
704 		}
705 	}
706 
707 	/* Determine our source address */
708 	if (source == NULL) {
709 		/*
710 		 * If a device was specified, use the interface address.
711 		 * Otherwise, try to determine our source address.
712 		 */
713 		if (device != NULL)
714 			setsin(from, al->addr);
715 		else if ((err = findsaddr(to, from)) != NULL) {
716 			Fprintf(stderr, "%s: findsaddr: %s\n",
717 			    prog, err);
718 			exit(1);
719 		}
720 	} else {
721 		hi = gethostinfo(source);
722 		source = hi->name;
723 		hi->name = NULL;
724 		/*
725 		 * If the device was specified make sure it
726 		 * corresponds to the source address specified.
727 		 * Otherwise, use the first address (and warn if
728 		 * there are more than one).
729 		 */
730 		if (device != NULL) {
731 			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
732 				if (*ap == al->addr)
733 					break;
734 			if (i <= 0) {
735 				Fprintf(stderr,
736 				    "%s: %s is not on interface %.32s\n",
737 				    prog, source, device);
738 				exit(1);
739 			}
740 			setsin(from, *ap);
741 		} else {
742 			setsin(from, hi->addrs[0]);
743 			if (hi->n > 1)
744 				Fprintf(stderr,
745 			"%s: Warning: %s has multiple addresses; using %s\n",
746 				    prog, source, inet_ntoa(from->sin_addr));
747 		}
748 		freehostinfo(hi);
749 	}
750 
751 	/* Revert to non-privileged user after opening sockets */
752 	setgid(getgid());
753 	setuid(getuid());
754 
755 	outip->ip_src = from->sin_addr;
756 #ifndef IP_HDRINCL
757 	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
758 		Fprintf(stderr, "%s: bind: %s\n",
759 		    prog, strerror(errno));
760 		exit (1);
761 	}
762 #endif
763 
764 	Fprintf(stderr, "%s to %s (%s)",
765 	    prog, hostname, inet_ntoa(to->sin_addr));
766 	if (source)
767 		Fprintf(stderr, " from %s", source);
768 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
769 	(void)fflush(stderr);
770 
771 	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
772 		u_int32_t lastaddr = 0;
773 		int gotlastaddr = 0;
774 		int got_there = 0;
775 		int unreachable = 0;
776 		int sentfirst = 0;
777 
778 		Printf("%2d ", ttl);
779 		for (probe = 0; probe < nprobes; ++probe) {
780 			register int cc;
781 			struct timeval t1, t2;
782 			struct timezone tz;
783 			register struct ip *ip;
784 
785 			if (sentfirst && pausemsecs > 0)
786 				usleep(pausemsecs * 1000);
787 			(void)gettimeofday(&t1, &tz);
788 			send_probe(++seq, ttl, &t1);
789 			++sentfirst;
790 			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
791 				(void)gettimeofday(&t2, &tz);
792 				i = packet_ok(packet, cc, from, seq);
793 				/* Skip short packet */
794 				if (i == 0)
795 					continue;
796 				if (!gotlastaddr ||
797 				    from->sin_addr.s_addr != lastaddr) {
798 					print(packet, cc, from);
799 					lastaddr = from->sin_addr.s_addr;
800 					++gotlastaddr;
801 				}
802 				Printf("  %.3f ms", deltaT(&t1, &t2));
803 				if (i == -2) {
804 #ifndef ARCHAIC
805 					ip = (struct ip *)packet;
806 					if (ip->ip_ttl <= 1)
807 						Printf(" !");
808 #endif
809 					++got_there;
810 					break;
811 				}
812 				/* time exceeded in transit */
813 				if (i == -1)
814 					break;
815 				code = i - 1;
816 				switch (code) {
817 
818 				case ICMP_UNREACH_PORT:
819 #ifndef ARCHAIC
820 					ip = (struct ip *)packet;
821 					if (ip->ip_ttl <= 1)
822 						Printf(" !");
823 #endif
824 					++got_there;
825 					break;
826 
827 				case ICMP_UNREACH_NET:
828 					++unreachable;
829 					Printf(" !N");
830 					break;
831 
832 				case ICMP_UNREACH_HOST:
833 					++unreachable;
834 					Printf(" !H");
835 					break;
836 
837 				case ICMP_UNREACH_PROTOCOL:
838 					++got_there;
839 					Printf(" !P");
840 					break;
841 
842 				case ICMP_UNREACH_NEEDFRAG:
843 					++unreachable;
844 					Printf(" !F-%d", pmtu);
845 					break;
846 
847 				case ICMP_UNREACH_SRCFAIL:
848 					++unreachable;
849 					Printf(" !S");
850 					break;
851 
852 				case ICMP_UNREACH_FILTER_PROHIB:
853 					++unreachable;
854 					Printf(" !X");
855 					break;
856 
857 				case ICMP_UNREACH_HOST_PRECEDENCE:
858 					++unreachable;
859 					Printf(" !V");
860 					break;
861 
862 				case ICMP_UNREACH_PRECEDENCE_CUTOFF:
863 					++unreachable;
864 					Printf(" !C");
865 					break;
866 
867 				default:
868 					++unreachable;
869 					Printf(" !<%d>", code);
870 					break;
871 				}
872 				break;
873 			}
874 			if (cc == 0)
875 				Printf(" *");
876 			(void)fflush(stdout);
877 		}
878 		putchar('\n');
879 		if (got_there ||
880 		    (unreachable > 0 && unreachable >= nprobes - 1))
881 			break;
882 	}
883 	exit(0);
884 }
885 
886 int
887 wait_for_reply(register int sock, register struct sockaddr_in *fromp,
888     register const struct timeval *tp)
889 {
890 	fd_set fds;
891 	struct timeval now, wait;
892 	struct timezone tz;
893 	register int cc = 0;
894 	int fromlen = sizeof(*fromp);
895 
896 	FD_ZERO(&fds);
897 	FD_SET(sock, &fds);
898 
899 	wait.tv_sec = tp->tv_sec + waittime;
900 	wait.tv_usec = tp->tv_usec;
901 	(void)gettimeofday(&now, &tz);
902 	tvsub(&wait, &now);
903 
904 	if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
905 		cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
906 			    (struct sockaddr *)fromp, &fromlen);
907 
908 	return(cc);
909 }
910 
911 void
912 send_probe(register int seq, int ttl, register struct timeval *tp)
913 {
914 	register int cc;
915 	struct ip tip;
916 
917 	outip->ip_ttl = ttl;
918 #ifndef __hpux
919 	outip->ip_id = htons(ident + seq);
920 #endif
921 
922 	/*
923 	 * In most cases, the kernel will recalculate the ip checksum.
924 	 * But we must do it anyway so that the udp checksum comes out
925 	 * right.
926 	 */
927 	if (doipcksum) {
928 		outip->ip_sum =
929 		    in_cksum((u_short *)outip, sizeof(*outip) + optlen);
930 		if (outip->ip_sum == 0)
931 			outip->ip_sum = 0xffff;
932 	}
933 
934 	/* Payload */
935 	outdata->seq = seq;
936 	outdata->ttl = ttl;
937 	outdata->tv = *tp;
938 
939 	if (useicmp)
940 		outicmp->icmp_seq = htons(seq);
941 	else
942 		outudp->uh_dport = htons(port + seq);
943 
944 	if (useicmp) {
945 		/* Always calculate checksum for icmp packets */
946 		outicmp->icmp_cksum = 0;
947 		outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
948 		    packlen - (sizeof(*outip) + optlen));
949 		if (outicmp->icmp_cksum == 0)
950 			outicmp->icmp_cksum = 0xffff;
951 	} else if (doipcksum) {
952 		memset(&tip, 0, sizeof(tip));
953 		tip.ip_src = outip->ip_src;
954 		tip.ip_dst = outip->ip_dst;
955 		tip.ip_p   = outip->ip_p;
956 		tip.ip_len = outudp->uh_ulen;
957 
958 		outudp->uh_sum = ~in_cksum((u_short *)&tip, sizeof(tip));
959 		outudp->uh_sum = in_cksum((u_short *)outudp,
960 					  packlen - (sizeof(*outip) + optlen));
961 		if (outudp->uh_sum == 0)
962 			outudp->uh_sum = 0xffff;
963 	}
964 
965 	/* XXX undocumented debugging hack */
966 	if (verbose > 1) {
967 		register const u_short *sp;
968 		register int nshorts, i;
969 
970 		sp = (u_short *)outip;
971 		nshorts = (u_int)packlen / sizeof(u_short);
972 		i = 0;
973 		Printf("[ %d bytes", packlen);
974 		while (--nshorts >= 0) {
975 			if ((i++ % 8) == 0)
976 				Printf("\n\t");
977 			Printf(" %04x", ntohs(*sp++));
978 		}
979 		if (packlen & 1) {
980 			if ((i % 8) == 0)
981 				Printf("\n\t");
982 			Printf(" %02x", *(u_char *)sp);
983 		}
984 		Printf("]\n");
985 	}
986 
987 #if !defined(IP_HDRINCL) && defined(IP_TTL)
988 	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
989 	    (char *)&ttl, sizeof(ttl)) < 0) {
990 		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
991 		    prog, ttl, strerror(errno));
992 		exit(1);
993 	}
994 #endif
995 
996 #ifdef __hpux
997 	cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp,
998 	    packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto));
999 	if (cc > 0)
1000 		cc += sizeof(*outip) + optlen;
1001 #else
1002 	cc = sendto(sndsock, (char *)outip,
1003 	    packlen, 0, &whereto, sizeof(whereto));
1004 #endif
1005 	if (cc < 0 || cc != packlen)  {
1006 		if (cc < 0)
1007 			Fprintf(stderr, "%s: sendto: %s\n",
1008 			    prog, strerror(errno));
1009 		Printf("%s: wrote %s %d chars, ret=%d\n",
1010 		    prog, hostname, packlen, cc);
1011 		(void)fflush(stdout);
1012 	}
1013 }
1014 
1015 double
1016 deltaT(struct timeval *t1p, struct timeval *t2p)
1017 {
1018 	register double dt;
1019 
1020 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
1021 	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
1022 	return (dt);
1023 }
1024 
1025 /*
1026  * Convert an ICMP "type" field to a printable string.
1027  */
1028 char *
1029 pr_type(register u_char t)
1030 {
1031 	static char *ttab[] = {
1032 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
1033 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
1034 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
1035 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
1036 	"Info Reply"
1037 	};
1038 
1039 	if (t > 16)
1040 		return("OUT-OF-RANGE");
1041 
1042 	return(ttab[t]);
1043 }
1044 
1045 int
1046 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
1047     register int seq)
1048 {
1049 	register struct icmp *icp;
1050 	register u_char type, code;
1051 	register int hlen;
1052 #ifndef ARCHAIC
1053 	register struct ip *ip;
1054 
1055 	ip = (struct ip *) buf;
1056 	hlen = ip->ip_hl << 2;
1057 	if (cc < hlen + ICMP_MINLEN) {
1058 		if (verbose)
1059 			Printf("packet too short (%d bytes) from %s\n", cc,
1060 				inet_ntoa(from->sin_addr));
1061 		return (0);
1062 	}
1063 	cc -= hlen;
1064 	icp = (struct icmp *)(buf + hlen);
1065 #else
1066 	icp = (struct icmp *)buf;
1067 #endif
1068 	type = icp->icmp_type;
1069 	code = icp->icmp_code;
1070 	/* Path MTU Discovery (RFC1191) */
1071 	if (code != ICMP_UNREACH_NEEDFRAG)
1072 		pmtu = 0;
1073 	else {
1074 #ifdef HAVE_ICMP_NEXTMTU
1075 		pmtu = ntohs(icp->icmp_nextmtu);
1076 #else
1077 		pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
1078 #endif
1079 	}
1080 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
1081 	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
1082 		register struct ip *hip;
1083 		register struct udphdr *up;
1084 		register struct icmp *hicmp;
1085 
1086 		hip = &icp->icmp_ip;
1087 		hlen = hip->ip_hl << 2;
1088 		if (useicmp) {
1089 			/* XXX */
1090 			if (type == ICMP_ECHOREPLY &&
1091 			    icp->icmp_id == htons(ident) &&
1092 			    icp->icmp_seq == htons(seq))
1093 				return (-2);
1094 
1095 			hicmp = (struct icmp *)((u_char *)hip + hlen);
1096 			/* XXX 8 is a magic number */
1097 			if (hlen + 8 <= cc &&
1098 			    hip->ip_p == IPPROTO_ICMP &&
1099 			    hicmp->icmp_id == htons(ident) &&
1100 			    hicmp->icmp_seq == htons(seq))
1101 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
1102 		} else {
1103 			up = (struct udphdr *)((u_char *)hip + hlen);
1104 			/* XXX 8 is a magic number */
1105 			if (hlen + 12 <= cc &&
1106 			    hip->ip_p == IPPROTO_UDP &&
1107 			    up->uh_sport == htons(ident) &&
1108 			    up->uh_dport == htons(port + seq))
1109 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
1110 		}
1111 	}
1112 #ifndef ARCHAIC
1113 	if (verbose) {
1114 		register int i;
1115 		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
1116 
1117 		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
1118 		Printf("%s: icmp type %d (%s) code %d\n",
1119 		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
1120 		for (i = 4; i < cc ; i += sizeof(*lp))
1121 			Printf("%2d: x%8.8x\n", i, *lp++);
1122 	}
1123 #endif
1124 	return(0);
1125 }
1126 
1127 
1128 void
1129 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
1130 {
1131 	register struct ip *ip;
1132 	register int hlen;
1133 
1134 	ip = (struct ip *) buf;
1135 	hlen = ip->ip_hl << 2;
1136 	cc -= hlen;
1137 
1138 	if (nflag)
1139 		Printf(" %s", inet_ntoa(from->sin_addr));
1140 	else
1141 		Printf(" %s (%s)", inetname(from->sin_addr),
1142 		    inet_ntoa(from->sin_addr));
1143 
1144 	if (verbose)
1145 		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
1146 }
1147 
1148 /*
1149  * Checksum routine for Internet Protocol family headers (C Version)
1150  */
1151 u_short
1152 in_cksum(register u_short *addr, register int len)
1153 {
1154 	register int nleft = len;
1155 	register u_short *w = addr;
1156 	register u_short answer;
1157 	register int sum = 0;
1158 
1159 	/*
1160 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
1161 	 *  we add sequential 16 bit words to it, and at the end, fold
1162 	 *  back all the carry bits from the top 16 bits into the lower
1163 	 *  16 bits.
1164 	 */
1165 	while (nleft > 1)  {
1166 		sum += *w++;
1167 		nleft -= 2;
1168 	}
1169 
1170 	/* mop up an odd byte, if necessary */
1171 	if (nleft == 1)
1172 		sum += *(u_char *)w;
1173 
1174 	/*
1175 	 * add back carry outs from top 16 bits to low 16 bits
1176 	 */
1177 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
1178 	sum += (sum >> 16);			/* add carry */
1179 	answer = ~sum;				/* truncate to 16 bits */
1180 	return (answer);
1181 }
1182 
1183 /*
1184  * Subtract 2 timeval structs:  out = out - in.
1185  * Out is assumed to be >= in.
1186  */
1187 void
1188 tvsub(register struct timeval *out, register struct timeval *in)
1189 {
1190 
1191 	if ((out->tv_usec -= in->tv_usec) < 0)   {
1192 		--out->tv_sec;
1193 		out->tv_usec += 1000000;
1194 	}
1195 	out->tv_sec -= in->tv_sec;
1196 }
1197 
1198 /*
1199  * Construct an Internet address representation.
1200  * If the nflag has been supplied, give
1201  * numeric value, otherwise try for symbolic name.
1202  */
1203 char *
1204 inetname(struct in_addr in)
1205 {
1206 	register char *cp;
1207 	register struct hostent *hp;
1208 	static int first = 1;
1209 	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
1210 
1211 	if (first && !nflag) {
1212 		first = 0;
1213 		if (gethostname(domain, sizeof(domain) - 1) < 0)
1214 			domain[0] = '\0';
1215 		else {
1216 			cp = strchr(domain, '.');
1217 			if (cp == NULL) {
1218 				hp = gethostbyname(domain);
1219 				if (hp != NULL)
1220 					cp = strchr(hp->h_name, '.');
1221 			}
1222 			if (cp == NULL)
1223 				domain[0] = '\0';
1224 			else {
1225 				++cp;
1226 				(void)strncpy(domain, cp, sizeof(domain) - 1);
1227 				domain[sizeof(domain) - 1] = '\0';
1228 			}
1229 		}
1230 	}
1231 	if (!nflag && in.s_addr != INADDR_ANY) {
1232 		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
1233 		if (hp != NULL) {
1234 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
1235 			    strcmp(cp + 1, domain) == 0)
1236 				*cp = '\0';
1237 			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
1238 			line[sizeof(line) - 1] = '\0';
1239 			return (line);
1240 		}
1241 	}
1242 	return (inet_ntoa(in));
1243 }
1244 
1245 struct hostinfo *
1246 gethostinfo(register char *hostname)
1247 {
1248 	register int n;
1249 	register struct hostent *hp;
1250 	register struct hostinfo *hi;
1251 	register char **p;
1252 	register u_int32_t addr, *ap;
1253 
1254 	if (strlen(hostname) > 64) {
1255 		Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
1256 		    prog, hostname);
1257 		exit(1);
1258 	}
1259 	hi = calloc(1, sizeof(*hi));
1260 	if (hi == NULL) {
1261 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1262 		exit(1);
1263 	}
1264 	addr = inet_addr(hostname);
1265 	if ((int32_t)addr != -1) {
1266 		hi->name = strdup(hostname);
1267 		hi->n = 1;
1268 		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1269 		if (hi->addrs == NULL) {
1270 			Fprintf(stderr, "%s: calloc %s\n",
1271 			    prog, strerror(errno));
1272 			exit(1);
1273 		}
1274 		hi->addrs[0] = addr;
1275 		return (hi);
1276 	}
1277 
1278 	hp = gethostbyname(hostname);
1279 	if (hp == NULL) {
1280 		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
1281 		exit(1);
1282 	}
1283 	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
1284 		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
1285 		exit(1);
1286 	}
1287 	hi->name = strdup(hp->h_name);
1288 	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1289 		continue;
1290 	hi->n = n;
1291 	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1292 	if (hi->addrs == NULL) {
1293 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1294 		exit(1);
1295 	}
1296 	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1297 		memcpy(ap, *p, sizeof(*ap));
1298 	return (hi);
1299 }
1300 
1301 void
1302 freehostinfo(register struct hostinfo *hi)
1303 {
1304 	if (hi->name != NULL) {
1305 		free(hi->name);
1306 		hi->name = NULL;
1307 	}
1308 	free((char *)hi->addrs);
1309 	free((char *)hi);
1310 }
1311 
1312 void
1313 getaddr(register u_int32_t *ap, register char *hostname)
1314 {
1315 	register struct hostinfo *hi;
1316 
1317 	hi = gethostinfo(hostname);
1318 	*ap = hi->addrs[0];
1319 	freehostinfo(hi);
1320 }
1321 
1322 void
1323 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
1324 {
1325 
1326 	memset(sin, 0, sizeof(*sin));
1327 #ifdef HAVE_SOCKADDR_SA_LEN
1328 	sin->sin_len = sizeof(*sin);
1329 #endif
1330 	sin->sin_family = AF_INET;
1331 	sin->sin_addr.s_addr = addr;
1332 }
1333 
1334 /* String to value with optional min and max. Handles decimal and hex. */
1335 int
1336 str2val(register const char *str, register const char *what,
1337     register int mi, register int ma)
1338 {
1339 	register const char *cp;
1340 	register int val;
1341 	char *ep;
1342 
1343 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1344 		cp = str + 2;
1345 		val = (int)strtol(cp, &ep, 16);
1346 	} else
1347 		val = (int)strtol(str, &ep, 10);
1348 	if (*ep != '\0') {
1349 		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1350 		    prog, str, what);
1351 		exit(1);
1352 	}
1353 	if (val < mi && mi >= 0) {
1354 		if (mi == 0)
1355 			Fprintf(stderr, "%s: %s must be >= %d\n",
1356 			    prog, what, mi);
1357 		else
1358 			Fprintf(stderr, "%s: %s must be > %d\n",
1359 			    prog, what, mi - 1);
1360 		exit(1);
1361 	}
1362 	if (val > ma && ma >= 0) {
1363 		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1364 		exit(1);
1365 	}
1366 	return (val);
1367 }
1368 
1369 __dead void
1370 usage(void)
1371 {
1372 	extern char version[];
1373 
1374 	Fprintf(stderr, "Version %s\n", version);
1375 	Fprintf(stderr,
1376 	    "Usage: %s [-dFInrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
1377 	    "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
1378 	    "\t[-w waittime] [-z pausemsecs] host [packetlen]\n", prog);
1379 	exit(1);
1380 }
1381