dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / traceroute / traceroute.c
blobb8b56259ad8cbe5a1203947dbe4e1dc7055f8d47
1 /*
2 * Copyright 2009 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 #include <sys/param.h>
31 #include <sys/file.h>
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
34 #include <sys/time.h>
35 #include <sys/sysmacros.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip_var.h>
41 #include <netinet/ip_icmp.h>
42 #include <netinet/udp.h>
43 #include <netinet/udp_var.h>
44 #include <netinet/ip6.h>
45 #include <netinet/icmp6.h>
47 #include <arpa/inet.h>
49 #include <ctype.h>
50 #include <errno.h>
51 #include <malloc.h>
52 #include <memory.h>
53 #include <netdb.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <strings.h>
57 #include <unistd.h>
58 #include <libintl.h>
59 #include <locale.h>
60 #include <signal.h>
61 #include <setjmp.h>
62 #include <limits.h>
63 #include <zone.h>
65 #include <priv_utils.h>
67 #include <libinetutil.h>
68 #include "traceroute.h"
70 #define MAX_SEQ 65535 /* max sequence value for ICMP */
71 #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
72 #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
73 #define MAX_TOS 255 /* max type-of-service for IPv4 */
74 #define STR_LEN 30
76 /* store the information about a host */
77 struct hostinfo {
78 char *name; /* hostname */
79 int family; /* address family of the IP addresses */
80 int num_addr; /* number of IP addresses */
81 union any_in_addr *addrs; /* list of IP addresses */
84 /* used to store a bunch of protocol specific values */
85 struct pr_set {
86 int family; /* AF_INET or AF_INET6 */
87 char name[STR_LEN]; /* "IPv4" or "IPv6" */
88 char icmp[STR_LEN]; /* "icmp" or "ipv6-icmp" */
89 int icmp_minlen;
90 int addr_len;
91 int ip_hdr_len;
92 int packlen;
93 int sock_size; /* size of sockaddr_in or sockaddr_in6 */
94 struct sockaddr *to;
95 struct sockaddr *from;
96 void *from_sin_addr;
97 union any_in_addr *gwIPlist;
98 /* pointers to v4/v6 functions */
99 struct ip *(*set_buffers_fn) (int);
100 int (*check_reply_fn)(struct msghdr *, int, int, uchar_t *, uchar_t *);
101 boolean_t (*print_icmp_other_fn)(uchar_t, uchar_t);
102 void (*print_addr_fn)(uchar_t *, int, struct sockaddr *);
107 * LBNL bug fixed: in LBNL traceroute 'uchar_t packet[512];'
108 * Not sufficient to hold the complete packet for ECHO REPLY of a big probe.
109 * Packet size is reported incorrectly in such a case.
110 * Also this buffer needs to be 32 bit aligned. In the future the alignment
111 * requirement will be increased to 64 bit. So, let's use 64 bit alignment now.
113 static uint64_t packet[(IP_MAXPACKET + 1)/8]; /* received packet */
115 static struct ip *outip4; /* output buffer to send as an IPv4 datagram */
116 static struct ip *outip6; /* output buffer to send as an IPv6 datagram */
118 /* Used to store the ancillary data that comes with the received packets */
119 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
121 /* first get the gw names, later you'll resolve them based on the family */
122 static char *gwlist[MAXMAX_GWS]; /* gateway names list */
123 static union any_in_addr gwIPlist[MAX_GWS]; /* gateway IPv4 address list */
124 static union any_in_addr gwIP6list[MAX_GWS6]; /* gateway IPv6 address list */
126 static int family_input = AF_UNSPEC; /* User supplied protocol family */
127 static int rcvsock4; /* receive (icmp) socket file descriptor */
128 static int sndsock4; /* send (udp/icmp) socket file descriptor */
129 static int rcvsock6; /* receive (icmp6) socket file descriptor */
130 static int sndsock6; /* send (udp6/icmp6) socket file descriptor */
131 int gw_count = 0; /* number of gateways */
132 static struct sockaddr_in whereto; /* Who to try to reach */
133 static struct sockaddr_in6 whereto6;
134 static struct sockaddr_in wherefrom; /* Who we are */
135 static struct sockaddr_in6 wherefrom6;
136 static int packlen_input = 0; /* user input for packlen */
138 char *prog;
139 static char *source_input = NULL; /* this is user arg. source, doesn't change */
140 static char *source = NULL; /* this gets modified after name lookup */
141 char *hostname;
142 static char *device = NULL; /* interface name */
143 static struct pr_set *pr4; /* protocol info for IPv4 */
144 static struct pr_set *pr6; /* protocol info for IPv6 */
145 static struct ifaddrlist *al4; /* list of interfaces */
146 static struct ifaddrlist *al6; /* list of interfaces */
147 static uint_t if_index = 0; /* interface index */
148 static int num_v4 = 0; /* count of IPv4 addresses */
149 static int num_v6 = 0; /* count of IPv6 addresses */
150 static int num_ifs4 = 0; /* count of local IPv4 interfaces */
151 static int num_ifs6 = 0; /* count of local IPv6 interfaces */
153 static int nprobes = 3; /* number of probes */
154 static int max_ttl = 30; /* max number of hops */
155 static int first_ttl = 1; /* initial number of hops */
156 ushort_t ident; /* used to authenticate replies */
157 ushort_t port = 32768 + 666; /* start udp dest port # for probe packets */
159 static int options = 0; /* socket options */
160 boolean_t verbose = _B_FALSE; /* verbose output */
161 static int waittime = 5; /* time to wait for response (in seconds) */
162 static struct timeval delay = {0, 0}; /* delay between consecutive probe */
163 boolean_t nflag = _B_FALSE; /* print addresses numerically */
164 static boolean_t showttl = _B_FALSE; /* print the ttl(hop limit) of recvd pkt */
165 boolean_t useicmp = _B_FALSE; /* use icmp echo instead of udp packets */
166 boolean_t docksum = _B_TRUE; /* calculate checksums */
167 static boolean_t collect_stat = _B_FALSE; /* print statistics */
168 boolean_t settos = _B_FALSE; /* set type-of-service field */
169 int dontfrag = 0; /* IP*_DONTFRAG */
170 static int max_timeout = 5; /* quit after this consecutive timeouts */
171 static boolean_t probe_all = _B_FALSE; /* probe all the IFs of the target */
172 static boolean_t pick_src = _B_FALSE; /* traceroute picks the src address */
175 * flow and class are specific to IPv6, tos and off are specific to IPv4.
176 * Each protocol uses the ones that are specific to itself, and ignores
177 * others.
179 static uint_t flow = 0; /* IPv6 flow info */
180 static uint_t class = 0; /* IPv6 class */
181 uchar_t tos = 0; /* IPv4 type-of-service */
182 ushort_t off = 0; /* set DF bit */
184 static jmp_buf env; /* stack environment for longjmp() */
185 boolean_t raw_req; /* if sndsock for IPv4 must be raw */
187 /* Forwards */
188 static uint_t calc_packetlen(int, struct pr_set *);
189 extern int check_reply(struct msghdr *, int, int, uchar_t *, uchar_t *);
190 extern int check_reply6(struct msghdr *, int, int, uchar_t *, uchar_t *);
191 static double deltaT(struct timeval *, struct timeval *);
192 static char *device_name(struct ifaddrlist *, int, union any_in_addr *,
193 struct pr_set *);
194 extern void *find_ancillary_data(struct msghdr *, int, int);
195 static boolean_t has_addr(struct addrinfo *, union any_in_addr *);
196 static struct ifaddrlist *find_device(struct ifaddrlist *, int, char *);
197 static struct ifaddrlist *find_ifaddr(struct ifaddrlist *, int,
198 union any_in_addr *, int);
199 static void get_gwaddrs(char **, int, union any_in_addr *,
200 union any_in_addr *, int *, int *);
201 static void get_hostinfo(char *, int, struct addrinfo **);
202 char *inet_name(union any_in_addr *, int);
203 ushort_t in_cksum(ushort_t *, int);
204 extern int ip_hdr_length_v6(ip6_t *, int, uint8_t *);
205 extern char *pr_type(uchar_t);
206 extern char *pr_type6(uchar_t);
207 extern void print_addr(uchar_t *, int, struct sockaddr *);
208 extern void print_addr6(uchar_t *, int, struct sockaddr *);
209 extern boolean_t print_icmp_other(uchar_t, uchar_t);
210 extern boolean_t print_icmp_other6(uchar_t, uchar_t);
211 static void print_stats(int, int, double, double, double, double);
212 static void print_unknown_host_msg(const char *, const char *);
213 static void record_stats(double, int *, double *, double *, double *, double *);
214 static void resolve_nodes(int *, struct addrinfo **);
215 static void select_src_addr(union any_in_addr *, union any_in_addr *, int);
216 extern void send_probe(int, struct sockaddr *, struct ip *, int, int,
217 struct timeval *, int);
218 extern void send_probe6(int, struct msghdr *, struct ip *, int, int,
219 struct timeval *, int);
220 extern void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int,
221 uint_t);
222 extern struct ip *set_buffers(int);
223 extern struct ip *set_buffers6(int);
224 extern void set_IPv4opt_sourcerouting(int, union any_in_addr *,
225 union any_in_addr *);
226 static void set_sin(struct sockaddr *, union any_in_addr *, int);
227 static int set_src_addr(struct pr_set *, struct ifaddrlist **);
228 static void setup_protocol(struct pr_set *, int);
229 static void setup_socket(struct pr_set *, int);
230 static void sig_handler(int);
231 static int str2int(const char *, const char *, int, int);
232 static double str2dbl(const char *, const char *, double, double);
233 static void trace_it(struct addrinfo *);
234 static void traceroute(union any_in_addr *, struct msghdr *, struct pr_set *,
235 int, struct ifaddrlist *);
236 static void tv_sub(struct timeval *, struct timeval *);
237 static void usage(void);
238 static int wait_for_reply(int, struct msghdr *, struct timeval *);
239 static double xsqrt(double);
242 * main
245 main(int argc, char **argv)
247 struct addrinfo *ai_dst = NULL; /* destination host */
249 * "probing_successful" indicates if we could successfully send probes,
250 * not necessarily received reply from the target (this behavior is from
251 * the original traceroute). It's _B_FALSE if packlen is invalid, or no
252 * interfaces found.
254 boolean_t probing_successful = _B_FALSE;
255 int longjmp_return; /* return value from longjump */
256 int i = 0;
257 char *cp;
258 int op;
259 char *ep;
260 char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */
261 double pause;
264 * A raw socket will be used for IPv4 if there is sufficient
265 * privilege.
267 raw_req = priv_ineffect(PRIV_NET_RAWACCESS);
270 * We'll need the privilege only when we open the sockets; that's
271 * when we'll fail if the program has insufficient privileges.
273 (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
274 raw_req ? PRIV_NET_RAWACCESS : NULL, NULL);
276 (void) setlinebuf(stdout);
278 if ((cp = strrchr(argv[0], '/')) != NULL)
279 prog = cp + 1;
280 else
281 prog = argv[0];
283 opterr = 0;
284 while ((op = getopt(argc, argv, "adFIlnrSvxA:c:f:g:i:L:m:P:p:Q:q:s:"
285 "t:w:")) != EOF) {
286 switch (op) {
287 case 'A':
288 if (strcmp(optarg, "inet") == 0) {
289 family_input = AF_INET;
290 } else if (strcmp(optarg, "inet6") == 0) {
291 family_input = AF_INET6;
292 } else {
293 Fprintf(stderr,
294 "%s: unknown address family %s\n",
295 prog, optarg);
296 exit(EXIT_FAILURE);
298 break;
300 case 'a':
301 probe_all = _B_TRUE;
302 break;
304 case 'c':
305 class = str2int(optarg, "traffic class", 0,
306 MAX_TRAFFIC_CLASS);
307 break;
309 case 'd':
310 options |= SO_DEBUG;
311 break;
313 case 'f':
314 first_ttl = str2int(optarg, "first ttl", 1, MAXTTL);
315 break;
317 case 'F':
318 off = IP_DF;
319 dontfrag = 1;
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 abuf[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, &addr, abuf, sizeof (abuf));
725 /* now the host is an IPv4 address */
726 (void) strcpy(host, abuf);
729 * If it's a mapped address, we convert it into IPv4
730 * address because traceroute will send and receive IPv4
731 * packets for that address. Therefore, it's a failure case to
732 * ask get_hostinfo() to treat a mapped address as an IPv6
733 * address.
735 if (family == AF_INET6) {
736 return;
740 (void) memset(&hints, 0, sizeof (hints));
741 hints.ai_family = family;
742 hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
743 rc = getaddrinfo(host, NULL, &hints, &ai);
744 if (rc != 0) {
745 if (rc != EAI_NONAME)
746 Fprintf(stderr, "%s: getaddrinfo: %s\n", prog,
747 gai_strerror(rc));
748 *aipp = NULL;
749 return;
751 *aipp = ai;
755 * Calculate the packet length to be used, and check against the valid range.
756 * Returns -1 if range check fails.
758 static uint_t
759 calc_packetlen(int plen_input, struct pr_set *pr)
761 int minpacket; /* min ip packet size */
762 int optlen; /* length of ip options */
763 int plen;
766 * LBNL bug fixed: miscalculation of optlen
768 if (gw_count > 0) {
770 * IPv4:
771 * ----
772 * 5 (NO OPs) + 3 (code, len, ptr) + gateways
773 * IP options field can hold up to 9 gateways. But the API
774 * allows you to specify only 8, because the last one is the
775 * destination host. When this packet is sent, on the wire
776 * you see one gateway replaced by 4 NO OPs. The other 1 NO
777 * OP is for alignment
779 * IPv6:
780 * ----
781 * Well, formula is different, but the result is same.
782 * 8 byte fixed part for Type 0 Routing header, followed by
783 * gateway addresses
785 optlen = 8 + gw_count * pr->addr_len;
786 } else {
787 optlen = 0;
790 /* take care of the packet length calculations and checks */
791 minpacket = pr->ip_hdr_len + sizeof (struct outdata) + optlen;
792 if (useicmp)
793 minpacket += pr->icmp_minlen; /* minimum ICMP header size */
794 else
795 minpacket += sizeof (struct udphdr);
796 plen = plen_input;
797 if (plen == 0) {
798 plen = minpacket; /* minimum sized packet */
799 } else if (minpacket > plen || plen > IP_MAXPACKET) {
800 Fprintf(stderr, "%s: %s packet size must be >= %d and <= %d\n",
801 prog, pr->name, minpacket, IP_MAXPACKET);
802 return (0);
805 return (plen);
809 * Sets the source address by resolving -i and -s arguments, or if -i and -s
810 * don't dictate any, it sets the pick_src to make sure traceroute uses the
811 * kernel's pick of the source address.
812 * Returns number of interfaces configured on the source host, 0 on error or
813 * there's no interface which is up amd not a loopback.
815 static int
816 set_src_addr(struct pr_set *pr, struct ifaddrlist **alp)
818 union any_in_addr *ap;
819 struct ifaddrlist *al = NULL;
820 struct ifaddrlist *tmp1_al = NULL;
821 struct ifaddrlist *tmp2_al = NULL;
822 /* LINTED E_BAD_PTR_CAST_ALIGN */
823 struct sockaddr_in *sin_from = (struct sockaddr_in *)pr->from;
824 /* LINTED E_BAD_PTR_CAST_ALIGN */
825 struct sockaddr_in6 *sin6_from = (struct sockaddr_in6 *)pr->from;
826 struct addrinfo *aip;
827 char errbuf[ERRBUFSIZE];
828 char abuf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */
829 int num_ifs; /* all the interfaces */
830 int num_src_ifs; /* exclude loopback and down */
831 int i;
832 uint_t ifaddrflags = 0;
834 source = source_input;
836 if (device != NULL)
837 ifaddrflags |= LIFC_UNDER_IPMP;
839 /* get the interface address list */
840 num_ifs = ifaddrlist(&al, pr->family, ifaddrflags, errbuf);
841 if (num_ifs < 0) {
842 Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
843 exit(EXIT_FAILURE);
846 num_src_ifs = 0;
847 for (i = 0; i < num_ifs; i++) {
848 if (!(al[i].flags & IFF_LOOPBACK) && (al[i].flags & IFF_UP))
849 num_src_ifs++;
852 if (num_src_ifs == 0) {
853 Fprintf(stderr, "%s: can't find any %s network interfaces\n",
854 prog, pr->name);
855 return (0);
858 /* verify the device */
859 if (device != NULL) {
860 tmp1_al = find_device(al, num_ifs, device);
862 if (tmp1_al == NULL) {
863 Fprintf(stderr, "%s: %s (index %d) is an invalid %s"
864 " interface\n", prog, device, if_index, pr->name);
865 free(al);
866 return (0);
870 /* verify the source address */
871 if (source != NULL) {
872 get_hostinfo(source, pr->family, &aip);
873 if (aip == NULL) {
874 Fprintf(stderr,
875 "%s: %s is an invalid %s source address\n",
876 prog, source, pr->name);
878 free(al);
879 return (0);
882 source = aip->ai_canonname;
884 if (pr->family == AF_INET)
885 ap = (union any_in_addr *)
886 /* LINTED E_BAD_PTR_CAST_ALIGN */
887 &((struct sockaddr_in *)aip->ai_addr)->sin_addr;
888 else
889 ap = (union any_in_addr *)
890 /* LINTED E_BAD_PTR_CAST_ALIGN */
891 &((struct sockaddr_in6 *)aip->ai_addr)->sin6_addr;
894 * LBNL bug fixed: used to accept any src address
896 tmp2_al = find_ifaddr(al, num_ifs, ap, pr->family);
897 if (tmp2_al == NULL) {
898 (void) inet_ntop(pr->family, ap, abuf, sizeof (abuf));
899 Fprintf(stderr, "%s: %s is not a local %s address\n",
900 prog, abuf, pr->name);
901 free(al);
902 freeaddrinfo(aip);
903 return (0);
907 pick_src = _B_FALSE;
909 if (source == NULL) { /* no -s used */
910 if (device == NULL) { /* no -i used, no -s used */
911 pick_src = _B_TRUE;
912 } else { /* -i used, no -s used */
914 * -i used, but not -s, and it's IPv4: set the source
915 * address to whatever the interface has configured on
916 * it.
918 if (pr->family == AF_INET)
919 set_sin(pr->from, &(tmp1_al->addr), pr->family);
920 else
921 pick_src = _B_TRUE;
923 } else { /* -s used */
924 if (device == NULL) { /* no -i used, -s used */
925 set_sin(pr->from, ap, pr->family);
927 if (aip->ai_next != NULL) {
928 (void) inet_ntop(pr->family, pr->from_sin_addr,
929 abuf, sizeof (abuf));
930 Fprintf(stderr, "%s: Warning: %s has multiple "
931 "addresses; using %s\n", prog, source,
932 abuf);
934 } else { /* -i and -s used */
936 * Make sure the source specified matches the
937 * interface address. You only care about this for IPv4
938 * IPv6 can handle IF not matching src address
940 if (pr->family == AF_INET) {
941 if (!has_addr(aip, &tmp1_al->addr)) {
942 Fprintf(stderr,
943 "%s: %s is not on interface %s\n",
944 prog, source, device);
945 exit(EXIT_FAILURE);
948 * make sure we use the one matching the
949 * interface's address
951 *ap = tmp1_al->addr;
954 set_sin(pr->from, ap, pr->family);
959 * Binding at this point will set the source address to be used
960 * for both IPv4 (when raw IP datagrams are not required) and
961 * IPv6. If the address being bound to is zero, then the kernel
962 * will end up choosing the source address when the datagram is
963 * sent.
965 * For raw IPv4 datagrams, the source address is initialized
966 * within traceroute() along with the outbound destination
967 * address.
969 if (pr->family == AF_INET && !raw_req) {
970 sin_from->sin_family = AF_INET;
971 sin_from->sin_port = htons(ident);
972 if (bind(sndsock4, (struct sockaddr *)pr->from,
973 sizeof (struct sockaddr_in)) < 0) {
974 Fprintf(stderr, "%s: bind: %s\n", prog,
975 strerror(errno));
976 exit(EXIT_FAILURE);
978 } else if (pr->family == AF_INET6) {
979 sin6_from->sin6_family = AF_INET6;
980 sin6_from->sin6_port = htons(ident);
981 if (bind(sndsock6, (struct sockaddr *)pr->from,
982 sizeof (struct sockaddr_in6)) < 0) {
983 Fprintf(stderr, "%s: bind: %s\n", prog,
984 strerror(errno));
985 exit(EXIT_FAILURE);
988 whereto6.sin6_flowinfo = htonl((class << 20) | flow);
990 *alp = al;
991 return (num_ifs);
995 * Returns the complete ifaddrlist structure matching the desired interface
996 * address. Ignores interfaces which are either down or loopback.
998 static struct ifaddrlist *
999 find_ifaddr(struct ifaddrlist *al, int len, union any_in_addr *addr,
1000 int family)
1002 struct ifaddrlist *tmp_al = al;
1003 int i;
1004 size_t addr_len = (family == AF_INET) ? sizeof (struct in_addr) :
1005 sizeof (struct in6_addr);
1007 for (i = 0; i < len; i++, tmp_al++) {
1008 if ((!(tmp_al->flags & IFF_LOOPBACK) &&
1009 (tmp_al->flags & IFF_UP)) &&
1010 (memcmp(&tmp_al->addr, addr, addr_len) == 0))
1011 break;
1014 if (i < len) {
1015 return (tmp_al);
1016 } else {
1017 return (NULL);
1022 * Returns the complete ifaddrlist structure matching the desired interface name
1023 * Ignores interfaces which are either down or loopback.
1025 static struct ifaddrlist *
1026 find_device(struct ifaddrlist *al, int len, char *device)
1028 struct ifaddrlist *tmp_al = al;
1029 int i;
1031 for (i = 0; i < len; i++, tmp_al++) {
1032 if ((!(tmp_al->flags & IFF_LOOPBACK) &&
1033 (tmp_al->flags & IFF_UP)) &&
1034 (strcmp(tmp_al->device, device) == 0))
1035 break;
1038 if (i < len) {
1039 return (tmp_al);
1040 } else {
1041 return (NULL);
1046 * returns _B_TRUE if given hostinfo contains the given address
1048 static boolean_t
1049 has_addr(struct addrinfo *ai, union any_in_addr *addr)
1051 struct addrinfo *ai_tmp = NULL;
1052 union any_in_addr *ap;
1054 for (ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
1055 if (ai_tmp->ai_family == AF_INET6)
1056 continue;
1057 ap = (union any_in_addr *)
1058 /* LINTED E_BAD_PTR_CAST_ALIGN */
1059 &((struct sockaddr_in *)ai_tmp->ai_addr)->sin_addr;
1060 if (memcmp(ap, addr, sizeof (struct in_addr)) == 0)
1061 break;
1064 if (ai_tmp != NULL) {
1065 return (_B_TRUE);
1066 } else {
1067 return (_B_FALSE);
1072 * Resolve the gateway names, splitting results into v4 and v6 lists.
1073 * Gateway addresses are added to the appropriate passed-in array; the
1074 * number of resolved gateways for each af is returned in resolved[6].
1075 * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
1076 * and resolved[6] ptrs are non-null; ignores array and counter if the
1077 * address family param makes them irrelevant.
1079 static void
1080 get_gwaddrs(char **gwlist, int family, union any_in_addr *gwIPlist,
1081 union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
1083 int i;
1084 boolean_t check_v4 = _B_TRUE, check_v6 = _B_TRUE;
1085 struct addrinfo *ai = NULL;
1086 struct addrinfo *aip = NULL;
1088 *resolved = *resolved6 = 0;
1089 switch (family) {
1090 case AF_UNSPEC:
1091 break;
1092 case AF_INET:
1093 check_v6 = _B_FALSE;
1094 break;
1095 case AF_INET6:
1096 check_v4 = _B_FALSE;
1097 break;
1098 default:
1099 return;
1102 if (check_v4 && gw_count >= MAX_GWS) {
1103 check_v4 = _B_FALSE;
1104 Fprintf(stderr, "%s: too many IPv4 gateways\n", prog);
1105 num_v4 = 0;
1107 if (check_v6 && gw_count >= MAX_GWS6) {
1108 check_v6 = _B_FALSE;
1109 Fprintf(stderr, "%s: too many IPv6 gateways\n", prog);
1110 num_v6 = 0;
1113 for (i = 0; i < gw_count; i++) {
1114 if (!check_v4 && !check_v6)
1115 return;
1116 get_hostinfo(gwlist[i], family, &ai);
1117 if (ai == NULL)
1118 return;
1119 if (check_v4 && num_v4 != 0) {
1120 check_v4 = _B_FALSE;
1121 for (aip = ai; aip != NULL; aip = aip->ai_next) {
1122 if (aip->ai_family == AF_INET) {
1123 /* LINTED E_BAD_PTR_CAST_ALIGN */
1124 bcopy(&((struct sockaddr_in *)
1125 aip->ai_addr)->sin_addr,
1126 &gwIPlist[i].addr,
1127 aip->ai_addrlen);
1128 (*resolved)++;
1129 check_v4 = _B_TRUE;
1130 break;
1133 } else if (check_v4) {
1134 check_v4 = _B_FALSE;
1136 if (check_v6 && num_v6 != 0) {
1137 check_v6 = _B_FALSE;
1138 for (aip = ai; aip != NULL; aip = aip->ai_next) {
1139 if (aip->ai_family == AF_INET6) {
1140 /* LINTED E_BAD_PTR_CAST_ALIGN */
1141 bcopy(&((struct sockaddr_in6 *)
1142 aip->ai_addr)->sin6_addr,
1143 &gwIPlist6[i].addr6,
1144 aip->ai_addrlen);
1145 (*resolved6)++;
1146 check_v6 = _B_TRUE;
1147 break;
1150 } else if (check_v6) {
1151 check_v6 = _B_FALSE;
1154 freeaddrinfo(ai);
1158 * set protocol specific values here
1160 static void
1161 setup_protocol(struct pr_set *pr, int family)
1164 * Set the global variables for each AF. This is going to save us lots
1165 * of "if (family == AF_INET)... else .."
1167 pr->family = family;
1169 if (family == AF_INET) {
1170 if (!docksum) {
1171 Fprintf(stderr,
1172 "%s: Warning: checksums disabled\n", prog);
1174 (void) strcpy(pr->name, "IPv4");
1175 (void) strcpy(pr->icmp, "icmp");
1176 pr->icmp_minlen = ICMP_MINLEN;
1177 pr->addr_len = sizeof (struct in_addr);
1178 pr->ip_hdr_len = sizeof (struct ip);
1179 pr->sock_size = sizeof (struct sockaddr_in);
1180 pr->to = (struct sockaddr *)&whereto;
1181 pr->from = (struct sockaddr *)&wherefrom;
1182 pr->from_sin_addr = (void *)&wherefrom.sin_addr;
1183 pr->gwIPlist = gwIPlist;
1184 pr->set_buffers_fn = set_buffers;
1185 pr->check_reply_fn = check_reply;
1186 pr->print_icmp_other_fn = print_icmp_other;
1187 pr->print_addr_fn = print_addr;
1188 pr->packlen = calc_packetlen(packlen_input, pr);
1189 } else {
1190 (void) strcpy(pr->name, "IPv6");
1191 (void) strcpy(pr->icmp, "ipv6-icmp");
1192 pr->icmp_minlen = ICMP6_MINLEN;
1193 pr->addr_len = sizeof (struct in6_addr);
1194 pr->ip_hdr_len = sizeof (struct ip6_hdr);
1195 pr->sock_size = sizeof (struct sockaddr_in6);
1196 pr->to = (struct sockaddr *)&whereto6;
1197 pr->from = (struct sockaddr *)&wherefrom6;
1198 pr->from_sin_addr = (void *)&wherefrom6.sin6_addr;
1199 pr->gwIPlist = gwIP6list;
1200 pr->set_buffers_fn = set_buffers6;
1201 pr->check_reply_fn = check_reply6;
1202 pr->print_icmp_other_fn = print_icmp_other6;
1203 pr->print_addr_fn = print_addr6;
1204 pr->packlen = calc_packetlen(packlen_input, pr);
1206 if (pr->packlen == 0)
1207 exit(EXIT_FAILURE);
1211 * setup the sockets for the given protocol's address family
1213 static void
1214 setup_socket(struct pr_set *pr, int packet_len)
1216 int on = 1;
1217 struct protoent *pe;
1218 int type;
1219 int proto;
1220 int int_op;
1221 int rsock;
1222 int ssock;
1224 if ((pe = getprotobyname(pr->icmp)) == NULL) {
1225 Fprintf(stderr, "%s: unknown protocol %s\n", prog, pr->icmp);
1226 exit(EXIT_FAILURE);
1229 /* privilege bracketing */
1230 (void) __priv_bracket(PRIV_ON);
1232 if ((rsock = socket(pr->family, SOCK_RAW, pe->p_proto)) < 0) {
1233 Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
1234 exit(EXIT_FAILURE);
1237 if (options & SO_DEBUG) {
1238 if (setsockopt(rsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1239 sizeof (on)) < 0) {
1240 Fprintf(stderr, "%s: SO_DEBUG: %s\n", prog,
1241 strerror(errno));
1242 exit(EXIT_FAILURE);
1245 if (options & SO_DONTROUTE) {
1246 if (setsockopt(rsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1247 sizeof (on)) < 0) {
1248 Fprintf(stderr, "%s: SO_DONTROUTE: %s\n", prog,
1249 strerror(errno));
1250 exit(EXIT_FAILURE);
1254 if (pr->family == AF_INET6) {
1255 /* Enable receipt of destination address info */
1256 if (setsockopt(rsock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
1257 (char *)&on, sizeof (on)) < 0) {
1258 Fprintf(stderr, "%s: IPV6_RECVPKTINFO: %s\n", prog,
1259 strerror(errno));
1260 exit(EXIT_FAILURE);
1262 /* Enable receipt of hoplimit info */
1263 if (setsockopt(rsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
1264 (char *)&on, sizeof (on)) < 0) {
1265 Fprintf(stderr, "%s: IPV6_RECVHOPLIMIT: %s\n", prog,
1266 strerror(errno));
1267 exit(EXIT_FAILURE);
1273 * Initialize the socket type and protocol based on the address
1274 * family, whether or not a raw IP socket is required (for IPv4)
1275 * or whether ICMP will be used instead of UDP.
1277 * For historical reasons, the datagrams sent out by
1278 * traceroute(1M) do not have the "don't fragment" flag set. For
1279 * this reason as well as the ability to set the Loose Source and
1280 * Record Route (LSRR) option, a raw IP socket will be used for
1281 * IPv4 when run in the global zone. Otherwise, the actual
1282 * datagram that will be sent will be a regular UDP or ICMP echo
1283 * request packet. However for convenience and for future options
1284 * when other IP header information may be specified using
1285 * traceroute, the buffer including the raw IP and UDP or ICMP
1286 * header is always filled in. When the probe is actually sent,
1287 * the size of the request and the start of the packet is set
1288 * according to the type of datagram to send.
1290 if (pr->family == AF_INET && raw_req) {
1291 type = SOCK_RAW;
1292 proto = IPPROTO_RAW;
1293 } else if (useicmp) {
1294 type = SOCK_RAW;
1295 if (pr->family == AF_INET)
1296 proto = IPPROTO_ICMP;
1297 else
1298 proto = IPPROTO_ICMPV6;
1299 } else {
1300 type = SOCK_DGRAM;
1301 proto = IPPROTO_UDP;
1303 ssock = socket(pr->family, type, proto);
1305 if (ssock < 0) {
1306 if (proto == IPPROTO_RAW) {
1307 Fprintf(stderr, "%s: raw socket: %s\n", prog,
1308 strerror(errno));
1309 } else if (proto == IPPROTO_UDP) {
1310 Fprintf(stderr, "%s: udp socket: %s\n", prog,
1311 strerror(errno));
1312 } else {
1313 Fprintf(stderr, "%s: icmp socket: %s\n", prog,
1314 strerror(errno));
1316 exit(EXIT_FAILURE);
1319 if (setsockopt(ssock, SOL_SOCKET, SO_SNDBUF, (char *)&packet_len,
1320 sizeof (packet_len)) < 0) {
1321 Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
1322 exit(EXIT_FAILURE);
1325 if (pr->family == AF_INET && raw_req) {
1326 if (setsockopt(ssock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1327 sizeof (on)) < 0) {
1328 Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog,
1329 strerror(errno));
1330 exit(EXIT_FAILURE);
1334 if (options & SO_DEBUG) {
1335 if (setsockopt(ssock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1336 sizeof (on)) < 0) {
1337 Fprintf(stderr, "%s: SO_DEBUG: %s\n", prog,
1338 strerror(errno));
1339 exit(EXIT_FAILURE);
1342 if (options & SO_DONTROUTE) {
1343 if (setsockopt(ssock, SOL_SOCKET, SO_DONTROUTE,
1344 (char *)&on, sizeof (on)) < 0) {
1345 Fprintf(stderr, "%s: SO_DONTROUTE: %s\n", prog,
1346 strerror(errno));
1347 exit(EXIT_FAILURE);
1352 * If a raw IPv4 packet is going to be sent, the Type of Service
1353 * field in the packet will be initialized in set_buffers().
1354 * Otherwise, it is initialized here using the IPPROTO_IP level
1355 * socket option.
1357 if (settos && !raw_req) {
1358 int_op = tos;
1359 if (setsockopt(ssock, IPPROTO_IP, IP_TOS, (char *)&int_op,
1360 sizeof (int_op)) < 0) {
1361 Fprintf(stderr, "%s: IP_TOS: %s\n", prog,
1362 strerror(errno));
1363 exit(EXIT_FAILURE);
1367 /* We enable or disable to not depend on the kernel default */
1368 if (pr->family == AF_INET) {
1369 if (setsockopt(ssock, IPPROTO_IP, IP_DONTFRAG,
1370 (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1371 Fprintf(stderr, "%s: IP_DONTFRAG %s\n", prog,
1372 strerror(errno));
1373 exit(EXIT_FAILURE);
1375 } else {
1376 if (setsockopt(ssock, IPPROTO_IPV6, IPV6_DONTFRAG,
1377 (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1378 Fprintf(stderr, "%s: IPV6_DONTFRAG %s\n", prog,
1379 strerror(errno));
1380 exit(EXIT_FAILURE);
1384 if (pr->family == AF_INET) {
1385 rcvsock4 = rsock;
1386 sndsock4 = ssock;
1387 } else {
1388 rcvsock6 = rsock;
1389 sndsock6 = ssock;
1391 /* Revert to non-privileged user after configuring sockets */
1392 (void) __priv_bracket(PRIV_OFF);
1396 * If we are "probing all", this function calls traceroute() for each IP address
1397 * of the target, otherwise calls only once. Returns _B_FALSE if traceroute()
1398 * fails.
1400 static void
1401 trace_it(struct addrinfo *ai_dst)
1403 struct msghdr msg6;
1404 int num_dst_IPaddrs;
1405 struct addrinfo *aip;
1406 int i;
1408 if (!probe_all)
1409 num_dst_IPaddrs = 1;
1410 else
1411 num_dst_IPaddrs = num_v4 + num_v6;
1414 * Initialize the msg6 structure using the hoplimit for the first
1415 * probe packet, gateway addresses and the outgoing interface index.
1417 if (ai_dst->ai_family == AF_INET6 || (probe_all && num_v6)) {
1418 msg6.msg_control = NULL;
1419 msg6.msg_controllen = 0;
1420 set_ancillary_data(&msg6, first_ttl, pr6->gwIPlist, gw_count,
1421 if_index);
1424 /* run traceroute for all the IP addresses of the multihomed dest */
1425 for (aip = ai_dst, i = 0; i < num_dst_IPaddrs && aip != NULL; i++) {
1426 union any_in_addr *addrp;
1427 if (aip->ai_family == AF_INET) {
1428 addrp = (union any_in_addr *)
1429 /* LINTED E_BAD_PTR_CAST_ALIGN */
1430 &((struct sockaddr_in *)
1431 aip->ai_addr)->sin_addr;
1432 set_sin((struct sockaddr *)pr4->to, addrp,
1433 aip->ai_family);
1434 traceroute(addrp, &msg6, pr4, num_ifs4, al4);
1435 } else {
1436 addrp = (union any_in_addr *)
1437 /* LINTED E_BAD_PTR_CAST_ALIGN */
1438 &((struct sockaddr_in6 *)
1439 aip->ai_addr)->sin6_addr;
1440 set_sin((struct sockaddr *)pr6->to, addrp,
1441 aip->ai_family);
1442 traceroute(addrp, &msg6, pr6, num_ifs6, al6);
1444 aip = aip->ai_next;
1445 if (i < (num_dst_IPaddrs - 1))
1446 (void) putchar('\n');
1451 * set the IP address in a sockaddr struct
1453 static void
1454 set_sin(struct sockaddr *sock, union any_in_addr *addr, int family)
1456 sock->sa_family = family;
1458 if (family == AF_INET)
1459 /* LINTED E_BAD_PTR_CAST_ALIGN */
1460 ((struct sockaddr_in *)sock)->sin_addr = addr->addr;
1461 else
1462 /* LINTED E_BAD_PTR_CAST_ALIGN */
1463 ((struct sockaddr_in6 *)sock)->sin6_addr = addr->addr6;
1467 * returns the IF name on which the given IP address is configured
1469 static char *
1470 device_name(struct ifaddrlist *al, int len, union any_in_addr *ip_addr,
1471 struct pr_set *pr)
1473 int i;
1474 struct ifaddrlist *tmp_al;
1476 tmp_al = al;
1478 for (i = 0; i < len; i++, tmp_al++) {
1479 if (memcmp(&tmp_al->addr, ip_addr, pr->addr_len) == 0) {
1480 return (tmp_al->device);
1484 return (NULL);
1488 * Trace the route to the host with given IP address.
1490 static void
1491 traceroute(union any_in_addr *ip_addr, struct msghdr *msg6, struct pr_set *pr,
1492 int num_ifs, struct ifaddrlist *al)
1494 int ttl;
1495 int probe;
1496 uchar_t type; /* icmp type */
1497 uchar_t code; /* icmp code */
1498 int reply;
1499 int seq = 0;
1500 char abuf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */
1501 int longjmp_return; /* return value from longjump */
1502 struct ip *ip = (struct ip *)packet;
1503 boolean_t got_there = _B_FALSE; /* we hit the destination */
1504 static boolean_t first_pkt = _B_TRUE;
1505 int hoplimit; /* hoplimit for IPv6 packets */
1506 struct in6_addr addr6;
1507 int num_src_ifs; /* excludes down and loopback */
1508 struct msghdr in_msg;
1509 struct iovec iov;
1510 int *intp;
1511 int sndsock;
1512 int rcvsock;
1514 msg6->msg_name = pr->to;
1515 msg6->msg_namelen = sizeof (struct sockaddr_in6);
1516 sndsock = (pr->family == AF_INET) ? sndsock4 : sndsock6;
1517 rcvsock = (pr->family == AF_INET) ? rcvsock4 : rcvsock6;
1519 /* carry out the source address selection */
1520 if (pick_src) {
1521 union any_in_addr src_addr;
1522 char *dev_name;
1523 int i;
1526 * If there's a gateway, a routing header as a consequence, our
1527 * kernel picks the source address based on the first hop
1528 * address, rather than final destination address.
1530 if (gw_count > 0) {
1531 (void) select_src_addr(pr->gwIPlist, &src_addr,
1532 pr->family);
1533 } else {
1534 (void) select_src_addr(ip_addr, &src_addr, pr->family);
1536 set_sin(pr->from, &src_addr, pr->family);
1538 /* filter out down and loopback interfaces */
1539 num_src_ifs = 0;
1540 for (i = 0; i < num_ifs; i++) {
1541 if (!(al[i].flags & IFF_LOOPBACK) &&
1542 (al[i].flags & IFF_UP))
1543 num_src_ifs++;
1546 if (num_src_ifs > 1) {
1547 dev_name = device_name(al, num_ifs, &src_addr, pr);
1548 if (dev_name == NULL)
1549 dev_name = "?";
1551 (void) inet_ntop(pr->family, pr->from_sin_addr, abuf,
1552 sizeof (abuf));
1553 Fprintf(stderr,
1554 "%s: Warning: Multiple interfaces found;"
1555 " using %s @ %s\n", prog, abuf, dev_name);
1559 if (pr->family == AF_INET) {
1560 outip4->ip_src = *(struct in_addr *)pr->from_sin_addr;
1561 outip4->ip_dst = ip_addr->addr;
1565 * If the hostname is an IPv6 literal address, let's not print it twice.
1567 if (pr->family == AF_INET6 &&
1568 inet_pton(AF_INET6, hostname, &addr6) > 0) {
1569 Fprintf(stderr, "%s to %s", prog, hostname);
1570 } else {
1571 Fprintf(stderr, "%s to %s (%s)", prog, hostname,
1572 inet_ntop(pr->family, ip_addr, abuf, sizeof (abuf)));
1575 if (source)
1576 Fprintf(stderr, " from %s", source);
1577 Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl,
1578 pr->packlen);
1579 (void) fflush(stderr);
1582 * Setup the source routing for IPv4. For IPv6, we did the required
1583 * setup in the caller function, trace_it(), because it's independent
1584 * from the IP address of target.
1586 if (pr->family == AF_INET && gw_count > 0)
1587 set_IPv4opt_sourcerouting(sndsock, ip_addr, pr->gwIPlist);
1589 if (probe_all) {
1590 /* interrupt handler sig_handler() jumps back to here */
1591 if ((longjmp_return = setjmp(env)) != 0) {
1592 switch (longjmp_return) {
1593 case SIGINT:
1594 Printf("(skipping)\n");
1595 return;
1596 case SIGQUIT:
1597 Printf("(exiting)\n");
1598 exit(EXIT_SUCCESS);
1599 default: /* should never happen */
1600 exit(EXIT_FAILURE);
1603 (void) signal(SIGINT, sig_handler);
1606 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1607 union any_in_addr lastaddr;
1608 int timeouts = 0;
1609 double rtt; /* for statistics */
1610 int nreceived = 0;
1611 double rttmin, rttmax;
1612 double rttsum, rttssq;
1613 int unreachable;
1615 got_there = _B_FALSE;
1616 unreachable = 0;
1619 * The following line clears both IPv4 and IPv6 address stored
1620 * in the union.
1622 lastaddr.addr6 = in6addr_any;
1624 if ((ttl == (first_ttl + 1)) && (options & SO_DONTROUTE)) {
1625 Fprintf(stderr,
1626 "%s: host %s is not on a directly-attached"
1627 " network\n", prog, hostname);
1628 break;
1631 Printf("%2d ", ttl);
1632 (void) fflush(stdout);
1634 for (probe = 0; (probe < nprobes) && (timeouts < max_timeout);
1635 ++probe) {
1636 int cc;
1637 struct timeval t1, t2;
1640 * Put a delay before sending this probe packet. Don't
1641 * delay it if it's the very first packet.
1643 if (!first_pkt) {
1644 if (delay.tv_sec > 0)
1645 (void) sleep((uint_t)delay.tv_sec);
1646 if (delay.tv_usec > 0)
1647 (void) usleep(delay.tv_usec);
1648 } else {
1649 first_pkt = _B_FALSE;
1652 (void) gettimeofday(&t1, NULL);
1654 if (pr->family == AF_INET) {
1655 send_probe(sndsock, pr->to, outip4, seq, ttl,
1656 &t1, pr->packlen);
1657 } else {
1658 send_probe6(sndsock, msg6, outip6, seq, ttl,
1659 &t1, pr->packlen);
1662 /* prepare msghdr for recvmsg() */
1663 in_msg.msg_name = pr->from;
1664 in_msg.msg_namelen = pr->sock_size;
1666 iov.iov_base = (char *)packet;
1667 iov.iov_len = sizeof (packet);
1669 in_msg.msg_iov = &iov;
1670 in_msg.msg_iovlen = 1;
1672 in_msg.msg_control = ancillary_data;
1673 in_msg.msg_controllen = sizeof (ancillary_data);
1675 while ((cc = wait_for_reply(rcvsock, &in_msg,
1676 &t1)) != 0) {
1677 (void) gettimeofday(&t2, NULL);
1679 reply = (*pr->check_reply_fn) (&in_msg, cc, seq,
1680 &type, &code);
1682 in_msg.msg_controllen =
1683 sizeof (ancillary_data);
1684 /* Skip short packet */
1685 if (reply == REPLY_SHORT_PKT) {
1686 continue;
1689 timeouts = 0;
1692 * if reply comes from a different host, print
1693 * the hostname
1695 if (memcmp(pr->from_sin_addr, &lastaddr,
1696 pr->addr_len) != 0) {
1697 (*pr->print_addr_fn) ((uchar_t *)packet,
1698 cc, pr->from);
1699 /* store the address response */
1700 (void) memcpy(&lastaddr,
1701 pr->from_sin_addr, pr->addr_len);
1704 rtt = deltaT(&t1, &t2);
1705 if (collect_stat) {
1706 record_stats(rtt, &nreceived, &rttmin,
1707 &rttmax, &rttsum, &rttssq);
1708 } else {
1709 Printf(" %.3f ms", rtt);
1712 if (pr->family == AF_INET6) {
1713 intp = find_ancillary_data(&in_msg,
1714 IPPROTO_IPV6, IPV6_HOPLIMIT);
1715 if (intp == NULL) {
1716 Fprintf(stderr,
1717 "%s: can't find "
1718 "IPV6_HOPLIMIT ancillary "
1719 "data\n", prog);
1720 exit(EXIT_FAILURE);
1722 hoplimit = *intp;
1725 if (reply == REPLY_GOT_TARGET) {
1726 got_there = _B_TRUE;
1728 if (((pr->family == AF_INET) &&
1729 (ip->ip_ttl <= 1)) ||
1730 ((pr->family == AF_INET6) &&
1731 (hoplimit <= 1)))
1732 Printf(" !");
1735 if (!collect_stat && showttl) {
1736 if (pr->family == AF_INET) {
1737 Printf(" (ttl=%d)",
1738 (int)ip->ip_ttl);
1739 } else if (hoplimit != -1) {
1740 Printf(" (hop limit=%d)",
1741 hoplimit);
1745 if (reply == REPLY_GOT_OTHER) {
1746 if ((*pr->print_icmp_other_fn)
1747 (type, code)) {
1748 unreachable++;
1752 /* special case */
1753 if (pr->family == AF_INET &&
1754 type == ICMP_UNREACH &&
1755 code == ICMP_UNREACH_PROTOCOL)
1756 got_there = _B_TRUE;
1758 break;
1761 seq = (seq + 1) % (MAX_SEQ + 1);
1763 if (cc == 0) {
1764 Printf(" *");
1765 timeouts++;
1768 (void) fflush(stdout);
1771 if (collect_stat) {
1772 print_stats(probe, nreceived, rttmin, rttmax, rttsum,
1773 rttssq);
1776 (void) putchar('\n');
1778 /* either we hit the target or received too many unreachables */
1779 if (got_there ||
1780 (unreachable > 0 && unreachable >= nprobes - 1))
1781 break;
1784 /* Ignore the SIGINT between traceroute() runs */
1785 if (probe_all)
1786 (void) signal(SIGINT, SIG_IGN);
1790 * for a given destination address and address family, it finds out what
1791 * source address kernel is going to pick
1793 static void
1794 select_src_addr(union any_in_addr *dst_addr, union any_in_addr *src_addr,
1795 int family)
1797 int tmp_fd;
1798 struct sockaddr *sock;
1799 struct sockaddr_in *sin;
1800 struct sockaddr_in6 *sin6;
1801 size_t sock_len;
1803 sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
1804 if (sock == NULL) {
1805 Fprintf(stderr, "%s: malloc %s\n", prog, strerror(errno));
1806 exit(EXIT_FAILURE);
1808 (void) bzero(sock, sizeof (struct sockaddr_in6));
1810 if (family == AF_INET) {
1811 /* LINTED E_BAD_PTR_CAST_ALIGN */
1812 sin = (struct sockaddr_in *)sock;
1813 sin->sin_family = AF_INET;
1814 sin->sin_addr = dst_addr->addr;
1815 sin->sin_port = IPPORT_ECHO; /* port shouldn't be 0 */
1816 sock_len = sizeof (struct sockaddr_in);
1817 } else {
1818 /* LINTED E_BAD_PTR_CAST_ALIGN */
1819 sin6 = (struct sockaddr_in6 *)sock;
1820 sin6->sin6_family = AF_INET6;
1821 sin6->sin6_addr = dst_addr->addr6;
1822 sin6->sin6_port = IPPORT_ECHO; /* port shouldn't be 0 */
1823 sock_len = sizeof (struct sockaddr_in6);
1826 /* open a UDP socket */
1827 if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
1828 Fprintf(stderr, "%s: udp socket: %s\n", prog,
1829 strerror(errno));
1830 exit(EXIT_FAILURE);
1833 /* connect it */
1834 if (connect(tmp_fd, sock, sock_len) < 0) {
1836 * If there's no route to the destination, this connect() call
1837 * fails. We just return all-zero (wildcard) as the source
1838 * address, so that user can get to see "no route to dest"
1839 * message, as it'll try to send the probe packet out and will
1840 * receive ICMP unreachable.
1842 if (family == AF_INET)
1843 src_addr->addr.s_addr = INADDR_ANY;
1844 else
1845 src_addr->addr6 = in6addr_any;
1846 free(sock);
1847 return;
1850 /* get the local sock info */
1851 if (getsockname(tmp_fd, sock, &sock_len) < 0) {
1852 Fprintf(stderr, "%s: getsockname: %s\n", prog,
1853 strerror(errno));
1854 exit(EXIT_FAILURE);
1857 if (family == AF_INET) {
1858 /* LINTED E_BAD_PTR_CAST_ALIGN */
1859 sin = (struct sockaddr_in *)sock;
1860 src_addr->addr = sin->sin_addr;
1861 } else {
1862 /* LINTED E_BAD_PTR_CAST_ALIGN */
1863 sin6 = (struct sockaddr_in6 *)sock;
1864 src_addr->addr6 = sin6->sin6_addr;
1867 free(sock);
1868 (void) close(tmp_fd);
1872 * Checksum routine for Internet Protocol family headers (C Version)
1874 ushort_t
1875 in_cksum(ushort_t *addr, int len)
1877 int nleft = len;
1878 ushort_t *w = addr;
1879 ushort_t answer;
1880 int sum = 0;
1883 * Our algorithm is simple, using a 32 bit accumulator (sum),
1884 * we add sequential 16 bit words to it, and at the end, fold
1885 * back all the carry bits from the top 16 bits into the lower
1886 * 16 bits.
1888 while (nleft > 1) {
1889 sum += *w++;
1890 nleft -= 2;
1893 /* mop up an odd byte, if necessary */
1894 if (nleft == 1)
1895 sum += *(uchar_t *)w;
1897 /* add back carry outs from top 16 bits to low 16 bits */
1898 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1899 sum += (sum >> 16); /* add carry */
1900 answer = ~sum; /* truncate to 16 bits */
1901 return (answer);
1905 * Wait until a reply arrives or timeout occurs. If packet arrived, read it
1906 * return the size of the packet read.
1908 static int
1909 wait_for_reply(int sock, struct msghdr *msg, struct timeval *tp)
1911 fd_set fds;
1912 struct timeval now, wait;
1913 int cc = 0;
1914 int result;
1916 (void) FD_ZERO(&fds);
1917 FD_SET(sock, &fds);
1919 wait.tv_sec = tp->tv_sec + waittime;
1920 wait.tv_usec = tp->tv_usec;
1921 (void) gettimeofday(&now, NULL);
1922 tv_sub(&wait, &now);
1924 if (wait.tv_sec < 0 || wait.tv_usec < 0)
1925 return (0);
1927 result = select(sock + 1, &fds, (fd_set *)NULL, (fd_set *)NULL, &wait);
1929 if (result == -1) {
1930 if (errno != EINTR) {
1931 Fprintf(stderr, "%s: select: %s\n", prog,
1932 strerror(errno));
1934 } else if (result > 0)
1935 cc = recvmsg(sock, msg, 0);
1937 return (cc);
1941 * Construct an Internet address representation. If the nflag has been supplied,
1942 * give numeric value, otherwise try for symbolic name.
1944 char *
1945 inet_name(union any_in_addr *in, int family)
1947 char *cp;
1948 static boolean_t first = _B_TRUE;
1949 static char domain[NI_MAXHOST + 1];
1950 static char line[NI_MAXHOST + 1]; /* assuming */
1951 /* (NI_MAXHOST + 1) >= INET6_ADDRSTRLEN */
1952 char hbuf[NI_MAXHOST];
1953 socklen_t slen;
1954 struct sockaddr_in sin;
1955 struct sockaddr_in6 sin6;
1956 struct sockaddr *sa;
1957 int flags;
1959 switch (family) {
1960 case AF_INET:
1961 slen = sizeof (struct sockaddr_in);
1962 sin.sin_addr = in->addr;
1963 sin.sin_port = 0;
1964 sa = (struct sockaddr *)&sin;
1965 break;
1966 case AF_INET6:
1967 slen = sizeof (struct sockaddr_in6);
1968 sin6.sin6_addr = in->addr6;
1969 sin6.sin6_port = 0;
1970 sin6.sin6_scope_id = 0;
1971 sa = (struct sockaddr *)&sin6;
1972 break;
1973 default:
1974 (void) snprintf(line, sizeof (line),
1975 "<invalid address family>");
1976 return (line);
1978 sa->sa_family = family;
1980 if (first && !nflag) {
1981 /* find out the domain name */
1982 first = _B_FALSE;
1983 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
1984 (cp = strchr(domain, '.')) != NULL) {
1985 (void) strncpy(domain, cp + 1, sizeof (domain) - 1);
1986 domain[sizeof (domain) - 1] = '\0';
1987 } else {
1988 domain[0] = '\0';
1992 flags = (nflag) ? NI_NUMERICHOST : NI_NAMEREQD;
1993 if (getnameinfo(sa, slen, hbuf, sizeof (hbuf), NULL, 0, flags) != 0) {
1994 if (inet_ntop(family, (const void *)&in->addr6,
1995 hbuf, sizeof (hbuf)) == NULL)
1996 hbuf[0] = 0;
1997 } else if (!nflag && (cp = strchr(hbuf, '.')) != NULL &&
1998 strcmp(cp + 1, domain) == 0) {
1999 *cp = '\0';
2001 (void) strlcpy(line, hbuf, sizeof (line));
2003 return (line);
2007 * return the difference (in msec) between two time values
2009 static double
2010 deltaT(struct timeval *t1p, struct timeval *t2p)
2012 double dt;
2014 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
2015 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
2016 return (dt);
2020 * Subtract 2 timeval structs: out = out - in.
2021 * Out is assumed to be >= in.
2023 static void
2024 tv_sub(struct timeval *out, struct timeval *in)
2026 if ((out->tv_usec -= in->tv_usec) < 0) {
2027 --out->tv_sec;
2028 out->tv_usec += 1000000;
2030 out->tv_sec -= in->tv_sec;
2034 * record statistics
2036 static void
2037 record_stats(double rtt, int *nreceived, double *rttmin, double *rttmax,
2038 double *rttsum, double *rttssq)
2040 if (*nreceived == 0) {
2041 *rttmin = rtt;
2042 *rttmax = rtt;
2043 *rttsum = rtt;
2044 *rttssq = rtt * rtt;
2045 } else {
2046 if (rtt < *rttmin)
2047 *rttmin = rtt;
2049 if (rtt > *rttmax)
2050 *rttmax = rtt;
2052 *rttsum += rtt;
2053 *rttssq += rtt * rtt;
2056 (*nreceived)++;
2060 * display statistics
2062 static void
2063 print_stats(int ntransmitted, int nreceived, double rttmin, double rttmax,
2064 double rttsum, double rttssq)
2066 double rttavg; /* average round-trip time */
2067 double rttstd; /* rtt standard deviation */
2069 if (ntransmitted > 0 && ntransmitted >= nreceived) {
2070 int missed = ntransmitted - nreceived;
2071 double loss = 100 * (double)missed / (double)ntransmitted;
2073 if (nreceived > 0) {
2074 rttavg = rttsum / nreceived;
2075 rttstd = rttssq - (rttavg * rttsum);
2076 rttstd = xsqrt(rttstd / nreceived);
2078 Printf(" %.3f", rttmin);
2079 Printf("/%.3f", rttavg);
2080 Printf("/%.3f", rttmax);
2082 Printf(" (%.3f) ms ", rttstd);
2085 Printf(" %d/%d pkts", nreceived, ntransmitted);
2087 if (nreceived == 0)
2088 Printf(" (100%% loss)");
2089 else
2090 Printf(" (%.2g%% loss)", loss);
2095 * square root function
2097 double
2098 xsqrt(double y)
2100 double t, x;
2102 if (y <= 0) {
2103 return (0.0);
2106 x = (y < 1.0) ? 1.0 : y;
2107 do {
2108 t = x;
2109 x = (t + (y/t))/2.0;
2110 } while (0 < x && x < t);
2112 return (x);
2116 * String to double with optional min and max.
2118 static double
2119 str2dbl(const char *str, const char *what, double mi, double ma)
2121 double val;
2122 char *ep;
2124 errno = 0;
2126 val = strtod(str, &ep);
2127 if (errno != 0 || *ep != '\0') {
2128 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
2129 prog, str, what);
2130 exit(EXIT_FAILURE);
2132 if (val < mi && mi >= 0) {
2133 Fprintf(stderr, "%s: %s must be >= %f\n", prog, what, mi);
2134 exit(EXIT_FAILURE);
2136 if (val > ma && ma >= 0) {
2137 Fprintf(stderr, "%s: %s must be <= %f\n", prog, what, ma);
2138 exit(EXIT_FAILURE);
2140 return (val);
2144 * String to int with optional min and max. Handles decimal and hex.
2146 static int
2147 str2int(const char *str, const char *what, int mi, int ma)
2149 const char *cp;
2150 int val;
2151 char *ep;
2153 errno = 0;
2155 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
2156 cp = str + 2;
2157 val = (int)strtol(cp, &ep, 16);
2158 } else {
2159 val = (int)strtol(str, &ep, 10);
2161 if (errno != 0 || *ep != '\0') {
2162 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
2163 prog, str, what);
2164 exit(EXIT_FAILURE);
2166 if (val < mi && mi >= 0) {
2167 if (mi == 0) {
2168 Fprintf(stderr, "%s: %s must be >= %d\n",
2169 prog, what, mi);
2170 } else {
2171 Fprintf(stderr, "%s: %s must be > %d\n",
2172 prog, what, mi - 1);
2174 exit(EXIT_FAILURE);
2176 if (val > ma && ma >= 0) {
2177 Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
2178 exit(EXIT_FAILURE);
2180 return (val);
2184 * This is the interrupt handler for SIGINT and SIGQUIT. It's completely handled
2185 * where it jumps to.
2187 static void
2188 sig_handler(int sig)
2190 longjmp(env, sig);
2194 * display the usage of traceroute
2196 static void
2197 usage(void)
2199 Fprintf(stderr, "Usage: %s [-adFIlnSvx] [-A address_family] "
2200 "[-c traffic_class]\n"
2201 "\t[-f first_hop] [-g gateway [-g gateway ...]| -r] [-i iface]\n"
2202 "\t[-L flow_label] [-m max_hop] [-P pause_sec] [-p port] "
2203 "[-Q max_timeout]\n"
2204 "\t[-q nqueries] [-s src_addr] [-t tos] [-w wait_time] host "
2205 "[packetlen]\n", prog);
2206 exit(EXIT_FAILURE);