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