6615189 reverse ip6 name lookups don't work in traceroute
[opensolaris.git] / usr / src / cmd / cmd-inet / usr.sbin / traceroute / traceroute.c
blobadc6a932b0e32cc9ed849eb03e6a89b98e77e885
1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that: (1) source code distributions
12 * retain the above copyright notice and this paragraph in its entirety, (2)
13 * distributions including binary code include the above copyright notice and
14 * this paragraph in its entirety in the documentation or other materials
15 * provided with the distribution, and (3) all advertising materials mentioning
16 * features or use of this software display the following acknowledgement:
17 * ``This product includes software developed by the University of California,
18 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
19 * the University nor the names of its contributors may be used to endorse
20 * or promote products derived from this software without specific prior
21 * written permission.
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27 * @(#)$Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp $ (LBL)
30 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <sys/param.h>
33 #include <sys/file.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <sys/sysmacros.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip_var.h>
43 #include <netinet/ip_icmp.h>
44 #include <netinet/udp.h>
45 #include <netinet/udp_var.h>
46 #include <netinet/ip6.h>
47 #include <netinet/icmp6.h>
49 #include <arpa/inet.h>
51 #include <ctype.h>
52 #include <errno.h>
53 #include <malloc.h>
54 #include <memory.h>
55 #include <netdb.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <strings.h>
59 #include <unistd.h>
60 #include <libintl.h>
61 #include <locale.h>
62 #include <signal.h>
63 #include <setjmp.h>
64 #include <limits.h>
65 #include <zone.h>
67 #include <priv_utils.h>
69 #include <libinetutil.h>
70 #include "traceroute.h"
72 #define MAX_SEQ 65535 /* max sequence value for ICMP */
73 #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
74 #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
75 #define MAX_TOS 255 /* max type-of-service for IPv4 */
76 #define STR_LEN 30
78 /* store the information about a host */
79 struct hostinfo {
80 char *name; /* hostname */
81 int family; /* address family of the IP addresses */
82 int num_addr; /* number of IP addresses */
83 union any_in_addr *addrs; /* list of IP addresses */
86 /* used to store a bunch of protocol specific values */
87 struct pr_set {
88 int family; /* AF_INET or AF_INET6 */
89 char name[STR_LEN]; /* "IPv4" or "IPv6" */
90 char icmp[STR_LEN]; /* "icmp" or "ipv6-icmp" */
91 int icmp_minlen;
92 int addr_len;
93 int ip_hdr_len;
94 int packlen;
95 int sock_size; /* size of sockaddr_in or sockaddr_in6 */
96 struct sockaddr *to;
97 struct sockaddr *from;
98 void *from_sin_addr;
99 union any_in_addr *gwIPlist;
100 /* pointers to v4/v6 functions */
101 struct ip *(*set_buffers_fn) (int);
102 int (*check_reply_fn)(struct msghdr *, int, int, uchar_t *, uchar_t *);
103 boolean_t (*print_icmp_other_fn)(uchar_t, uchar_t);
104 void (*print_addr_fn)(uchar_t *, int, struct sockaddr *);
109 * LBNL bug fixed: in LBNL traceroute 'uchar_t packet[512];'
110 * Not sufficient to hold the complete packet for ECHO REPLY of a big probe.
111 * Packet size is reported incorrectly in such a case.
112 * Also this buffer needs to be 32 bit aligned. In the future the alignment
113 * requirement will be increased to 64 bit. So, let's use 64 bit alignment now.
115 static uint64_t packet[(IP_MAXPACKET + 1)/8]; /* received packet */
117 static struct ip *outip4; /* output buffer to send as an IPv4 datagram */
118 static struct ip *outip6; /* output buffer to send as an IPv6 datagram */
120 /* Used to store the ancillary data that comes with the received packets */
121 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
123 /* first get the gw names, later you'll resolve them based on the family */
124 static char *gwlist[MAXMAX_GWS]; /* gateway names list */
125 static union any_in_addr gwIPlist[MAX_GWS]; /* gateway IPv4 address list */
126 static union any_in_addr gwIP6list[MAX_GWS6]; /* gateway IPv6 address list */
128 static int family_input = AF_UNSPEC; /* User supplied protocol family */
129 static int rcvsock4; /* receive (icmp) socket file descriptor */
130 static int sndsock4; /* send (udp/icmp) socket file descriptor */
131 static int rcvsock6; /* receive (icmp6) socket file descriptor */
132 static int sndsock6; /* send (udp6/icmp6) socket file descriptor */
133 int gw_count = 0; /* number of gateways */
134 static struct sockaddr_in whereto; /* Who to try to reach */
135 static struct sockaddr_in6 whereto6;
136 static struct sockaddr_in wherefrom; /* Who we are */
137 static struct sockaddr_in6 wherefrom6;
138 static int packlen_input = 0; /* user input for packlen */
140 char *prog;
141 static char *source_input = NULL; /* this is user arg. source, doesn't change */
142 static char *source = NULL; /* this gets modified after name lookup */
143 char *hostname;
144 static char *device = NULL; /* interface name */
145 static struct pr_set *pr4; /* protocol info for IPv4 */
146 static struct pr_set *pr6; /* protocol info for IPv6 */
147 static struct ifaddrlist *al4; /* list of interfaces */
148 static struct ifaddrlist *al6; /* list of interfaces */
149 static uint_t if_index = 0; /* interface index */
150 static int num_v4 = 0; /* count of IPv4 addresses */
151 static int num_v6 = 0; /* count of IPv6 addresses */
152 static int num_ifs4 = 0; /* count of local IPv4 interfaces */
153 static int num_ifs6 = 0; /* count of local IPv6 interfaces */
155 static int nprobes = 3; /* number of probes */
156 static int max_ttl = 30; /* max number of hops */
157 static int first_ttl = 1; /* initial number of hops */
158 ushort_t ident; /* used to authenticate replies */
159 ushort_t port = 32768 + 666; /* start udp dest port # for probe packets */
161 static int options = 0; /* socket options */
162 boolean_t verbose = _B_FALSE; /* verbose output */
163 static int waittime = 5; /* time to wait for response (in seconds) */
164 static struct timeval delay = {0, 0}; /* delay between consecutive probe */
165 boolean_t nflag = _B_FALSE; /* print addresses numerically */
166 static boolean_t showttl = _B_FALSE; /* print the ttl(hop limit) of recvd pkt */
167 boolean_t useicmp = _B_FALSE; /* use icmp echo instead of udp packets */
168 boolean_t docksum = _B_TRUE; /* calculate checksums */
169 static boolean_t collect_stat = _B_FALSE; /* print statistics */
170 boolean_t settos = _B_FALSE; /* set type-of-service field */
171 static int max_timeout = 5; /* quit after this consecutive timeouts */
172 static boolean_t probe_all = _B_FALSE; /* probe all the IFs of the target */
173 static boolean_t pick_src = _B_FALSE; /* traceroute picks the src address */
176 * flow and class are specific to IPv6, tos and off are specific to IPv4.
177 * Each protocol uses the ones that are specific to itself, and ignores
178 * others.
180 static uint_t flow = 0; /* IPv6 flow info */
181 static uint_t class = 0; /* IPv6 class */
182 uchar_t tos = 0; /* IPv4 type-of-service */
183 ushort_t off = 0; /* set DF bit */
185 static jmp_buf env; /* stack environment for longjmp() */
186 boolean_t raw_req; /* if sndsock for IPv4 must be raw */
188 /* Forwards */
189 static uint_t calc_packetlen(int, struct pr_set *);
190 extern int check_reply(struct msghdr *, int, int, uchar_t *, uchar_t *);
191 extern int check_reply6(struct msghdr *, int, int, uchar_t *, uchar_t *);
192 static double deltaT(struct timeval *, struct timeval *);
193 static char *device_name(struct ifaddrlist *, int, union any_in_addr *,
194 struct pr_set *);
195 extern void *find_ancillary_data(struct msghdr *, int, int);
196 static boolean_t has_addr(struct addrinfo *, union any_in_addr *);
197 static struct ifaddrlist *find_device(struct ifaddrlist *, int, char *);
198 static struct ifaddrlist *find_ifaddr(struct ifaddrlist *, int,
199 union any_in_addr *, int);
200 static void get_gwaddrs(char **, int, union any_in_addr *,
201 union any_in_addr *, int *, int *);
202 static void get_hostinfo(char *, int, struct addrinfo **);
203 char *inet_name(union any_in_addr *, int);
204 ushort_t in_cksum(ushort_t *, int);
205 extern int ip_hdr_length_v6(ip6_t *, int, uint8_t *);
206 extern char *pr_type(uchar_t);
207 extern char *pr_type6(uchar_t);
208 extern void print_addr(uchar_t *, int, struct sockaddr *);
209 extern void print_addr6(uchar_t *, int, struct sockaddr *);
210 extern boolean_t print_icmp_other(uchar_t, uchar_t);
211 extern boolean_t print_icmp_other6(uchar_t, uchar_t);
212 static void print_stats(int, int, double, double, double, double);
213 static void print_unknown_host_msg(const char *, const char *);
214 static void record_stats(double, int *, double *, double *, double *, double *);
215 static void resolve_nodes(int *, struct addrinfo **);
216 static void select_src_addr(union any_in_addr *, union any_in_addr *, int);
217 extern void send_probe(int, struct sockaddr *, struct ip *, int, int,
218 struct timeval *, int);
219 extern void send_probe6(int, struct msghdr *, struct ip *, int, int,
220 struct timeval *, int);
221 extern void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int,
222 uint_t);
223 extern struct ip *set_buffers(int);
224 extern struct ip *set_buffers6(int);
225 extern void set_IPv4opt_sourcerouting(int, union any_in_addr *,
226 union any_in_addr *);
227 static void set_sin(struct sockaddr *, union any_in_addr *, int);
228 static int set_src_addr(struct pr_set *, struct ifaddrlist **);
229 static void setup_protocol(struct pr_set *, int);
230 static void setup_socket(struct pr_set *, int);
231 static void sig_handler(int);
232 static int str2int(const char *, const char *, int, int);
233 static double str2dbl(const char *, const char *, double, double);
234 static void trace_it(struct addrinfo *);
235 static void traceroute(union any_in_addr *, struct msghdr *, struct pr_set *,
236 int, struct ifaddrlist *);
237 static void tv_sub(struct timeval *, struct timeval *);
238 static void usage(void);
239 static int wait_for_reply(int, struct msghdr *, struct timeval *);
240 static double xsqrt(double);
243 * main
246 main(int argc, char **argv)
248 struct addrinfo *ai_dst = NULL; /* destination host */
250 * "probing_successful" indicates if we could successfully send probes,
251 * not necessarily received reply from the target (this behavior is from
252 * the original traceroute). It's _B_FALSE if packlen is invalid, or no
253 * interfaces found.
255 boolean_t probing_successful = _B_FALSE;
256 int longjmp_return; /* return value from longjump */
257 int i = 0;
258 char *cp;
259 int op;
260 char *ep;
261 char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */
262 double pause;
265 * A raw socket will be used for IPv4 if there is sufficient
266 * privilege.
268 raw_req = priv_ineffect(PRIV_NET_RAWACCESS);
271 * We'll need the privilege only when we open the sockets; that's
272 * when we'll fail if the program has insufficient privileges.
274 (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
275 raw_req ? PRIV_NET_RAWACCESS : NULL, NULL);
277 (void) setlinebuf(stdout);
279 if ((cp = strrchr(argv[0], '/')) != NULL)
280 prog = cp + 1;
281 else
282 prog = argv[0];
284 opterr = 0;
285 while ((op = getopt(argc, argv, "adFIlnrSvxA:c:f:g:i:L:m:P:p:Q:q:s:"
286 "t:w:")) != EOF) {
287 switch (op) {
288 case 'A':
289 if (strcmp(optarg, "inet") == 0) {
290 family_input = AF_INET;
291 } else if (strcmp(optarg, "inet6") == 0) {
292 family_input = AF_INET6;
293 } else {
294 Fprintf(stderr,
295 "%s: unknown address family %s\n",
296 prog, optarg);
297 exit(EXIT_FAILURE);
299 break;
301 case 'a':
302 probe_all = _B_TRUE;
303 break;
305 case 'c':
306 class = str2int(optarg, "traffic class", 0,
307 MAX_TRAFFIC_CLASS);
308 break;
310 case 'd':
311 options |= SO_DEBUG;
312 break;
314 case 'f':
315 first_ttl = str2int(optarg, "first ttl", 1, MAXTTL);
316 break;
318 case 'F':
319 off = IP_DF;
320 break;
322 case 'g':
323 if (!raw_req) {
324 Fprintf(stderr,
325 "%s: privilege to specify a loose source "
326 "route gateway is unavailable\n",
327 prog);
328 exit(EXIT_FAILURE);
330 if (gw_count >= MAXMAX_GWS) {
331 Fprintf(stderr,
332 "%s: Too many gateways\n", prog);
333 exit(EXIT_FAILURE);
335 gwlist[gw_count] = strdup(optarg);
336 if (gwlist[gw_count] == NULL) {
337 Fprintf(stderr, "%s: strdup %s\n", prog,
338 strerror(errno));
339 exit(EXIT_FAILURE);
342 ++gw_count;
343 break;
345 case 'l':
346 showttl = _B_TRUE;
347 break;
349 case 'i':
350 /* this can be IF name or IF index */
351 if_index = (uint_t)strtol(optarg, &ep, 10);
353 /* convert IF index <--> IF name */
354 if (errno != 0 || *ep != '\0') {
355 device = optarg;
356 if_index = if_nametoindex((const char *)device);
359 * In case it fails, check to see if the problem
360 * is other than "IF not found".
362 if (if_index == 0 && errno != ENXIO) {
363 Fprintf(stderr, "%s: if_nametoindex:"
364 "%s\n", prog, strerror(errno));
365 exit(EXIT_FAILURE);
367 } else {
368 device = (char *)malloc(LIFNAMSIZ + 1);
369 if (device == NULL) {
370 Fprintf(stderr, "%s: malloc: %s\n",
371 prog, strerror(errno));
372 exit(EXIT_FAILURE);
375 device = if_indextoname(if_index, device);
376 if (device != NULL) {
377 device[LIFNAMSIZ] = '\0';
378 } else if (errno != ENXIO) {
380 * The problem was other than "index
381 * not found".
383 Fprintf(stderr, "%s: if_indextoname:"
384 "%s\n", prog, strerror(errno));
385 exit(EXIT_FAILURE);
389 if (device == NULL || if_index == 0) {
390 Fprintf(stderr, "%s: interface %s "
391 "doesn't match any actual interfaces\n",
392 prog, optarg);
393 exit(EXIT_FAILURE);
395 break;
397 case 'I':
398 useicmp = _B_TRUE;
399 break;
401 case 'L':
402 flow = str2int(optarg, "flow label", 0, MAX_FLOW_LABEL);
403 break;
405 case 'm':
406 max_ttl = str2int(optarg, "max ttl(hop limit)", 1,
407 MAXTTL);
408 break;
410 case 'n':
411 nflag = _B_TRUE;
412 break;
414 case 'P':
415 pause = str2dbl(optarg, "pause", 0, INT_MAX);
416 delay.tv_sec = (time_t)pause;
417 delay.tv_usec = (suseconds_t)((pause - delay.tv_sec) *
418 1000000);
419 break;
421 case 'p':
422 port = str2int(optarg, "port", 1, MAX_PORT);
423 break;
425 case 'Q':
426 max_timeout = str2int(optarg, "max timeout", 1, -1);
427 break;
429 case 'q':
430 nprobes = str2int(optarg, "nprobes", 1, -1);
431 break;
433 case 'r':
434 options |= SO_DONTROUTE;
435 break;
437 case 'S':
438 collect_stat = _B_TRUE;
439 break;
441 case 's':
443 * set the ip source address of the outbound
444 * probe (e.g., on a multi-homed host).
446 source_input = optarg;
447 break;
449 case 't':
450 tos = (uchar_t)str2int(optarg, "tos", 0, MAX_TOS);
451 settos = _B_TRUE;
452 break;
454 case 'v':
455 verbose = _B_TRUE;
456 break;
458 case 'x':
459 docksum = _B_FALSE;
460 break;
462 case 'w':
463 waittime = str2int(optarg, "wait time", 2, -1);
464 break;
466 default:
467 usage();
468 break;
473 * If it's probe_all, SIGQUIT makes traceroute exit(). But we set the
474 * address to jump back to in traceroute(). Until then, we'll need to
475 * temporarily specify one.
477 if (probe_all) {
478 if ((longjmp_return = setjmp(env)) != 0) {
479 if (longjmp_return == SIGQUIT) {
480 Printf("(exiting)\n");
481 exit(EXIT_SUCCESS);
482 } else { /* should never happen */
483 exit(EXIT_FAILURE);
486 (void) signal(SIGQUIT, sig_handler);
489 if ((gw_count > 0) && (options & SO_DONTROUTE)) {
490 Fprintf(stderr, "%s: loose source route gateways (-g)"
491 " cannot be specified when probe packets are sent"
492 " directly to a host on an attached network (-r)\n",
493 prog);
494 exit(EXIT_FAILURE);
497 i = argc - optind;
498 if (i == 1 || i == 2) {
499 hostname = argv[optind];
501 if (i == 2) {
502 /* accept any length now, we'll check it later */
503 packlen_input = str2int(argv[optind + 1],
504 "packet length", 0, -1);
506 } else {
507 usage();
510 if (first_ttl > max_ttl) {
511 Fprintf(stderr,
512 "%s: first ttl(hop limit) (%d) may not be greater"
513 " than max ttl(hop limit) (%d)\n",
514 prog, first_ttl, max_ttl);
515 exit(EXIT_FAILURE);
518 /* resolve hostnames */
519 resolve_nodes(&family_input, &ai_dst);
520 if (ai_dst == NULL) {
521 exit(EXIT_FAILURE);
525 * If it's probe_all, SIGINT makes traceroute skip to probing next IP
526 * address of the target. The new interrupt handler is assigned in
527 * traceroute() function. Until then let's ignore the signal.
529 if (probe_all)
530 (void) signal(SIGINT, SIG_IGN);
532 ident = (getpid() & 0xffff) | 0x8000;
535 * We KNOW that probe_all == TRUE if family is AF_UNSPEC,
536 * since family is set to the specific AF found unless it's
537 * probe_all. So if family == AF_UNSPEC, we need to init pr4 and pr6.
539 switch (family_input) {
540 case AF_UNSPEC:
541 pr4 = (struct pr_set *)malloc(sizeof (struct pr_set));
542 if (pr4 == NULL) {
543 Fprintf(stderr,
544 "%s: malloc %s\n", prog, strerror(errno));
545 exit(EXIT_FAILURE);
547 pr6 = (struct pr_set *)malloc(sizeof (struct pr_set));
548 if (pr6 == NULL) {
549 Fprintf(stderr,
550 "%s: malloc %s\n", prog, strerror(errno));
551 exit(EXIT_FAILURE);
553 setup_protocol(pr6, AF_INET6);
554 setup_protocol(pr4, AF_INET);
555 outip6 = (*pr6->set_buffers_fn)(pr6->packlen);
556 setup_socket(pr6, pr6->packlen);
558 outip4 = (*pr4->set_buffers_fn)(pr4->packlen);
559 setup_socket(pr4, pr4->packlen);
560 num_ifs6 = set_src_addr(pr6, &al6);
561 num_ifs4 = set_src_addr(pr4, &al4);
562 break;
563 case AF_INET6:
564 pr6 = (struct pr_set *)malloc(sizeof (struct pr_set));
565 if (pr6 == NULL) {
566 Fprintf(stderr,
567 "%s: malloc %s\n", prog, strerror(errno));
568 exit(EXIT_FAILURE);
570 setup_protocol(pr6, AF_INET6);
571 outip6 = (*pr6->set_buffers_fn)(pr6->packlen);
572 setup_socket(pr6, pr6->packlen);
573 num_ifs6 = set_src_addr(pr6, &al6);
574 break;
575 case AF_INET:
576 pr4 = (struct pr_set *)malloc(sizeof (struct pr_set));
577 if (pr4 == NULL) {
578 Fprintf(stderr,
579 "%s: malloc %s\n", prog, strerror(errno));
580 exit(EXIT_FAILURE);
582 setup_protocol(pr4, AF_INET);
583 outip4 = (*pr4->set_buffers_fn)(pr4->packlen);
584 setup_socket(pr4, pr4->packlen);
585 num_ifs4 = set_src_addr(pr4, &al4);
586 break;
587 default:
588 Fprintf(stderr, "%s: unknow address family.\n", prog);
589 exit(EXIT_FAILURE);
592 if (num_v4 + num_v6 > 1 && !probe_all) {
593 if (ai_dst->ai_family == AF_INET) {
594 Fprintf(stderr,
595 "%s: Warning: %s has multiple addresses;"
596 " using %s\n", prog, hostname,
597 inet_ntop(AF_INET,
598 /* LINTED E_BAD_PTR_CAST_ALIGN */
599 (void *)&((struct sockaddr_in *)
600 ai_dst->ai_addr)->sin_addr,
601 temp_buf, sizeof (temp_buf)));
602 } else {
603 Fprintf(stderr,
604 "%s: Warning: %s has multiple addresses;"
605 " using %s\n", prog, hostname,
606 inet_ntop(AF_INET6,
607 /* LINTED E_BAD_PTR_CAST_ALIGN */
608 (void *)&((struct sockaddr_in6 *)
609 ai_dst->ai_addr)->sin6_addr,
610 temp_buf, sizeof (temp_buf)));
614 if (num_ifs4 + num_ifs6 > 0) {
615 trace_it(ai_dst);
616 probing_successful = _B_TRUE;
619 (void) close(rcvsock4);
620 (void) close(sndsock4);
621 (void) close(rcvsock6);
622 (void) close(sndsock6);
625 * if we could probe any of the IP addresses of the target, that means
626 * this was a successful operation
628 if (probing_successful)
629 return (EXIT_SUCCESS);
630 else
631 return (EXIT_FAILURE);
635 * print "unknown host" message
637 static void
638 print_unknown_host_msg(const char *protocol, const char *host)
640 Fprintf(stderr, "%s: unknown%s host %s\n", prog, protocol, host);
644 * resolve destination host and gateways
646 static void
647 resolve_nodes(int *family, struct addrinfo **ai_dstp)
649 struct addrinfo *ai_dst = NULL;
650 struct addrinfo *aip = NULL;
651 int num_resolved_gw = 0;
652 int num_resolved_gw6 = 0;
654 get_hostinfo(hostname, *family, &ai_dst);
655 if (ai_dst == NULL) {
656 print_unknown_host_msg("", hostname);
657 exit(EXIT_FAILURE);
659 /* Get a count of the v4 & v6 addresses */
660 for (aip = ai_dst; aip != NULL; aip = aip->ai_next) {
661 switch (aip->ai_family) {
662 case AF_INET:
663 num_v4++;
664 break;
665 case AF_INET6:
666 num_v6++;
667 break;
671 if (*family == AF_UNSPEC && !probe_all) {
672 *family = ai_dst->ai_family;
675 /* resolve gateways */
676 if (gw_count > 0) {
677 get_gwaddrs(gwlist, *family, gwIPlist, gwIP6list,
678 &num_resolved_gw, &num_resolved_gw6);
680 /* we couldn't resolve a gateway as an IPv6 host */
681 if (num_resolved_gw6 != gw_count && num_v6 != 0) {
682 if (*family == AF_INET6 || *family == AF_UNSPEC)
683 print_unknown_host_msg(" IPv6",
684 gwlist[num_resolved_gw6]);
685 num_v6 = 0;
688 /* we couldn't resolve a gateway as an IPv4 host */
689 if (num_resolved_gw != gw_count && num_v4 != 0) {
690 if (*family == AF_INET || *family == AF_UNSPEC)
691 print_unknown_host_msg(" IPv4",
692 gwlist[num_resolved_gw]);
693 num_v4 = 0;
697 *ai_dstp = (num_v4 + num_v6 > 0) ? ai_dst : NULL;
701 * Given IP address or hostname, return v4 and v6 hostinfo lists.
702 * Assumes that hostinfo ** ptrs are non-null.
704 static void
705 get_hostinfo(char *host, int family, struct addrinfo **aipp)
707 struct addrinfo hints, *ai;
708 struct in6_addr addr6;
709 struct in_addr addr;
710 char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */
711 int rc;
714 * Take care of v4-mapped addresses. It should run same as v4, after
715 * chopping off the prefix, leaving the IPv4 address
717 if ((inet_pton(AF_INET6, host, &addr6) > 0) &&
718 IN6_IS_ADDR_V4MAPPED(&addr6)) {
719 /* peel off the "mapping" stuff, leaving 32 bit IPv4 address */
720 IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
722 /* convert it back to a string */
723 (void) inet_ntop(AF_INET, (void *)&addr, temp_buf,
724 sizeof (temp_buf));
726 /* now the host is an IPv4 address */
727 (void) strcpy(host, temp_buf);
730 * If it's a mapped address, we convert it into IPv4
731 * address because traceroute will send and receive IPv4
732 * packets for that address. Therefore, it's a failure case to
733 * ask get_hostinfo() to treat a mapped address as an IPv6
734 * address.
736 if (family == AF_INET6) {
737 return;
741 (void) memset(&hints, 0, sizeof (hints));
742 hints.ai_family = family;
743 hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
744 rc = getaddrinfo(host, NULL, &hints, &ai);
745 if (rc != 0) {
746 if (rc != EAI_NONAME)
747 Fprintf(stderr, "%s: getaddrinfo: %s\n", prog,
748 gai_strerror(rc));
749 *aipp = NULL;
750 return;
752 *aipp = ai;
756 * Calculate the packet length to be used, and check against the valid range.
757 * Returns -1 if range check fails.
759 static uint_t
760 calc_packetlen(int plen_input, struct pr_set *pr)
762 int minpacket; /* min ip packet size */
763 int optlen; /* length of ip options */
764 int plen;
767 * LBNL bug fixed: miscalculation of optlen
769 if (gw_count > 0) {
771 * IPv4:
772 * ----
773 * 5 (NO OPs) + 3 (code, len, ptr) + gateways
774 * IP options field can hold up to 9 gateways. But the API
775 * allows you to specify only 8, because the last one is the
776 * destination host. When this packet is sent, on the wire
777 * you see one gateway replaced by 4 NO OPs. The other 1 NO
778 * OP is for alignment
780 * IPv6:
781 * ----
782 * Well, formula is different, but the result is same.
783 * 8 byte fixed part for Type 0 Routing header, followed by
784 * gateway addresses
786 optlen = 8 + gw_count * pr->addr_len;
787 } else {
788 optlen = 0;
791 /* take care of the packet length calculations and checks */
792 minpacket = pr->ip_hdr_len + sizeof (struct outdata) + optlen;
793 if (useicmp)
794 minpacket += pr->icmp_minlen; /* minimum ICMP header size */
795 else
796 minpacket += sizeof (struct udphdr);
797 plen = plen_input;
798 if (plen == 0) {
799 plen = minpacket; /* minimum sized packet */
800 } else if (minpacket > plen || plen > IP_MAXPACKET) {
801 Fprintf(stderr, "%s: %s packet size must be >= %d and <= %d\n",
802 prog, pr->name, minpacket, IP_MAXPACKET);
803 return (0);
806 return (plen);
810 * Sets the source address by resolving -i and -s arguments, or if -i and -s
811 * don't dictate any, it sets the pick_src to make sure traceroute uses the
812 * kernel's pick of the source address.
813 * Returns number of interfaces configured on the source host, 0 on error or
814 * there's no interface which is up amd not a loopback.
816 static int
817 set_src_addr(struct pr_set *pr, struct ifaddrlist **alp)
819 union any_in_addr *ap;
820 struct ifaddrlist *al = NULL;
821 struct ifaddrlist *tmp1_al = NULL;
822 struct ifaddrlist *tmp2_al = NULL;
823 /* LINTED E_BAD_PTR_CAST_ALIGN */
824 struct sockaddr_in *sin_from = (struct sockaddr_in *)pr->from;
825 /* LINTED E_BAD_PTR_CAST_ALIGN */
826 struct sockaddr_in6 *sin6_from = (struct sockaddr_in6 *)pr->from;
827 struct addrinfo *aip;
828 char errbuf[ERRBUFSIZE];
829 char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */
830 int num_ifs; /* all the interfaces */
831 int num_src_ifs; /* exclude loopback and down */
832 int i;
834 source = source_input;
836 /* get the interface address list */
837 num_ifs = ifaddrlist(&al, pr->family, errbuf);
838 if (num_ifs < 0) {
839 Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
840 exit(EXIT_FAILURE);
843 num_src_ifs = 0;
844 for (i = 0; i < num_ifs; i++) {
845 if (!(al[i].flags & IFF_LOOPBACK) && (al[i].flags & IFF_UP))
846 num_src_ifs++;
849 if (num_src_ifs == 0) {
850 Fprintf(stderr, "%s: can't find any %s network interfaces\n",
851 prog, pr->name);
852 return (0);
855 /* verify the device */
856 if (device != NULL) {
857 tmp1_al = find_device(al, num_ifs, device);
859 if (tmp1_al == NULL) {
860 Fprintf(stderr, "%s: %s (index %d) is an invalid %s"
861 " interface\n", prog, device, if_index, pr->name);
862 free(al);
863 return (0);
867 /* verify the source address */
868 if (source != NULL) {
869 get_hostinfo(source, pr->family, &aip);
870 if (aip == NULL) {
871 Fprintf(stderr,
872 "%s: %s is an invalid %s source address\n",
873 prog, source, pr->name);
875 free(al);
876 return (0);
879 source = aip->ai_canonname;
881 if (pr->family == AF_INET)
882 ap = (union any_in_addr *)
883 /* LINTED E_BAD_PTR_CAST_ALIGN */
884 &((struct sockaddr_in *)
885 aip->ai_addr)->sin_addr;
886 else
887 ap = (union any_in_addr *)
888 /* LINTED E_BAD_PTR_CAST_ALIGN */
889 &((struct sockaddr_in6 *)
890 aip->ai_addr)->sin6_addr;
893 * LBNL bug fixed: used to accept any src address
895 tmp2_al = find_ifaddr(al, num_ifs, ap, pr->family);
897 if (tmp2_al == NULL) {
898 Fprintf(stderr,
899 "%s: %s is not a local %s address\n",
900 prog, inet_ntop(pr->family, ap,
901 temp_buf, sizeof (temp_buf)),
902 pr->name);
904 free(al);
905 freeaddrinfo(aip);
906 return (0);
910 pick_src = _B_FALSE;
912 if (source == NULL) { /* no -s used */
913 if (device == NULL) { /* no -i used, no -s used */
914 pick_src = _B_TRUE;
915 } else { /* -i used, no -s used */
917 * -i used, but not -s, and it's IPv4: set the source
918 * address to whatever the interface has configured on
919 * it.
921 if (pr->family == AF_INET)
922 set_sin(pr->from, &(tmp1_al->addr), pr->family);
923 else
924 pick_src = _B_TRUE;
926 } else { /* -s used */
927 if (device == NULL) { /* no -i used, -s used */
928 set_sin(pr->from, ap, pr->family);
930 if (aip->ai_next != NULL) {
931 Fprintf(stderr,
932 "%s: Warning: %s has multiple "
933 "addresses; using %s\n",
934 prog, source,
935 inet_ntop(pr->family,
936 (const void *)pr->from_sin_addr,
937 temp_buf, sizeof (temp_buf)));
939 } else { /* -i and -s used */
941 * Make sure the source specified matches the
942 * interface address. You only care about this for IPv4
943 * IPv6 can handle IF not matching src address
945 if (pr->family == AF_INET) {
946 if (!has_addr(aip, &tmp1_al->addr)) {
947 Fprintf(stderr,
948 "%s: %s is not on interface %s\n",
949 prog, source, device);
950 exit(EXIT_FAILURE);
953 * make sure we use the one matching the
954 * interface's address
956 *ap = tmp1_al->addr;
959 set_sin(pr->from, ap, pr->family);
964 * Binding at this point will set the source address to be used
965 * for both IPv4 (when raw IP datagrams are not required) and
966 * IPv6. If the address being bound to is zero, then the kernel
967 * will end up choosing the source address when the datagram is
968 * sent.
970 * For raw IPv4 datagrams, the source address is initialized
971 * within traceroute() along with the outbound destination
972 * address.
974 if (pr->family == AF_INET && !raw_req) {
975 sin_from->sin_family = AF_INET;
976 sin_from->sin_port = htons(ident);
977 if (bind(sndsock4, (struct sockaddr *)pr->from,
978 sizeof (struct sockaddr_in)) < 0) {
979 Fprintf(stderr, "%s: bind: %s\n", prog,
980 strerror(errno));
981 exit(EXIT_FAILURE);
983 } else if (pr->family == AF_INET6) {
984 sin6_from->sin6_family = AF_INET6;
985 sin6_from->sin6_port = htons(ident);
986 if (bind(sndsock6, (struct sockaddr *)pr->from,
987 sizeof (struct sockaddr_in6)) < 0) {
988 Fprintf(stderr, "%s: bind: %s\n", prog,
989 strerror(errno));
990 exit(EXIT_FAILURE);
993 whereto6.sin6_flowinfo = htonl((class << 20) | flow);
995 *alp = al;
996 return (num_ifs);
1000 * Returns the complete ifaddrlist structure matching the desired interface
1001 * address. Ignores interfaces which are either down or loopback.
1003 static struct ifaddrlist *
1004 find_ifaddr(struct ifaddrlist *al, int len, union any_in_addr *addr,
1005 int family)
1007 struct ifaddrlist *tmp_al = al;
1008 int i;
1009 size_t addr_len = (family == AF_INET) ? sizeof (struct in_addr) :
1010 sizeof (struct in6_addr);
1012 for (i = 0; i < len; i++, tmp_al++) {
1013 if ((!(tmp_al->flags & IFF_LOOPBACK) &&
1014 (tmp_al->flags & IFF_UP)) &&
1015 (memcmp(&tmp_al->addr, addr, addr_len) == 0))
1016 break;
1019 if (i < len) {
1020 return (tmp_al);
1021 } else {
1022 return (NULL);
1027 * Returns the complete ifaddrlist structure matching the desired interface name
1028 * Ignores interfaces which are either down or loopback.
1030 static struct ifaddrlist *
1031 find_device(struct ifaddrlist *al, int len, char *device)
1033 struct ifaddrlist *tmp_al = al;
1034 int i;
1036 for (i = 0; i < len; i++, tmp_al++) {
1037 if ((!(tmp_al->flags & IFF_LOOPBACK) &&
1038 (tmp_al->flags & IFF_UP)) &&
1039 (strcmp(tmp_al->device, device) == 0))
1040 break;
1043 if (i < len) {
1044 return (tmp_al);
1045 } else {
1046 return (NULL);
1051 * returns _B_TRUE if given hostinfo contains the given address
1053 static boolean_t
1054 has_addr(struct addrinfo *ai, union any_in_addr *addr)
1056 struct addrinfo *ai_tmp = NULL;
1057 union any_in_addr *ap;
1059 for (ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
1060 if (ai_tmp->ai_family == AF_INET6)
1061 continue;
1062 ap = (union any_in_addr *)
1063 /* LINTED E_BAD_PTR_CAST_ALIGN */
1064 &((struct sockaddr_in *)ai_tmp->ai_addr)->sin_addr;
1065 if (memcmp(ap, addr, sizeof (struct in_addr)) == 0)
1066 break;
1069 if (ai_tmp != NULL) {
1070 return (_B_TRUE);
1071 } else {
1072 return (_B_FALSE);
1077 * Resolve the gateway names, splitting results into v4 and v6 lists.
1078 * Gateway addresses are added to the appropriate passed-in array; the
1079 * number of resolved gateways for each af is returned in resolved[6].
1080 * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
1081 * and resolved[6] ptrs are non-null; ignores array and counter if the
1082 * address family param makes them irrelevant.
1084 static void
1085 get_gwaddrs(char **gwlist, int family, union any_in_addr *gwIPlist,
1086 union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
1088 int i;
1089 boolean_t check_v4 = _B_TRUE, check_v6 = _B_TRUE;
1090 struct addrinfo *ai = NULL;
1091 struct addrinfo *aip = NULL;
1093 *resolved = *resolved6 = 0;
1094 switch (family) {
1095 case AF_UNSPEC:
1096 break;
1097 case AF_INET:
1098 check_v6 = _B_FALSE;
1099 break;
1100 case AF_INET6:
1101 check_v4 = _B_FALSE;
1102 break;
1103 default:
1104 return;
1107 if (check_v4 && gw_count >= MAX_GWS) {
1108 check_v4 = _B_FALSE;
1109 Fprintf(stderr, "%s: too many IPv4 gateways\n", prog);
1110 num_v4 = 0;
1112 if (check_v6 && gw_count >= MAX_GWS6) {
1113 check_v6 = _B_FALSE;
1114 Fprintf(stderr, "%s: too many IPv6 gateways\n", prog);
1115 num_v6 = 0;
1118 for (i = 0; i < gw_count; i++) {
1119 if (!check_v4 && !check_v6)
1120 return;
1121 get_hostinfo(gwlist[i], family, &ai);
1122 if (ai == NULL)
1123 return;
1124 if (check_v4 && num_v4 != 0) {
1125 check_v4 = _B_FALSE;
1126 for (aip = ai; aip != NULL; aip = aip->ai_next) {
1127 if (aip->ai_family == AF_INET) {
1128 /* LINTED E_BAD_PTR_CAST_ALIGN */
1129 bcopy(&((struct sockaddr_in *)
1130 aip->ai_addr)->sin_addr,
1131 &gwIPlist[i].addr,
1132 aip->ai_addrlen);
1133 (*resolved)++;
1134 check_v4 = _B_TRUE;
1135 break;
1138 } else if (check_v4) {
1139 check_v4 = _B_FALSE;
1141 if (check_v6 && num_v6 != 0) {
1142 check_v6 = _B_FALSE;
1143 for (aip = ai; aip != NULL; aip = aip->ai_next) {
1144 if (aip->ai_family == AF_INET6) {
1145 /* LINTED E_BAD_PTR_CAST_ALIGN */
1146 bcopy(&((struct sockaddr_in6 *)
1147 aip->ai_addr)->sin6_addr,
1148 &gwIPlist6[i].addr6,
1149 aip->ai_addrlen);
1150 (*resolved6)++;
1151 check_v6 = _B_TRUE;
1152 break;
1155 } else if (check_v6) {
1156 check_v6 = _B_FALSE;
1159 freeaddrinfo(ai);
1163 * set protocol specific values here
1165 static void
1166 setup_protocol(struct pr_set *pr, int family)
1169 * Set the global variables for each AF. This is going to save us lots
1170 * of "if (family == AF_INET)... else .."
1172 pr->family = family;
1174 if (family == AF_INET) {
1175 if (!docksum) {
1176 Fprintf(stderr,
1177 "%s: Warning: checksums disabled\n", prog);
1179 (void) strcpy(pr->name, "IPv4");
1180 (void) strcpy(pr->icmp, "icmp");
1181 pr->icmp_minlen = ICMP_MINLEN;
1182 pr->addr_len = sizeof (struct in_addr);
1183 pr->ip_hdr_len = sizeof (struct ip);
1184 pr->sock_size = sizeof (struct sockaddr_in);
1185 pr->to = (struct sockaddr *)&whereto;
1186 pr->from = (struct sockaddr *)&wherefrom;
1187 pr->from_sin_addr = (void *)&wherefrom.sin_addr;
1188 pr->gwIPlist = gwIPlist;
1189 pr->set_buffers_fn = set_buffers;
1190 pr->check_reply_fn = check_reply;
1191 pr->print_icmp_other_fn = print_icmp_other;
1192 pr->print_addr_fn = print_addr;
1193 pr->packlen = calc_packetlen(packlen_input, pr);
1194 } else {
1195 (void) strcpy(pr->name, "IPv6");
1196 (void) strcpy(pr->icmp, "ipv6-icmp");
1197 pr->icmp_minlen = ICMP6_MINLEN;
1198 pr->addr_len = sizeof (struct in6_addr);
1199 pr->ip_hdr_len = sizeof (struct ip6_hdr);
1200 pr->sock_size = sizeof (struct sockaddr_in6);
1201 pr->to = (struct sockaddr *)&whereto6;
1202 pr->from = (struct sockaddr *)&wherefrom6;
1203 pr->from_sin_addr = (void *)&wherefrom6.sin6_addr;
1204 pr->gwIPlist = gwIP6list;
1205 pr->set_buffers_fn = set_buffers6;
1206 pr->check_reply_fn = check_reply6;
1207 pr->print_icmp_other_fn = print_icmp_other6;
1208 pr->print_addr_fn = print_addr6;
1209 pr->packlen = calc_packetlen(packlen_input, pr);
1211 if (pr->packlen == 0)
1212 exit(EXIT_FAILURE);
1216 * setup the sockets for the given protocol's address family
1218 static void
1219 setup_socket(struct pr_set *pr, int packet_len)
1221 int on = 1;
1222 struct protoent *pe;
1223 int type;
1224 int proto;
1225 int int_op;
1226 int rsock;
1227 int ssock;
1229 if ((pe = getprotobyname(pr->icmp)) == NULL) {
1230 Fprintf(stderr, "%s: unknown protocol %s\n", prog, pr->icmp);
1231 exit(EXIT_FAILURE);
1234 /* privilege bracketing */
1235 (void) __priv_bracket(PRIV_ON);
1237 if ((rsock = socket(pr->family, SOCK_RAW, pe->p_proto)) < 0) {
1238 Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
1239 exit(EXIT_FAILURE);
1242 if (options & SO_DEBUG) {
1243 if (setsockopt(rsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1244 sizeof (on)) < 0) {
1245 Fprintf(stderr, "%s: SO_DEBUG: %s\n", prog,
1246 strerror(errno));
1247 exit(EXIT_FAILURE);
1250 if (options & SO_DONTROUTE) {
1251 if (setsockopt(rsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1252 sizeof (on)) < 0) {
1253 Fprintf(stderr, "%s: SO_DONTROUTE: %s\n", prog,
1254 strerror(errno));
1255 exit(EXIT_FAILURE);
1259 if (pr->family == AF_INET6) {
1260 /* Enable receipt of destination address info */
1261 if (setsockopt(rsock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
1262 (char *)&on, sizeof (on)) < 0) {
1263 Fprintf(stderr, "%s: IPV6_RECVPKTINFO: %s\n", prog,
1264 strerror(errno));
1265 exit(EXIT_FAILURE);
1267 /* Enable receipt of hoplimit info */
1268 if (setsockopt(rsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
1269 (char *)&on, sizeof (on)) < 0) {
1270 Fprintf(stderr, "%s: IPV6_RECVHOPLIMIT: %s\n", prog,
1271 strerror(errno));
1272 exit(EXIT_FAILURE);
1278 * Initialize the socket type and protocol based on the address
1279 * family, whether or not a raw IP socket is required (for IPv4)
1280 * or whether ICMP will be used instead of UDP.
1282 * For historical reasons, the datagrams sent out by
1283 * traceroute(1M) do not have the "don't fragment" flag set. For
1284 * this reason as well as the ability to set the Loose Source and
1285 * Record Route (LSRR) option, a raw IP socket will be used for
1286 * IPv4 when run in the global zone. Otherwise, the actual
1287 * datagram that will be sent will be a regular UDP or ICMP echo
1288 * request packet. However for convenience and for future options
1289 * when other IP header information may be specified using
1290 * traceroute, the buffer including the raw IP and UDP or ICMP
1291 * header is always filled in. When the probe is actually sent,
1292 * the size of the request and the start of the packet is set
1293 * according to the type of datagram to send.
1295 if (pr->family == AF_INET && raw_req) {
1296 type = SOCK_RAW;
1297 proto = IPPROTO_RAW;
1298 } else if (useicmp) {
1299 type = SOCK_RAW;
1300 if (pr->family == AF_INET)
1301 proto = IPPROTO_ICMP;
1302 else
1303 proto = IPPROTO_ICMPV6;
1304 } else {
1305 type = SOCK_DGRAM;
1306 proto = IPPROTO_UDP;
1308 ssock = socket(pr->family, type, proto);
1310 if (ssock < 0) {
1311 if (proto == IPPROTO_RAW) {
1312 Fprintf(stderr, "%s: raw socket: %s\n", prog,
1313 strerror(errno));
1314 } else if (proto == IPPROTO_UDP) {
1315 Fprintf(stderr, "%s: udp socket: %s\n", prog,
1316 strerror(errno));
1317 } else {
1318 Fprintf(stderr, "%s: icmp socket: %s\n", prog,
1319 strerror(errno));
1321 exit(EXIT_FAILURE);
1324 if (setsockopt(ssock, SOL_SOCKET, SO_SNDBUF, (char *)&packet_len,
1325 sizeof (packet_len)) < 0) {
1326 Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
1327 exit(EXIT_FAILURE);
1330 if (pr->family == AF_INET && raw_req) {
1331 if (setsockopt(ssock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1332 sizeof (on)) < 0) {
1333 Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog,
1334 strerror(errno));
1335 exit(EXIT_FAILURE);
1339 if (options & SO_DEBUG) {
1340 if (setsockopt(ssock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1341 sizeof (on)) < 0) {
1342 Fprintf(stderr, "%s: SO_DEBUG: %s\n", prog,
1343 strerror(errno));
1344 exit(EXIT_FAILURE);
1347 if (options & SO_DONTROUTE) {
1348 if (setsockopt(ssock, SOL_SOCKET, SO_DONTROUTE,
1349 (char *)&on, sizeof (on)) < 0) {
1350 Fprintf(stderr, "%s: SO_DONTROUTE: %s\n", prog,
1351 strerror(errno));
1352 exit(EXIT_FAILURE);
1357 * If a raw IPv4 packet is going to be sent, the Type of Service
1358 * field in the packet will be initialized in set_buffers().
1359 * Otherwise, it is initialized here using the IPPROTO_IP level
1360 * socket option.
1362 if (settos && !raw_req) {
1363 int_op = tos;
1364 if (setsockopt(ssock, IPPROTO_IP, IP_TOS, (char *)&int_op,
1365 sizeof (int_op)) < 0) {
1366 Fprintf(stderr, "%s: IP_TOS: %s\n", prog,
1367 strerror(errno));
1368 exit(EXIT_FAILURE);
1371 if (pr->family == AF_INET) {
1372 rcvsock4 = rsock;
1373 sndsock4 = ssock;
1374 } else {
1375 rcvsock6 = rsock;
1376 sndsock6 = ssock;
1378 /* Revert to non-privileged user after configuring sockets */
1379 (void) __priv_bracket(PRIV_OFF);
1383 * If we are "probing all", this function calls traceroute() for each IP address
1384 * of the target, otherwise calls only once. Returns _B_FALSE if traceroute()
1385 * fails.
1387 static void
1388 trace_it(struct addrinfo *ai_dst)
1390 struct msghdr msg6;
1391 int num_dst_IPaddrs;
1392 struct addrinfo *aip;
1393 int i;
1395 if (!probe_all)
1396 num_dst_IPaddrs = 1;
1397 else
1398 num_dst_IPaddrs = num_v4 + num_v6;
1401 * Initialize the msg6 structure using the hoplimit for the first
1402 * probe packet, gateway addresses and the outgoing interface index.
1404 if (ai_dst->ai_family == AF_INET6 || (probe_all && num_v6)) {
1405 msg6.msg_control = NULL;
1406 msg6.msg_controllen = 0;
1407 set_ancillary_data(&msg6, first_ttl, pr6->gwIPlist, gw_count,
1408 if_index);
1411 /* run traceroute for all the IP addresses of the multihomed dest */
1412 for (aip = ai_dst, i = 0; i < num_dst_IPaddrs && aip != NULL; i++) {
1413 union any_in_addr *addrp;
1414 if (aip->ai_family == AF_INET) {
1415 addrp = (union any_in_addr *)
1416 /* LINTED E_BAD_PTR_CAST_ALIGN */
1417 &((struct sockaddr_in *)
1418 aip->ai_addr)->sin_addr;
1419 set_sin((struct sockaddr *)pr4->to, addrp,
1420 aip->ai_family);
1421 traceroute(addrp, &msg6, pr4, num_ifs4, al4);
1422 } else {
1423 addrp = (union any_in_addr *)
1424 /* LINTED E_BAD_PTR_CAST_ALIGN */
1425 &((struct sockaddr_in6 *)
1426 aip->ai_addr)->sin6_addr;
1427 set_sin((struct sockaddr *)pr6->to, addrp,
1428 aip->ai_family);
1429 traceroute(addrp, &msg6, pr6, num_ifs6, al6);
1431 aip = aip->ai_next;
1432 if (i < (num_dst_IPaddrs - 1))
1433 (void) putchar('\n');
1438 * set the IP address in a sockaddr struct
1440 static void
1441 set_sin(struct sockaddr *sock, union any_in_addr *addr, int family)
1443 sock->sa_family = family;
1445 if (family == AF_INET)
1446 /* LINTED E_BAD_PTR_CAST_ALIGN */
1447 ((struct sockaddr_in *)sock)->sin_addr = addr->addr;
1448 else
1449 /* LINTED E_BAD_PTR_CAST_ALIGN */
1450 ((struct sockaddr_in6 *)sock)->sin6_addr = addr->addr6;
1454 * returns the IF name on which the given IP address is configured
1456 static char *
1457 device_name(struct ifaddrlist *al, int len, union any_in_addr *ip_addr,
1458 struct pr_set *pr)
1460 int i;
1461 struct ifaddrlist *tmp_al;
1463 tmp_al = al;
1465 for (i = 0; i < len; i++, tmp_al++) {
1466 if (memcmp(&tmp_al->addr, ip_addr, pr->addr_len) == 0) {
1467 return (tmp_al->device);
1471 return (NULL);
1475 * Trace the route to the host with given IP address.
1477 static void
1478 traceroute(union any_in_addr *ip_addr, struct msghdr *msg6, struct pr_set *pr,
1479 int num_ifs, struct ifaddrlist *al)
1481 int ttl;
1482 int probe;
1483 uchar_t type; /* icmp type */
1484 uchar_t code; /* icmp code */
1485 int reply;
1486 int seq = 0;
1487 char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */
1488 int longjmp_return; /* return value from longjump */
1489 struct ip *ip = (struct ip *)packet;
1490 boolean_t got_there = _B_FALSE; /* we hit the destination */
1491 static boolean_t first_pkt = _B_TRUE;
1492 int hoplimit; /* hoplimit for IPv6 packets */
1493 struct in6_addr addr6;
1494 int num_src_ifs; /* excludes down and loopback */
1495 struct msghdr in_msg;
1496 struct iovec iov;
1497 int *intp;
1498 int sndsock;
1499 int rcvsock;
1501 msg6->msg_name = pr->to;
1502 msg6->msg_namelen = sizeof (struct sockaddr_in6);
1503 sndsock = (pr->family == AF_INET) ? sndsock4 : sndsock6;
1504 rcvsock = (pr->family == AF_INET) ? rcvsock4 : rcvsock6;
1506 /* carry out the source address selection */
1507 if (pick_src) {
1508 union any_in_addr src_addr;
1509 char *dev_name;
1510 int i;
1513 * If there's a gateway, a routing header as a consequence, our
1514 * kernel picks the source address based on the first hop
1515 * address, rather than final destination address.
1517 if (gw_count > 0) {
1518 (void) select_src_addr(pr->gwIPlist, &src_addr,
1519 pr->family);
1520 } else {
1521 (void) select_src_addr(ip_addr, &src_addr, pr->family);
1523 set_sin(pr->from, &src_addr, pr->family);
1525 /* filter out down and loopback interfaces */
1526 num_src_ifs = 0;
1527 for (i = 0; i < num_ifs; i++) {
1528 if (!(al[i].flags & IFF_LOOPBACK) &&
1529 (al[i].flags & IFF_UP))
1530 num_src_ifs++;
1533 if (num_src_ifs > 1) {
1534 dev_name = device_name(al, num_ifs, &src_addr, pr);
1535 if (dev_name == NULL)
1536 dev_name = "?";
1538 Fprintf(stderr,
1539 "%s: Warning: Multiple interfaces found;"
1540 " using %s @ %s\n",
1541 prog, inet_ntop(pr->family,
1542 (const void *)pr->from_sin_addr,
1543 temp_buf, sizeof (temp_buf)),
1544 dev_name);
1548 if (pr->family == AF_INET) {
1549 outip4->ip_src = *(struct in_addr *)pr->from_sin_addr;
1550 outip4->ip_dst = ip_addr->addr;
1554 * If the hostname is an IPv6 literal address, let's not print it twice.
1556 if (pr->family == AF_INET6 &&
1557 inet_pton(AF_INET6, hostname, &addr6) > 0) {
1558 Fprintf(stderr, "%s to %s", prog, hostname);
1559 } else {
1560 Fprintf(stderr, "%s to %s (%s)", prog, hostname,
1561 inet_ntop(pr->family, (const void *)ip_addr, temp_buf,
1562 sizeof (temp_buf)));
1565 if (source)
1566 Fprintf(stderr, " from %s", source);
1567 Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl,
1568 pr->packlen);
1569 (void) fflush(stderr);
1572 * Setup the source routing for IPv4. For IPv6, we did the required
1573 * setup in the caller function, trace_it(), because it's independent
1574 * from the IP address of target.
1576 if (pr->family == AF_INET && gw_count > 0)
1577 set_IPv4opt_sourcerouting(sndsock, ip_addr, pr->gwIPlist);
1579 if (probe_all) {
1580 /* interrupt handler sig_handler() jumps back to here */
1581 if ((longjmp_return = setjmp(env)) != 0) {
1582 switch (longjmp_return) {
1583 case SIGINT:
1584 Printf("(skipping)\n");
1585 return;
1586 case SIGQUIT:
1587 Printf("(exiting)\n");
1588 exit(EXIT_SUCCESS);
1589 default: /* should never happen */
1590 exit(EXIT_FAILURE);
1593 (void) signal(SIGINT, sig_handler);
1596 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1597 union any_in_addr lastaddr;
1598 int timeouts = 0;
1599 double rtt; /* for statistics */
1600 int nreceived = 0;
1601 double rttmin, rttmax;
1602 double rttsum, rttssq;
1603 int unreachable;
1605 got_there = _B_FALSE;
1606 unreachable = 0;
1609 * The following line clears both IPv4 and IPv6 address stored
1610 * in the union.
1612 lastaddr.addr6 = in6addr_any;
1614 if ((ttl == (first_ttl + 1)) && (options & SO_DONTROUTE)) {
1615 Fprintf(stderr,
1616 "%s: host %s is not on a directly-attached"
1617 " network\n", prog, hostname);
1618 break;
1621 Printf("%2d ", ttl);
1622 (void) fflush(stdout);
1624 for (probe = 0; (probe < nprobes) && (timeouts < max_timeout);
1625 ++probe) {
1626 int cc;
1627 struct timeval t1, t2;
1630 * Put a delay before sending this probe packet. Don't
1631 * delay it if it's the very first packet.
1633 if (!first_pkt) {
1634 if (delay.tv_sec > 0)
1635 (void) sleep((uint_t)delay.tv_sec);
1636 if (delay.tv_usec > 0)
1637 (void) usleep(delay.tv_usec);
1638 } else {
1639 first_pkt = _B_FALSE;
1642 (void) gettimeofday(&t1, NULL);
1644 if (pr->family == AF_INET) {
1645 send_probe(sndsock, pr->to, outip4, seq, ttl,
1646 &t1, pr->packlen);
1647 } else {
1648 send_probe6(sndsock, msg6, outip6, seq, ttl,
1649 &t1, pr->packlen);
1652 /* prepare msghdr for recvmsg() */
1653 in_msg.msg_name = pr->from;
1654 in_msg.msg_namelen = pr->sock_size;
1656 iov.iov_base = (char *)packet;
1657 iov.iov_len = sizeof (packet);
1659 in_msg.msg_iov = &iov;
1660 in_msg.msg_iovlen = 1;
1662 in_msg.msg_control = ancillary_data;
1663 in_msg.msg_controllen = sizeof (ancillary_data);
1665 while ((cc = wait_for_reply(rcvsock, &in_msg,
1666 &t1)) != 0) {
1667 (void) gettimeofday(&t2, NULL);
1669 reply = (*pr->check_reply_fn) (&in_msg, cc, seq,
1670 &type, &code);
1672 in_msg.msg_controllen =
1673 sizeof (ancillary_data);
1674 /* Skip short packet */
1675 if (reply == REPLY_SHORT_PKT) {
1676 continue;
1679 timeouts = 0;
1682 * if reply comes from a different host, print
1683 * the hostname
1685 if (memcmp(pr->from_sin_addr, &lastaddr,
1686 pr->addr_len) != 0) {
1687 (*pr->print_addr_fn) ((uchar_t *)packet,
1688 cc, pr->from);
1689 /* store the address response */
1690 (void) memcpy(&lastaddr,
1691 pr->from_sin_addr, pr->addr_len);
1694 rtt = deltaT(&t1, &t2);
1695 if (collect_stat) {
1696 record_stats(rtt, &nreceived, &rttmin,
1697 &rttmax, &rttsum, &rttssq);
1698 } else {
1699 Printf(" %.3f ms", rtt);
1702 if (pr->family == AF_INET6) {
1703 intp =
1704 (int *)find_ancillary_data(&in_msg,
1705 IPPROTO_IPV6, IPV6_HOPLIMIT);
1706 if (intp == NULL) {
1707 Fprintf(stderr,
1708 "%s: can't find "
1709 "IPV6_HOPLIMIT ancillary "
1710 "data\n", prog);
1711 exit(EXIT_FAILURE);
1713 hoplimit = *intp;
1716 if (reply == REPLY_GOT_TARGET) {
1717 got_there = _B_TRUE;
1719 if (((pr->family == AF_INET) &&
1720 (ip->ip_ttl <= 1)) ||
1721 ((pr->family == AF_INET6) &&
1722 (hoplimit <= 1)))
1723 Printf(" !");
1726 if (!collect_stat && showttl) {
1727 if (pr->family == AF_INET) {
1728 Printf(" (ttl=%d)",
1729 (int)ip->ip_ttl);
1730 } else if (hoplimit != -1) {
1731 Printf(" (hop limit=%d)",
1732 hoplimit);
1736 if (reply == REPLY_GOT_OTHER) {
1737 if ((*pr->print_icmp_other_fn)
1738 (type, code)) {
1739 unreachable++;
1743 /* special case */
1744 if (pr->family == AF_INET &&
1745 type == ICMP_UNREACH &&
1746 code == ICMP_UNREACH_PROTOCOL)
1747 got_there = _B_TRUE;
1749 break;
1752 seq = (seq + 1) % (MAX_SEQ + 1);
1754 if (cc == 0) {
1755 Printf(" *");
1756 timeouts++;
1759 (void) fflush(stdout);
1762 if (collect_stat) {
1763 print_stats(probe, nreceived, rttmin, rttmax, rttsum,
1764 rttssq);
1767 (void) putchar('\n');
1769 /* either we hit the target or received too many unreachables */
1770 if (got_there ||
1771 (unreachable > 0 && unreachable >= nprobes - 1))
1772 break;
1775 /* Ignore the SIGINT between traceroute() runs */
1776 if (probe_all)
1777 (void) signal(SIGINT, SIG_IGN);
1781 * for a given destination address and address family, it finds out what
1782 * source address kernel is going to pick
1784 static void
1785 select_src_addr(union any_in_addr *dst_addr, union any_in_addr *src_addr,
1786 int family)
1788 int tmp_fd;
1789 struct sockaddr *sock;
1790 struct sockaddr_in *sin;
1791 struct sockaddr_in6 *sin6;
1792 size_t sock_len;
1794 sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
1795 if (sock == NULL) {
1796 Fprintf(stderr, "%s: malloc %s\n", prog, strerror(errno));
1797 exit(EXIT_FAILURE);
1799 (void) bzero(sock, sizeof (struct sockaddr_in6));
1801 if (family == AF_INET) {
1802 /* LINTED E_BAD_PTR_CAST_ALIGN */
1803 sin = (struct sockaddr_in *)sock;
1804 sin->sin_family = AF_INET;
1805 sin->sin_addr = dst_addr->addr;
1806 sin->sin_port = IPPORT_ECHO; /* port shouldn't be 0 */
1807 sock_len = sizeof (struct sockaddr_in);
1808 } else {
1809 /* LINTED E_BAD_PTR_CAST_ALIGN */
1810 sin6 = (struct sockaddr_in6 *)sock;
1811 sin6->sin6_family = AF_INET6;
1812 sin6->sin6_addr = dst_addr->addr6;
1813 sin6->sin6_port = IPPORT_ECHO; /* port shouldn't be 0 */
1814 sock_len = sizeof (struct sockaddr_in6);
1817 /* open a UDP socket */
1818 if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
1819 Fprintf(stderr, "%s: udp socket: %s\n", prog,
1820 strerror(errno));
1821 exit(EXIT_FAILURE);
1824 /* connect it */
1825 if (connect(tmp_fd, sock, sock_len) < 0) {
1827 * If there's no route to the destination, this connect() call
1828 * fails. We just return all-zero (wildcard) as the source
1829 * address, so that user can get to see "no route to dest"
1830 * message, as it'll try to send the probe packet out and will
1831 * receive ICMP unreachable.
1833 if (family == AF_INET)
1834 src_addr->addr.s_addr = INADDR_ANY;
1835 else
1836 src_addr->addr6 = in6addr_any;
1837 free(sock);
1838 return;
1841 /* get the local sock info */
1842 if (getsockname(tmp_fd, sock, &sock_len) < 0) {
1843 Fprintf(stderr, "%s: getsockname: %s\n", prog,
1844 strerror(errno));
1845 exit(EXIT_FAILURE);
1848 if (family == AF_INET) {
1849 /* LINTED E_BAD_PTR_CAST_ALIGN */
1850 sin = (struct sockaddr_in *)sock;
1851 src_addr->addr = sin->sin_addr;
1852 } else {
1853 /* LINTED E_BAD_PTR_CAST_ALIGN */
1854 sin6 = (struct sockaddr_in6 *)sock;
1855 src_addr->addr6 = sin6->sin6_addr;
1858 free(sock);
1859 (void) close(tmp_fd);
1863 * Checksum routine for Internet Protocol family headers (C Version)
1865 ushort_t
1866 in_cksum(ushort_t *addr, int len)
1868 int nleft = len;
1869 ushort_t *w = addr;
1870 ushort_t answer;
1871 int sum = 0;
1874 * Our algorithm is simple, using a 32 bit accumulator (sum),
1875 * we add sequential 16 bit words to it, and at the end, fold
1876 * back all the carry bits from the top 16 bits into the lower
1877 * 16 bits.
1879 while (nleft > 1) {
1880 sum += *w++;
1881 nleft -= 2;
1884 /* mop up an odd byte, if necessary */
1885 if (nleft == 1)
1886 sum += *(uchar_t *)w;
1888 /* add back carry outs from top 16 bits to low 16 bits */
1889 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1890 sum += (sum >> 16); /* add carry */
1891 answer = ~sum; /* truncate to 16 bits */
1892 return (answer);
1896 * Wait until a reply arrives or timeout occurs. If packet arrived, read it
1897 * return the size of the packet read.
1899 static int
1900 wait_for_reply(int sock, struct msghdr *msg, struct timeval *tp)
1902 fd_set fds;
1903 struct timeval now, wait;
1904 int cc = 0;
1905 int result;
1907 (void) FD_ZERO(&fds);
1908 FD_SET(sock, &fds);
1910 wait.tv_sec = tp->tv_sec + waittime;
1911 wait.tv_usec = tp->tv_usec;
1912 (void) gettimeofday(&now, NULL);
1913 tv_sub(&wait, &now);
1915 if (wait.tv_sec < 0 || wait.tv_usec < 0)
1916 return (0);
1918 result = select(sock + 1, &fds, (fd_set *)NULL, (fd_set *)NULL, &wait);
1920 if (result == -1) {
1921 if (errno != EINTR) {
1922 Fprintf(stderr, "%s: select: %s\n", prog,
1923 strerror(errno));
1925 } else if (result > 0)
1926 cc = recvmsg(sock, msg, 0);
1928 return (cc);
1932 * Construct an Internet address representation. If the nflag has been supplied,
1933 * give numeric value, otherwise try for symbolic name.
1935 char *
1936 inet_name(union any_in_addr *in, int family)
1938 char *cp;
1939 static boolean_t first = _B_TRUE;
1940 static char domain[NI_MAXHOST + 1];
1941 static char line[NI_MAXHOST + 1]; /* assuming */
1942 /* (NI_MAXHOST + 1) >= INET6_ADDRSTRLEN */
1943 char hbuf[NI_MAXHOST];
1944 socklen_t slen;
1945 struct sockaddr_in sin;
1946 struct sockaddr_in6 sin6;
1947 struct sockaddr *sa;
1948 int flags;
1950 switch (family) {
1951 case AF_INET:
1952 slen = sizeof (struct sockaddr_in);
1953 sin.sin_addr = in->addr;
1954 sin.sin_port = 0;
1955 sa = (struct sockaddr *)&sin;
1956 break;
1957 case AF_INET6:
1958 slen = sizeof (struct sockaddr_in6);
1959 sin6.sin6_addr = in->addr6;
1960 sin6.sin6_port = 0;
1961 sin6.sin6_scope_id = 0;
1962 sa = (struct sockaddr *)&sin6;
1963 break;
1964 default:
1965 (void) snprintf(line, sizeof (line),
1966 "<invalid address family>");
1967 return (line);
1969 sa->sa_family = family;
1971 if (first && !nflag) {
1972 /* find out the domain name */
1973 first = _B_FALSE;
1974 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1975 (cp = strchr(domain, '.')) != NULL) {
1976 (void) strncpy(domain, cp + 1, sizeof (domain) - 1);
1977 domain[sizeof (domain) - 1] = '\0';
1978 } else {
1979 domain[0] = '\0';
1983 flags = (nflag) ? NI_NUMERICHOST : NI_NAMEREQD;
1984 if (getnameinfo(sa, slen, hbuf, sizeof (hbuf), NULL, 0, flags) != 0) {
1985 if (inet_ntop(family, (const void *)&in->addr6,
1986 hbuf, sizeof (hbuf)) == NULL)
1987 hbuf[0] = 0;
1988 } else if (!nflag && (cp = strchr(hbuf, '.')) != NULL &&
1989 strcmp(cp + 1, domain) == 0) {
1990 *cp = '\0';
1992 (void) strlcpy(line, hbuf, sizeof (line));
1994 return (line);
1998 * return the difference (in msec) between two time values
2000 static double
2001 deltaT(struct timeval *t1p, struct timeval *t2p)
2003 double dt;
2005 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
2006 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
2007 return (dt);
2011 * Subtract 2 timeval structs: out = out - in.
2012 * Out is assumed to be >= in.
2014 static void
2015 tv_sub(struct timeval *out, struct timeval *in)
2017 if ((out->tv_usec -= in->tv_usec) < 0) {
2018 --out->tv_sec;
2019 out->tv_usec += 1000000;
2021 out->tv_sec -= in->tv_sec;
2025 * record statistics
2027 static void
2028 record_stats(double rtt, int *nreceived, double *rttmin, double *rttmax,
2029 double *rttsum, double *rttssq)
2031 if (*nreceived == 0) {
2032 *rttmin = rtt;
2033 *rttmax = rtt;
2034 *rttsum = rtt;
2035 *rttssq = rtt * rtt;
2036 } else {
2037 if (rtt < *rttmin)
2038 *rttmin = rtt;
2040 if (rtt > *rttmax)
2041 *rttmax = rtt;
2043 *rttsum += rtt;
2044 *rttssq += rtt * rtt;
2047 (*nreceived)++;
2051 * display statistics
2053 static void
2054 print_stats(int ntransmitted, int nreceived, double rttmin, double rttmax,
2055 double rttsum, double rttssq)
2057 double rttavg; /* average round-trip time */
2058 double rttstd; /* rtt standard deviation */
2060 if (ntransmitted > 0 && ntransmitted >= nreceived) {
2061 int missed = ntransmitted - nreceived;
2062 double loss = 100 * (double)missed / (double)ntransmitted;
2064 if (nreceived > 0) {
2065 rttavg = rttsum / nreceived;
2066 rttstd = rttssq - (rttavg * rttsum);
2067 rttstd = xsqrt(rttstd / nreceived);
2069 Printf(" %.3f", rttmin);
2070 Printf("/%.3f", rttavg);
2071 Printf("/%.3f", rttmax);
2073 Printf(" (%.3f) ms ", rttstd);
2076 Printf(" %d/%d pkts", nreceived, ntransmitted);
2078 if (nreceived == 0)
2079 Printf(" (100%% loss)");
2080 else
2081 Printf(" (%.2g%% loss)", loss);
2086 * square root function
2088 double
2089 xsqrt(double y)
2091 double t, x;
2093 if (y <= 0) {
2094 return (0.0);
2097 x = (y < 1.0) ? 1.0 : y;
2098 do {
2099 t = x;
2100 x = (t + (y/t))/2.0;
2101 } while (0 < x && x < t);
2103 return (x);
2107 * String to double with optional min and max.
2109 static double
2110 str2dbl(const char *str, const char *what, double mi, double ma)
2112 double val;
2113 char *ep;
2115 errno = 0;
2117 val = strtod(str, &ep);
2118 if (errno != 0 || *ep != '\0') {
2119 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
2120 prog, str, what);
2121 exit(EXIT_FAILURE);
2123 if (val < mi && mi >= 0) {
2124 Fprintf(stderr, "%s: %s must be >= %f\n", prog, what, mi);
2125 exit(EXIT_FAILURE);
2127 if (val > ma && ma >= 0) {
2128 Fprintf(stderr, "%s: %s must be <= %f\n", prog, what, ma);
2129 exit(EXIT_FAILURE);
2131 return (val);
2135 * String to int with optional min and max. Handles decimal and hex.
2137 static int
2138 str2int(const char *str, const char *what, int mi, int ma)
2140 const char *cp;
2141 int val;
2142 char *ep;
2144 errno = 0;
2146 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
2147 cp = str + 2;
2148 val = (int)strtol(cp, &ep, 16);
2149 } else {
2150 val = (int)strtol(str, &ep, 10);
2152 if (errno != 0 || *ep != '\0') {
2153 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
2154 prog, str, what);
2155 exit(EXIT_FAILURE);
2157 if (val < mi && mi >= 0) {
2158 if (mi == 0) {
2159 Fprintf(stderr, "%s: %s must be >= %d\n",
2160 prog, what, mi);
2161 } else {
2162 Fprintf(stderr, "%s: %s must be > %d\n",
2163 prog, what, mi - 1);
2165 exit(EXIT_FAILURE);
2167 if (val > ma && ma >= 0) {
2168 Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
2169 exit(EXIT_FAILURE);
2171 return (val);
2175 * This is the interrupt handler for SIGINT and SIGQUIT. It's completely handled
2176 * where it jumps to.
2178 static void
2179 sig_handler(int sig)
2181 longjmp(env, sig);
2185 * display the usage of traceroute
2187 static void
2188 usage(void)
2190 Fprintf(stderr, "Usage: %s [-adFIlnSvx] [-A address_family] "
2191 "[-c traffic_class] \n"
2192 "\t[-f first_hop] [-g gateway [-g gateway ...]| -r] [-i iface]\n"
2193 "\t[-L flow_label] [-m max_hop] [-P pause_sec] [-p port] [-Q max_timeout]\n"
2194 "\t[-q nqueries] [-s src_addr] [-t tos] [-w wait_time] host [packetlen]\n",
2195 prog);
2196 exit(EXIT_FAILURE);