2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 * Copyright (c) 2017, Joyent, Inc.
8 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that: (1) source code distributions
13 * retain the above copyright notice and this paragraph in its entirety, (2)
14 * distributions including binary code include the above copyright notice and
15 * this paragraph in its entirety in the documentation or other materials
16 * provided with the distribution, and (3) all advertising materials mentioning
17 * features or use of this software display the following acknowledgement:
18 * ``This product includes software developed by the University of California,
19 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
20 * the University nor the names of its contributors may be used to endorse
21 * or promote products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 * @(#)$Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp $ (LBL)
31 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
36 #include <sys/sysmacros.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/in.h>
40 #include <netinet/ip.h>
41 #include <netinet/ip_var.h>
42 #include <netinet/ip_icmp.h>
43 #include <netinet/udp.h>
44 #include <netinet/udp_var.h>
45 #include <netinet/ip6.h>
46 #include <netinet/icmp6.h>
48 #include <arpa/inet.h>
68 #include <priv_utils.h>
70 #include <libinetutil.h>
71 #include "traceroute.h"
73 #define MAX_SEQ 65535 /* max sequence value for ICMP */
74 #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
75 #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
76 #define MAX_TOS 255 /* max type-of-service for IPv4 */
79 /* store the information about a host */
81 char *name
; /* hostname */
82 int family
; /* address family of the IP addresses */
83 int num_addr
; /* number of IP addresses */
84 union any_in_addr
*addrs
; /* list of IP addresses */
87 /* used to store a bunch of protocol specific values */
89 int family
; /* AF_INET or AF_INET6 */
90 char name
[STR_LEN
]; /* "IPv4" or "IPv6" */
91 char icmp
[STR_LEN
]; /* "icmp" or "ipv6-icmp" */
96 int sock_size
; /* size of sockaddr_in or sockaddr_in6 */
98 struct sockaddr
*from
;
100 union any_in_addr
*gwIPlist
;
101 /* pointers to v4/v6 functions */
102 struct ip
*(*set_buffers_fn
) (int);
103 int (*check_reply_fn
)(struct msghdr
*, int, int, uchar_t
*, uchar_t
*);
104 boolean_t (*print_icmp_other_fn
)(uchar_t
, uchar_t
);
105 void (*print_addr_fn
)(uchar_t
*, int, struct sockaddr
*);
110 * LBNL bug fixed: in LBNL traceroute 'uchar_t packet[512];'
111 * Not sufficient to hold the complete packet for ECHO REPLY of a big probe.
112 * Packet size is reported incorrectly in such a case.
113 * Also this buffer needs to be 32 bit aligned. In the future the alignment
114 * requirement will be increased to 64 bit. So, let's use 64 bit alignment now.
116 static uint64_t packet
[(IP_MAXPACKET
+ 1)/8]; /* received packet */
118 static struct ip
*outip4
; /* output buffer to send as an IPv4 datagram */
119 static struct ip
*outip6
; /* output buffer to send as an IPv6 datagram */
121 /* Used to store the ancillary data that comes with the received packets */
122 static uint64_t ancillary_data
[(IP_MAXPACKET
+ 1)/8];
124 /* first get the gw names, later you'll resolve them based on the family */
125 static char *gwlist
[MAXMAX_GWS
]; /* gateway names list */
126 static union any_in_addr gwIPlist
[MAX_GWS
]; /* gateway IPv4 address list */
127 static union any_in_addr gwIP6list
[MAX_GWS6
]; /* gateway IPv6 address list */
129 static int family_input
= AF_UNSPEC
; /* User supplied protocol family */
130 static int rcvsock4
; /* receive (icmp) socket file descriptor */
131 static int sndsock4
; /* send (udp/icmp) socket file descriptor */
132 static int rcvsock6
; /* receive (icmp6) socket file descriptor */
133 static int sndsock6
; /* send (udp6/icmp6) socket file descriptor */
134 int gw_count
= 0; /* number of gateways */
135 static struct sockaddr_in whereto
; /* Who to try to reach */
136 static struct sockaddr_in6 whereto6
;
137 static struct sockaddr_in wherefrom
; /* Who we are */
138 static struct sockaddr_in6 wherefrom6
;
139 static int packlen_input
= 0; /* user input for packlen */
142 static char *source_input
= NULL
; /* this is user arg. source, doesn't change */
143 static char *source
= NULL
; /* this gets modified after name lookup */
145 static char *device
= NULL
; /* interface name */
146 static struct pr_set
*pr4
; /* protocol info for IPv4 */
147 static struct pr_set
*pr6
; /* protocol info for IPv6 */
148 static struct ifaddrlist
*al4
; /* list of interfaces */
149 static struct ifaddrlist
*al6
; /* list of interfaces */
150 static uint_t if_index
= 0; /* interface index */
151 static int num_v4
= 0; /* count of IPv4 addresses */
152 static int num_v6
= 0; /* count of IPv6 addresses */
153 static int num_ifs4
= 0; /* count of local IPv4 interfaces */
154 static int num_ifs6
= 0; /* count of local IPv6 interfaces */
156 static int nprobes
= 3; /* number of probes */
157 static int max_ttl
= 30; /* max number of hops */
158 static int first_ttl
= 1; /* initial number of hops */
159 ushort_t ident
; /* used to authenticate replies */
160 ushort_t port
= 32768 + 666; /* start udp dest port # for probe packets */
162 static int options
= 0; /* socket options */
163 boolean_t verbose
= B_FALSE
; /* verbose output */
164 static int waittime
= 5; /* time to wait for response (in seconds) */
165 static struct timeval delay
= {0, 0}; /* delay between consecutive probe */
166 boolean_t nflag
= B_FALSE
; /* print addresses numerically */
167 static boolean_t showttl
= B_FALSE
; /* print the ttl(hop limit) of recvd pkt */
168 boolean_t useicmp
= B_FALSE
; /* use icmp echo instead of udp packets */
169 boolean_t docksum
= B_TRUE
; /* calculate checksums */
170 static boolean_t collect_stat
= B_FALSE
; /* print statistics */
171 boolean_t settos
= B_FALSE
; /* set type-of-service field */
172 int dontfrag
= 0; /* IP*_DONTFRAG */
173 static int max_timeout
= 5; /* quit after this consecutive timeouts */
174 static boolean_t probe_all
= B_FALSE
; /* probe all the IFs of the target */
175 static boolean_t pick_src
= B_FALSE
; /* traceroute picks the src address */
178 * flow and class are specific to IPv6, tos and off are specific to IPv4.
179 * Each protocol uses the ones that are specific to itself, and ignores
182 static uint_t flow
= 0; /* IPv6 flow info */
183 static uint_t
class = 0; /* IPv6 class */
184 uchar_t tos
= 0; /* IPv4 type-of-service */
185 ushort_t off
= 0; /* set DF bit */
187 static jmp_buf env
; /* stack environment for longjmp() */
188 boolean_t raw_req
; /* if sndsock for IPv4 must be raw */
191 * Name service lookup related data.
193 static mutex_t tr_nslock
= ERRORCHECKMUTEX
;
194 static boolean_t tr_nsactive
= B_FALSE
; /* Lookup ongoing */
195 static hrtime_t tr_nsstarttime
; /* Start time */
196 static int tr_nssleeptime
= 2; /* Interval between checks */
197 static int tr_nswarntime
= 2; /* Interval to warn after */
200 static uint_t
calc_packetlen(int, struct pr_set
*);
201 extern int check_reply(struct msghdr
*, int, int, uchar_t
*, uchar_t
*);
202 extern int check_reply6(struct msghdr
*, int, int, uchar_t
*, uchar_t
*);
203 static double deltaT(struct timeval
*, struct timeval
*);
204 static char *device_name(struct ifaddrlist
*, int, union any_in_addr
*,
206 extern void *find_ancillary_data(struct msghdr
*, int, int);
207 static boolean_t
has_addr(struct addrinfo
*, union any_in_addr
*);
208 static struct ifaddrlist
*find_device(struct ifaddrlist
*, int, char *);
209 static struct ifaddrlist
*find_ifaddr(struct ifaddrlist
*, int,
210 union any_in_addr
*, int);
211 static void get_gwaddrs(char **, int, union any_in_addr
*,
212 union any_in_addr
*, int *, int *);
213 static void get_hostinfo(char *, int, struct addrinfo
**);
214 char *inet_name(union any_in_addr
*, int);
215 ushort_t
in_cksum(ushort_t
*, int);
216 extern int ip_hdr_length_v6(ip6_t
*, int, uint8_t *);
217 extern char *pr_type(uchar_t
);
218 extern char *pr_type6(uchar_t
);
219 extern void print_addr(uchar_t
*, int, struct sockaddr
*);
220 extern void print_addr6(uchar_t
*, int, struct sockaddr
*);
221 extern boolean_t
print_icmp_other(uchar_t
, uchar_t
);
222 extern boolean_t
print_icmp_other6(uchar_t
, uchar_t
);
223 static void print_stats(int, int, double, double, double, double);
224 static void print_unknown_host_msg(const char *, const char *);
225 static void record_stats(double, int *, double *, double *, double *, double *);
226 static void resolve_nodes(int *, struct addrinfo
**);
227 static void select_src_addr(union any_in_addr
*, union any_in_addr
*, int);
228 extern void send_probe(int, struct sockaddr
*, struct ip
*, int, int,
229 struct timeval
*, int);
230 extern void send_probe6(int, struct msghdr
*, struct ip
*, int, int,
231 struct timeval
*, int);
232 extern void set_ancillary_data(struct msghdr
*, int, union any_in_addr
*, int,
234 extern struct ip
*set_buffers(int);
235 extern struct ip
*set_buffers6(int);
236 extern void set_IPv4opt_sourcerouting(int, union any_in_addr
*,
237 union any_in_addr
*);
238 static void set_sin(struct sockaddr
*, union any_in_addr
*, int);
239 static int set_src_addr(struct pr_set
*, struct ifaddrlist
**);
240 static void setup_protocol(struct pr_set
*, int);
241 static void setup_socket(struct pr_set
*, int);
242 static void sig_handler(int);
243 static int str2int(const char *, const char *, int, int);
244 static double str2dbl(const char *, const char *, double, double);
245 static void trace_it(struct addrinfo
*);
246 static void traceroute(union any_in_addr
*, struct msghdr
*, struct pr_set
*,
247 int, struct ifaddrlist
*);
248 static void tv_sub(struct timeval
*, struct timeval
*);
249 static void usage(void);
250 static int wait_for_reply(int, struct msghdr
*, struct timeval
*);
251 static double xsqrt(double);
252 static void *ns_warning_thr(void *);
258 main(int argc
, char **argv
)
260 struct addrinfo
*ai_dst
= NULL
; /* destination host */
262 * "probing_successful" indicates if we could successfully send probes,
263 * not necessarily received reply from the target (this behavior is from
264 * the original traceroute). It's B_FALSE if packlen is invalid, or no
267 boolean_t probing_successful
= B_FALSE
;
268 int longjmp_return
; /* return value from longjump */
273 char temp_buf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
277 * A raw socket will be used for IPv4 if there is sufficient
280 raw_req
= priv_ineffect(PRIV_NET_RAWACCESS
);
283 * We'll need the privilege only when we open the sockets; that's
284 * when we'll fail if the program has insufficient privileges.
286 (void) __init_suid_priv(PU_CLEARLIMITSET
, PRIV_NET_ICMPACCESS
,
287 raw_req
? PRIV_NET_RAWACCESS
: NULL
, NULL
);
289 (void) setlinebuf(stdout
);
291 if ((cp
= strrchr(argv
[0], '/')) != NULL
)
297 while ((op
= getopt(argc
, argv
, "adFIlnrSvxA:c:f:g:i:L:m:P:p:Q:q:s:"
301 if (strcmp(optarg
, "inet") == 0) {
302 family_input
= AF_INET
;
303 } else if (strcmp(optarg
, "inet6") == 0) {
304 family_input
= AF_INET6
;
307 "%s: unknown address family %s\n",
318 class = str2int(optarg
, "traffic class", 0,
327 first_ttl
= str2int(optarg
, "first ttl", 1, MAXTTL
);
338 "%s: privilege to specify a loose source "
339 "route gateway is unavailable\n",
343 if (gw_count
>= MAXMAX_GWS
) {
345 "%s: Too many gateways\n", prog
);
348 gwlist
[gw_count
] = strdup(optarg
);
349 if (gwlist
[gw_count
] == NULL
) {
350 Fprintf(stderr
, "%s: strdup %s\n", prog
,
363 /* this can be IF name or IF index */
364 if_index
= (uint_t
)strtol(optarg
, &ep
, 10);
366 /* convert IF index <--> IF name */
367 if (errno
!= 0 || *ep
!= '\0') {
369 if_index
= if_nametoindex((const char *)device
);
372 * In case it fails, check to see if the problem
373 * is other than "IF not found".
375 if (if_index
== 0 && errno
!= ENXIO
) {
376 Fprintf(stderr
, "%s: if_nametoindex:"
377 "%s\n", prog
, strerror(errno
));
381 device
= (char *)malloc(LIFNAMSIZ
+ 1);
382 if (device
== NULL
) {
383 Fprintf(stderr
, "%s: malloc: %s\n",
384 prog
, strerror(errno
));
388 device
= if_indextoname(if_index
, device
);
389 if (device
!= NULL
) {
390 device
[LIFNAMSIZ
] = '\0';
391 } else if (errno
!= ENXIO
) {
393 * The problem was other than "index
396 Fprintf(stderr
, "%s: if_indextoname:"
397 "%s\n", prog
, strerror(errno
));
402 if (device
== NULL
|| if_index
== 0) {
403 Fprintf(stderr
, "%s: interface %s "
404 "doesn't match any actual interfaces\n",
415 flow
= str2int(optarg
, "flow label", 0, MAX_FLOW_LABEL
);
419 max_ttl
= str2int(optarg
, "max ttl(hop limit)", 1,
428 pause
= str2dbl(optarg
, "pause", 0, INT_MAX
);
429 delay
.tv_sec
= (time_t)pause
;
430 delay
.tv_usec
= (suseconds_t
)((pause
- delay
.tv_sec
) *
435 port
= str2int(optarg
, "port", 1, MAX_PORT
);
439 max_timeout
= str2int(optarg
, "max timeout", 1, -1);
443 nprobes
= str2int(optarg
, "nprobes", 1, -1);
447 options
|= SO_DONTROUTE
;
451 collect_stat
= B_TRUE
;
456 * set the ip source address of the outbound
457 * probe (e.g., on a multi-homed host).
459 source_input
= optarg
;
463 tos
= (uchar_t
)str2int(optarg
, "tos", 0, MAX_TOS
);
476 waittime
= str2int(optarg
, "wait time", 2, -1);
486 * If it's probe_all, SIGQUIT makes traceroute exit(). But we set the
487 * address to jump back to in traceroute(). Until then, we'll need to
488 * temporarily specify one.
491 if ((longjmp_return
= setjmp(env
)) != 0) {
492 if (longjmp_return
== SIGQUIT
) {
493 Printf("(exiting)\n");
495 } else { /* should never happen */
499 (void) signal(SIGQUIT
, sig_handler
);
502 if ((gw_count
> 0) && (options
& SO_DONTROUTE
)) {
503 Fprintf(stderr
, "%s: loose source route gateways (-g)"
504 " cannot be specified when probe packets are sent"
505 " directly to a host on an attached network (-r)\n",
511 if (i
== 1 || i
== 2) {
512 hostname
= argv
[optind
];
515 /* accept any length now, we'll check it later */
516 packlen_input
= str2int(argv
[optind
+ 1],
517 "packet length", 0, -1);
523 if (first_ttl
> max_ttl
) {
525 "%s: first ttl(hop limit) (%d) may not be greater"
526 " than max ttl(hop limit) (%d)\n",
527 prog
, first_ttl
, max_ttl
);
532 * Start up the name services warning thread.
534 if (thr_create(NULL
, 0, ns_warning_thr
, NULL
,
535 THR_DETACHED
| THR_DAEMON
, NULL
) != 0) {
536 Fprintf(stderr
, "%s: failed to create name services "
537 "thread: %s\n", prog
, strerror(errno
));
542 /* resolve hostnames */
543 resolve_nodes(&family_input
, &ai_dst
);
544 if (ai_dst
== NULL
) {
549 * If it's probe_all, SIGINT makes traceroute skip to probing next IP
550 * address of the target. The new interrupt handler is assigned in
551 * traceroute() function. Until then let's ignore the signal.
554 (void) signal(SIGINT
, SIG_IGN
);
556 ident
= (getpid() & 0xffff) | 0x8000;
559 * We KNOW that probe_all == TRUE if family is AF_UNSPEC,
560 * since family is set to the specific AF found unless it's
561 * probe_all. So if family == AF_UNSPEC, we need to init pr4 and pr6.
563 switch (family_input
) {
565 pr4
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
568 "%s: malloc %s\n", prog
, strerror(errno
));
571 pr6
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
574 "%s: malloc %s\n", prog
, strerror(errno
));
577 setup_protocol(pr6
, AF_INET6
);
578 setup_protocol(pr4
, AF_INET
);
579 outip6
= (*pr6
->set_buffers_fn
)(pr6
->packlen
);
580 setup_socket(pr6
, pr6
->packlen
);
582 outip4
= (*pr4
->set_buffers_fn
)(pr4
->packlen
);
583 setup_socket(pr4
, pr4
->packlen
);
584 num_ifs6
= set_src_addr(pr6
, &al6
);
585 num_ifs4
= set_src_addr(pr4
, &al4
);
588 pr6
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
591 "%s: malloc %s\n", prog
, strerror(errno
));
594 setup_protocol(pr6
, AF_INET6
);
595 outip6
= (*pr6
->set_buffers_fn
)(pr6
->packlen
);
596 setup_socket(pr6
, pr6
->packlen
);
597 num_ifs6
= set_src_addr(pr6
, &al6
);
600 pr4
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
603 "%s: malloc %s\n", prog
, strerror(errno
));
606 setup_protocol(pr4
, AF_INET
);
607 outip4
= (*pr4
->set_buffers_fn
)(pr4
->packlen
);
608 setup_socket(pr4
, pr4
->packlen
);
609 num_ifs4
= set_src_addr(pr4
, &al4
);
612 Fprintf(stderr
, "%s: unknow address family.\n", prog
);
616 if (num_v4
+ num_v6
> 1 && !probe_all
) {
617 if (ai_dst
->ai_family
== AF_INET
) {
619 "%s: Warning: %s has multiple addresses;"
620 " using %s\n", prog
, hostname
,
622 /* LINTED E_BAD_PTR_CAST_ALIGN */
623 (void *)&((struct sockaddr_in
*)
624 ai_dst
->ai_addr
)->sin_addr
,
625 temp_buf
, sizeof (temp_buf
)));
628 "%s: Warning: %s has multiple addresses;"
629 " using %s\n", prog
, hostname
,
631 /* LINTED E_BAD_PTR_CAST_ALIGN */
632 (void *)&((struct sockaddr_in6
*)
633 ai_dst
->ai_addr
)->sin6_addr
,
634 temp_buf
, sizeof (temp_buf
)));
638 if (num_ifs4
+ num_ifs6
> 0) {
640 probing_successful
= B_TRUE
;
643 (void) close(rcvsock4
);
644 (void) close(sndsock4
);
645 (void) close(rcvsock6
);
646 (void) close(sndsock6
);
649 * if we could probe any of the IP addresses of the target, that means
650 * this was a successful operation
652 if (probing_successful
)
653 return (EXIT_SUCCESS
);
655 return (EXIT_FAILURE
);
659 * print "unknown host" message
662 print_unknown_host_msg(const char *protocol
, const char *host
)
664 Fprintf(stderr
, "%s: unknown%s host %s\n", prog
, protocol
, host
);
668 * resolve destination host and gateways
671 resolve_nodes(int *family
, struct addrinfo
**ai_dstp
)
673 struct addrinfo
*ai_dst
= NULL
;
674 struct addrinfo
*aip
= NULL
;
675 int num_resolved_gw
= 0;
676 int num_resolved_gw6
= 0;
678 get_hostinfo(hostname
, *family
, &ai_dst
);
679 if (ai_dst
== NULL
) {
680 print_unknown_host_msg("", hostname
);
683 /* Get a count of the v4 & v6 addresses */
684 for (aip
= ai_dst
; aip
!= NULL
; aip
= aip
->ai_next
) {
685 switch (aip
->ai_family
) {
695 if (*family
== AF_UNSPEC
&& !probe_all
) {
696 *family
= ai_dst
->ai_family
;
699 /* resolve gateways */
701 get_gwaddrs(gwlist
, *family
, gwIPlist
, gwIP6list
,
702 &num_resolved_gw
, &num_resolved_gw6
);
704 /* we couldn't resolve a gateway as an IPv6 host */
705 if (num_resolved_gw6
!= gw_count
&& num_v6
!= 0) {
706 if (*family
== AF_INET6
|| *family
== AF_UNSPEC
)
707 print_unknown_host_msg(" IPv6",
708 gwlist
[num_resolved_gw6
]);
712 /* we couldn't resolve a gateway as an IPv4 host */
713 if (num_resolved_gw
!= gw_count
&& num_v4
!= 0) {
714 if (*family
== AF_INET
|| *family
== AF_UNSPEC
)
715 print_unknown_host_msg(" IPv4",
716 gwlist
[num_resolved_gw
]);
721 *ai_dstp
= (num_v4
+ num_v6
> 0) ? ai_dst
: NULL
;
725 * Given IP address or hostname, return v4 and v6 hostinfo lists.
726 * Assumes that hostinfo ** ptrs are non-null.
729 get_hostinfo(char *host
, int family
, struct addrinfo
**aipp
)
731 struct addrinfo hints
, *ai
;
732 struct in6_addr addr6
;
734 char abuf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
738 * Take care of v4-mapped addresses. It should run same as v4, after
739 * chopping off the prefix, leaving the IPv4 address
741 if ((inet_pton(AF_INET6
, host
, &addr6
) > 0) &&
742 IN6_IS_ADDR_V4MAPPED(&addr6
)) {
743 /* peel off the "mapping" stuff, leaving 32 bit IPv4 address */
744 IN6_V4MAPPED_TO_INADDR(&addr6
, &addr
);
746 /* convert it back to a string */
747 (void) inet_ntop(AF_INET
, &addr
, abuf
, sizeof (abuf
));
749 /* now the host is an IPv4 address */
750 (void) strcpy(host
, abuf
);
753 * If it's a mapped address, we convert it into IPv4
754 * address because traceroute will send and receive IPv4
755 * packets for that address. Therefore, it's a failure case to
756 * ask get_hostinfo() to treat a mapped address as an IPv6
759 if (family
== AF_INET6
) {
764 (void) memset(&hints
, 0, sizeof (hints
));
765 hints
.ai_family
= family
;
766 hints
.ai_flags
= AI_ADDRCONFIG
| AI_CANONNAME
;
767 rc
= getaddrinfo(host
, NULL
, &hints
, &ai
);
769 if (rc
!= EAI_NONAME
)
770 Fprintf(stderr
, "%s: getaddrinfo: %s\n", prog
,
779 * Calculate the packet length to be used, and check against the valid range.
780 * Returns -1 if range check fails.
783 calc_packetlen(int plen_input
, struct pr_set
*pr
)
785 int minpacket
; /* min ip packet size */
786 int optlen
; /* length of ip options */
790 * LBNL bug fixed: miscalculation of optlen
796 * 5 (NO OPs) + 3 (code, len, ptr) + gateways
797 * IP options field can hold up to 9 gateways. But the API
798 * allows you to specify only 8, because the last one is the
799 * destination host. When this packet is sent, on the wire
800 * you see one gateway replaced by 4 NO OPs. The other 1 NO
801 * OP is for alignment
805 * Well, formula is different, but the result is same.
806 * 8 byte fixed part for Type 0 Routing header, followed by
809 optlen
= 8 + gw_count
* pr
->addr_len
;
814 /* take care of the packet length calculations and checks */
815 minpacket
= pr
->ip_hdr_len
+ sizeof (struct outdata
) + optlen
;
817 minpacket
+= pr
->icmp_minlen
; /* minimum ICMP header size */
819 minpacket
+= sizeof (struct udphdr
);
822 plen
= minpacket
; /* minimum sized packet */
823 } else if (minpacket
> plen
|| plen
> IP_MAXPACKET
) {
824 Fprintf(stderr
, "%s: %s packet size must be >= %d and <= %d\n",
825 prog
, pr
->name
, minpacket
, IP_MAXPACKET
);
833 * Sets the source address by resolving -i and -s arguments, or if -i and -s
834 * don't dictate any, it sets the pick_src to make sure traceroute uses the
835 * kernel's pick of the source address.
836 * Returns number of interfaces configured on the source host, 0 on error or
837 * there's no interface which is up amd not a loopback.
840 set_src_addr(struct pr_set
*pr
, struct ifaddrlist
**alp
)
842 union any_in_addr
*ap
;
843 struct ifaddrlist
*al
= NULL
;
844 struct ifaddrlist
*tmp1_al
= NULL
;
845 struct ifaddrlist
*tmp2_al
= NULL
;
846 /* LINTED E_BAD_PTR_CAST_ALIGN */
847 struct sockaddr_in
*sin_from
= (struct sockaddr_in
*)pr
->from
;
848 /* LINTED E_BAD_PTR_CAST_ALIGN */
849 struct sockaddr_in6
*sin6_from
= (struct sockaddr_in6
*)pr
->from
;
850 struct addrinfo
*aip
;
851 char errbuf
[ERRBUFSIZE
];
852 char abuf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
853 int num_ifs
; /* all the interfaces */
854 int num_src_ifs
; /* exclude loopback and down */
856 uint_t ifaddrflags
= 0;
858 source
= source_input
;
861 ifaddrflags
|= LIFC_UNDER_IPMP
;
863 /* get the interface address list */
864 num_ifs
= ifaddrlist(&al
, pr
->family
, ifaddrflags
, errbuf
);
866 Fprintf(stderr
, "%s: ifaddrlist: %s\n", prog
, errbuf
);
871 for (i
= 0; i
< num_ifs
; i
++) {
872 if (!(al
[i
].flags
& IFF_LOOPBACK
) && (al
[i
].flags
& IFF_UP
))
876 if (num_src_ifs
== 0) {
877 Fprintf(stderr
, "%s: can't find any %s network interfaces\n",
882 /* verify the device */
883 if (device
!= NULL
) {
884 tmp1_al
= find_device(al
, num_ifs
, device
);
886 if (tmp1_al
== NULL
) {
887 Fprintf(stderr
, "%s: %s (index %d) is an invalid %s"
888 " interface\n", prog
, device
, if_index
, pr
->name
);
894 /* verify the source address */
895 if (source
!= NULL
) {
896 get_hostinfo(source
, pr
->family
, &aip
);
899 "%s: %s is an invalid %s source address\n",
900 prog
, source
, pr
->name
);
906 source
= aip
->ai_canonname
;
908 if (pr
->family
== AF_INET
)
909 ap
= (union any_in_addr
*)
910 /* LINTED E_BAD_PTR_CAST_ALIGN */
911 &((struct sockaddr_in
*)aip
->ai_addr
)->sin_addr
;
913 ap
= (union any_in_addr
*)
914 /* LINTED E_BAD_PTR_CAST_ALIGN */
915 &((struct sockaddr_in6
*)aip
->ai_addr
)->sin6_addr
;
918 * LBNL bug fixed: used to accept any src address
920 tmp2_al
= find_ifaddr(al
, num_ifs
, ap
, pr
->family
);
921 if (tmp2_al
== NULL
) {
922 (void) inet_ntop(pr
->family
, ap
, abuf
, sizeof (abuf
));
923 Fprintf(stderr
, "%s: %s is not a local %s address\n",
924 prog
, abuf
, pr
->name
);
933 if (source
== NULL
) { /* no -s used */
934 if (device
== NULL
) { /* no -i used, no -s used */
936 } else { /* -i used, no -s used */
938 * -i used, but not -s, and it's IPv4: set the source
939 * address to whatever the interface has configured on
942 if (pr
->family
== AF_INET
)
943 set_sin(pr
->from
, &(tmp1_al
->addr
), pr
->family
);
947 } else { /* -s used */
948 if (device
== NULL
) { /* no -i used, -s used */
949 set_sin(pr
->from
, ap
, pr
->family
);
951 if (aip
->ai_next
!= NULL
) {
952 (void) inet_ntop(pr
->family
, pr
->from_sin_addr
,
953 abuf
, sizeof (abuf
));
954 Fprintf(stderr
, "%s: Warning: %s has multiple "
955 "addresses; using %s\n", prog
, source
,
958 } else { /* -i and -s used */
960 * Make sure the source specified matches the
961 * interface address. You only care about this for IPv4
962 * IPv6 can handle IF not matching src address
964 if (pr
->family
== AF_INET
) {
965 if (!has_addr(aip
, &tmp1_al
->addr
)) {
967 "%s: %s is not on interface %s\n",
968 prog
, source
, device
);
972 * make sure we use the one matching the
973 * interface's address
978 set_sin(pr
->from
, ap
, pr
->family
);
983 * Binding at this point will set the source address to be used
984 * for both IPv4 (when raw IP datagrams are not required) and
985 * IPv6. If the address being bound to is zero, then the kernel
986 * will end up choosing the source address when the datagram is
989 * For raw IPv4 datagrams, the source address is initialized
990 * within traceroute() along with the outbound destination
993 if (pr
->family
== AF_INET
&& !raw_req
) {
994 sin_from
->sin_family
= AF_INET
;
995 sin_from
->sin_port
= htons(ident
);
996 if (bind(sndsock4
, (struct sockaddr
*)pr
->from
,
997 sizeof (struct sockaddr_in
)) < 0) {
998 Fprintf(stderr
, "%s: bind: %s\n", prog
,
1002 } else if (pr
->family
== AF_INET6
) {
1003 sin6_from
->sin6_family
= AF_INET6
;
1004 sin6_from
->sin6_port
= htons(ident
);
1005 if (bind(sndsock6
, (struct sockaddr
*)pr
->from
,
1006 sizeof (struct sockaddr_in6
)) < 0) {
1007 Fprintf(stderr
, "%s: bind: %s\n", prog
,
1012 whereto6
.sin6_flowinfo
= htonl((class << 20) | flow
);
1019 * Returns the complete ifaddrlist structure matching the desired interface
1020 * address. Ignores interfaces which are either down or loopback.
1022 static struct ifaddrlist
*
1023 find_ifaddr(struct ifaddrlist
*al
, int len
, union any_in_addr
*addr
,
1026 struct ifaddrlist
*tmp_al
= al
;
1028 size_t addr_len
= (family
== AF_INET
) ? sizeof (struct in_addr
) :
1029 sizeof (struct in6_addr
);
1031 for (i
= 0; i
< len
; i
++, tmp_al
++) {
1032 if ((!(tmp_al
->flags
& IFF_LOOPBACK
) &&
1033 (tmp_al
->flags
& IFF_UP
)) &&
1034 (memcmp(&tmp_al
->addr
, addr
, addr_len
) == 0))
1046 * Returns the complete ifaddrlist structure matching the desired interface name
1047 * Ignores interfaces which are either down or loopback.
1049 static struct ifaddrlist
*
1050 find_device(struct ifaddrlist
*al
, int len
, char *device
)
1052 struct ifaddrlist
*tmp_al
= al
;
1055 for (i
= 0; i
< len
; i
++, tmp_al
++) {
1056 if ((!(tmp_al
->flags
& IFF_LOOPBACK
) &&
1057 (tmp_al
->flags
& IFF_UP
)) &&
1058 (strcmp(tmp_al
->device
, device
) == 0))
1070 * returns B_TRUE if given hostinfo contains the given address
1073 has_addr(struct addrinfo
*ai
, union any_in_addr
*addr
)
1075 struct addrinfo
*ai_tmp
= NULL
;
1076 union any_in_addr
*ap
;
1078 for (ai_tmp
= ai
; ai_tmp
!= NULL
; ai_tmp
= ai_tmp
->ai_next
) {
1079 if (ai_tmp
->ai_family
== AF_INET6
)
1081 ap
= (union any_in_addr
*)
1082 /* LINTED E_BAD_PTR_CAST_ALIGN */
1083 &((struct sockaddr_in
*)ai_tmp
->ai_addr
)->sin_addr
;
1084 if (memcmp(ap
, addr
, sizeof (struct in_addr
)) == 0)
1088 if (ai_tmp
!= NULL
) {
1096 * Resolve the gateway names, splitting results into v4 and v6 lists.
1097 * Gateway addresses are added to the appropriate passed-in array; the
1098 * number of resolved gateways for each af is returned in resolved[6].
1099 * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
1100 * and resolved[6] ptrs are non-null; ignores array and counter if the
1101 * address family param makes them irrelevant.
1104 get_gwaddrs(char **gwlist
, int family
, union any_in_addr
*gwIPlist
,
1105 union any_in_addr
*gwIPlist6
, int *resolved
, int *resolved6
)
1108 boolean_t check_v4
= B_TRUE
, check_v6
= B_TRUE
;
1109 struct addrinfo
*ai
= NULL
;
1110 struct addrinfo
*aip
= NULL
;
1112 *resolved
= *resolved6
= 0;
1126 if (check_v4
&& gw_count
>= MAX_GWS
) {
1128 Fprintf(stderr
, "%s: too many IPv4 gateways\n", prog
);
1131 if (check_v6
&& gw_count
>= MAX_GWS6
) {
1133 Fprintf(stderr
, "%s: too many IPv6 gateways\n", prog
);
1137 for (i
= 0; i
< gw_count
; i
++) {
1138 if (!check_v4
&& !check_v6
)
1140 get_hostinfo(gwlist
[i
], family
, &ai
);
1143 if (check_v4
&& num_v4
!= 0) {
1145 for (aip
= ai
; aip
!= NULL
; aip
= aip
->ai_next
) {
1146 if (aip
->ai_family
== AF_INET
) {
1147 /* LINTED E_BAD_PTR_CAST_ALIGN */
1148 bcopy(&((struct sockaddr_in
*)
1149 aip
->ai_addr
)->sin_addr
,
1157 } else if (check_v4
) {
1160 if (check_v6
&& num_v6
!= 0) {
1162 for (aip
= ai
; aip
!= NULL
; aip
= aip
->ai_next
) {
1163 if (aip
->ai_family
== AF_INET6
) {
1164 /* LINTED E_BAD_PTR_CAST_ALIGN */
1165 bcopy(&((struct sockaddr_in6
*)
1166 aip
->ai_addr
)->sin6_addr
,
1167 &gwIPlist6
[i
].addr6
,
1174 } else if (check_v6
) {
1182 * set protocol specific values here
1185 setup_protocol(struct pr_set
*pr
, int family
)
1188 * Set the global variables for each AF. This is going to save us lots
1189 * of "if (family == AF_INET)... else .."
1191 pr
->family
= family
;
1193 if (family
== AF_INET
) {
1196 "%s: Warning: checksums disabled\n", prog
);
1198 (void) strcpy(pr
->name
, "IPv4");
1199 (void) strcpy(pr
->icmp
, "icmp");
1200 pr
->icmp_minlen
= ICMP_MINLEN
;
1201 pr
->addr_len
= sizeof (struct in_addr
);
1202 pr
->ip_hdr_len
= sizeof (struct ip
);
1203 pr
->sock_size
= sizeof (struct sockaddr_in
);
1204 pr
->to
= (struct sockaddr
*)&whereto
;
1205 pr
->from
= (struct sockaddr
*)&wherefrom
;
1206 pr
->from_sin_addr
= (void *)&wherefrom
.sin_addr
;
1207 pr
->gwIPlist
= gwIPlist
;
1208 pr
->set_buffers_fn
= set_buffers
;
1209 pr
->check_reply_fn
= check_reply
;
1210 pr
->print_icmp_other_fn
= print_icmp_other
;
1211 pr
->print_addr_fn
= print_addr
;
1212 pr
->packlen
= calc_packetlen(packlen_input
, pr
);
1214 (void) strcpy(pr
->name
, "IPv6");
1215 (void) strcpy(pr
->icmp
, "ipv6-icmp");
1216 pr
->icmp_minlen
= ICMP6_MINLEN
;
1217 pr
->addr_len
= sizeof (struct in6_addr
);
1218 pr
->ip_hdr_len
= sizeof (struct ip6_hdr
);
1219 pr
->sock_size
= sizeof (struct sockaddr_in6
);
1220 pr
->to
= (struct sockaddr
*)&whereto6
;
1221 pr
->from
= (struct sockaddr
*)&wherefrom6
;
1222 pr
->from_sin_addr
= (void *)&wherefrom6
.sin6_addr
;
1223 pr
->gwIPlist
= gwIP6list
;
1224 pr
->set_buffers_fn
= set_buffers6
;
1225 pr
->check_reply_fn
= check_reply6
;
1226 pr
->print_icmp_other_fn
= print_icmp_other6
;
1227 pr
->print_addr_fn
= print_addr6
;
1228 pr
->packlen
= calc_packetlen(packlen_input
, pr
);
1230 if (pr
->packlen
== 0)
1235 * setup the sockets for the given protocol's address family
1238 setup_socket(struct pr_set
*pr
, int packet_len
)
1241 struct protoent
*pe
;
1248 if ((pe
= getprotobyname(pr
->icmp
)) == NULL
) {
1249 Fprintf(stderr
, "%s: unknown protocol %s\n", prog
, pr
->icmp
);
1253 /* privilege bracketing */
1254 (void) __priv_bracket(PRIV_ON
);
1256 if ((rsock
= socket(pr
->family
, SOCK_RAW
, pe
->p_proto
)) < 0) {
1257 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
, strerror(errno
));
1261 if (options
& SO_DEBUG
) {
1262 if (setsockopt(rsock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1264 Fprintf(stderr
, "%s: SO_DEBUG: %s\n", prog
,
1269 if (options
& SO_DONTROUTE
) {
1270 if (setsockopt(rsock
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
1272 Fprintf(stderr
, "%s: SO_DONTROUTE: %s\n", prog
,
1278 if (pr
->family
== AF_INET6
) {
1279 /* Enable receipt of destination address info */
1280 if (setsockopt(rsock
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
1281 (char *)&on
, sizeof (on
)) < 0) {
1282 Fprintf(stderr
, "%s: IPV6_RECVPKTINFO: %s\n", prog
,
1286 /* Enable receipt of hoplimit info */
1287 if (setsockopt(rsock
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
,
1288 (char *)&on
, sizeof (on
)) < 0) {
1289 Fprintf(stderr
, "%s: IPV6_RECVHOPLIMIT: %s\n", prog
,
1297 * Initialize the socket type and protocol based on the address
1298 * family, whether or not a raw IP socket is required (for IPv4)
1299 * or whether ICMP will be used instead of UDP.
1301 * For historical reasons, the datagrams sent out by
1302 * traceroute(8) do not have the "don't fragment" flag set. For
1303 * this reason as well as the ability to set the Loose Source and
1304 * Record Route (LSRR) option, a raw IP socket will be used for
1305 * IPv4 when run in the global zone. Otherwise, the actual
1306 * datagram that will be sent will be a regular UDP or ICMP echo
1307 * request packet. However for convenience and for future options
1308 * when other IP header information may be specified using
1309 * traceroute, the buffer including the raw IP and UDP or ICMP
1310 * header is always filled in. When the probe is actually sent,
1311 * the size of the request and the start of the packet is set
1312 * according to the type of datagram to send.
1314 if (pr
->family
== AF_INET
&& raw_req
) {
1316 proto
= IPPROTO_RAW
;
1317 } else if (useicmp
) {
1319 if (pr
->family
== AF_INET
)
1320 proto
= IPPROTO_ICMP
;
1322 proto
= IPPROTO_ICMPV6
;
1325 proto
= IPPROTO_UDP
;
1327 ssock
= socket(pr
->family
, type
, proto
);
1330 if (proto
== IPPROTO_RAW
) {
1331 Fprintf(stderr
, "%s: raw socket: %s\n", prog
,
1333 } else if (proto
== IPPROTO_UDP
) {
1334 Fprintf(stderr
, "%s: udp socket: %s\n", prog
,
1337 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
,
1343 if (setsockopt(ssock
, SOL_SOCKET
, SO_SNDBUF
, (char *)&packet_len
,
1344 sizeof (packet_len
)) < 0) {
1345 Fprintf(stderr
, "%s: SO_SNDBUF: %s\n", prog
, strerror(errno
));
1349 if (pr
->family
== AF_INET
&& raw_req
) {
1350 if (setsockopt(ssock
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
1352 Fprintf(stderr
, "%s: IP_HDRINCL: %s\n", prog
,
1358 if (options
& SO_DEBUG
) {
1359 if (setsockopt(ssock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1361 Fprintf(stderr
, "%s: SO_DEBUG: %s\n", prog
,
1366 if (options
& SO_DONTROUTE
) {
1367 if (setsockopt(ssock
, SOL_SOCKET
, SO_DONTROUTE
,
1368 (char *)&on
, sizeof (on
)) < 0) {
1369 Fprintf(stderr
, "%s: SO_DONTROUTE: %s\n", prog
,
1376 * If a raw IPv4 packet is going to be sent, the Type of Service
1377 * field in the packet will be initialized in set_buffers().
1378 * Otherwise, it is initialized here using the IPPROTO_IP level
1381 if (settos
&& !raw_req
) {
1383 if (setsockopt(ssock
, IPPROTO_IP
, IP_TOS
, (char *)&int_op
,
1384 sizeof (int_op
)) < 0) {
1385 Fprintf(stderr
, "%s: IP_TOS: %s\n", prog
,
1391 /* We enable or disable to not depend on the kernel default */
1392 if (pr
->family
== AF_INET
) {
1393 if (setsockopt(ssock
, IPPROTO_IP
, IP_DONTFRAG
,
1394 (char *)&dontfrag
, sizeof (dontfrag
)) == -1) {
1395 Fprintf(stderr
, "%s: IP_DONTFRAG %s\n", prog
,
1400 if (setsockopt(ssock
, IPPROTO_IPV6
, IPV6_DONTFRAG
,
1401 (char *)&dontfrag
, sizeof (dontfrag
)) == -1) {
1402 Fprintf(stderr
, "%s: IPV6_DONTFRAG %s\n", prog
,
1408 if (pr
->family
== AF_INET
) {
1415 /* Revert to non-privileged user after configuring sockets */
1416 (void) __priv_bracket(PRIV_OFF
);
1420 * If we are "probing all", this function calls traceroute() for each IP address
1421 * of the target, otherwise calls only once. Returns B_FALSE if traceroute()
1425 trace_it(struct addrinfo
*ai_dst
)
1428 int num_dst_IPaddrs
;
1429 struct addrinfo
*aip
;
1433 num_dst_IPaddrs
= 1;
1435 num_dst_IPaddrs
= num_v4
+ num_v6
;
1438 * Initialize the msg6 structure using the hoplimit for the first
1439 * probe packet, gateway addresses and the outgoing interface index.
1441 if (ai_dst
->ai_family
== AF_INET6
|| (probe_all
&& num_v6
)) {
1442 msg6
.msg_control
= NULL
;
1443 msg6
.msg_controllen
= 0;
1444 set_ancillary_data(&msg6
, first_ttl
, pr6
->gwIPlist
, gw_count
,
1448 /* run traceroute for all the IP addresses of the multihomed dest */
1449 for (aip
= ai_dst
, i
= 0; i
< num_dst_IPaddrs
&& aip
!= NULL
; i
++) {
1450 union any_in_addr
*addrp
;
1451 if (aip
->ai_family
== AF_INET
) {
1452 addrp
= (union any_in_addr
*)
1453 /* LINTED E_BAD_PTR_CAST_ALIGN */
1454 &((struct sockaddr_in
*)
1455 aip
->ai_addr
)->sin_addr
;
1456 set_sin((struct sockaddr
*)pr4
->to
, addrp
,
1458 traceroute(addrp
, &msg6
, pr4
, num_ifs4
, al4
);
1460 addrp
= (union any_in_addr
*)
1461 /* LINTED E_BAD_PTR_CAST_ALIGN */
1462 &((struct sockaddr_in6
*)
1463 aip
->ai_addr
)->sin6_addr
;
1464 set_sin((struct sockaddr
*)pr6
->to
, addrp
,
1466 traceroute(addrp
, &msg6
, pr6
, num_ifs6
, al6
);
1469 if (i
< (num_dst_IPaddrs
- 1))
1470 (void) putchar('\n');
1475 * set the IP address in a sockaddr struct
1478 set_sin(struct sockaddr
*sock
, union any_in_addr
*addr
, int family
)
1480 sock
->sa_family
= family
;
1482 if (family
== AF_INET
)
1483 /* LINTED E_BAD_PTR_CAST_ALIGN */
1484 ((struct sockaddr_in
*)sock
)->sin_addr
= addr
->addr
;
1486 /* LINTED E_BAD_PTR_CAST_ALIGN */
1487 ((struct sockaddr_in6
*)sock
)->sin6_addr
= addr
->addr6
;
1491 * returns the IF name on which the given IP address is configured
1494 device_name(struct ifaddrlist
*al
, int len
, union any_in_addr
*ip_addr
,
1498 struct ifaddrlist
*tmp_al
;
1502 for (i
= 0; i
< len
; i
++, tmp_al
++) {
1503 if (memcmp(&tmp_al
->addr
, ip_addr
, pr
->addr_len
) == 0) {
1504 return (tmp_al
->device
);
1512 * Trace the route to the host with given IP address.
1515 traceroute(union any_in_addr
*ip_addr
, struct msghdr
*msg6
, struct pr_set
*pr
,
1516 int num_ifs
, struct ifaddrlist
*al
)
1520 uchar_t type
; /* icmp type */
1521 uchar_t code
; /* icmp code */
1524 char abuf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
1525 int longjmp_return
; /* return value from longjump */
1526 struct ip
*ip
= (struct ip
*)packet
;
1527 boolean_t got_there
= B_FALSE
; /* we hit the destination */
1528 static boolean_t first_pkt
= B_TRUE
;
1529 int hoplimit
; /* hoplimit for IPv6 packets */
1530 struct in6_addr addr6
;
1531 int num_src_ifs
; /* excludes down and loopback */
1532 struct msghdr in_msg
;
1538 msg6
->msg_name
= pr
->to
;
1539 msg6
->msg_namelen
= sizeof (struct sockaddr_in6
);
1540 sndsock
= (pr
->family
== AF_INET
) ? sndsock4
: sndsock6
;
1541 rcvsock
= (pr
->family
== AF_INET
) ? rcvsock4
: rcvsock6
;
1543 /* carry out the source address selection */
1545 union any_in_addr src_addr
;
1550 * If there's a gateway, a routing header as a consequence, our
1551 * kernel picks the source address based on the first hop
1552 * address, rather than final destination address.
1555 (void) select_src_addr(pr
->gwIPlist
, &src_addr
,
1558 (void) select_src_addr(ip_addr
, &src_addr
, pr
->family
);
1560 set_sin(pr
->from
, &src_addr
, pr
->family
);
1562 /* filter out down and loopback interfaces */
1564 for (i
= 0; i
< num_ifs
; i
++) {
1565 if (!(al
[i
].flags
& IFF_LOOPBACK
) &&
1566 (al
[i
].flags
& IFF_UP
))
1570 if (num_src_ifs
> 1) {
1571 dev_name
= device_name(al
, num_ifs
, &src_addr
, pr
);
1572 if (dev_name
== NULL
)
1575 (void) inet_ntop(pr
->family
, pr
->from_sin_addr
, abuf
,
1578 "%s: Warning: Multiple interfaces found;"
1579 " using %s @ %s\n", prog
, abuf
, dev_name
);
1583 if (pr
->family
== AF_INET
) {
1584 outip4
->ip_src
= *(struct in_addr
*)pr
->from_sin_addr
;
1585 outip4
->ip_dst
= ip_addr
->addr
;
1589 * If the hostname is an IPv6 literal address, let's not print it twice.
1591 if (pr
->family
== AF_INET6
&&
1592 inet_pton(AF_INET6
, hostname
, &addr6
) > 0) {
1593 Fprintf(stderr
, "%s to %s", prog
, hostname
);
1595 Fprintf(stderr
, "%s to %s (%s)", prog
, hostname
,
1596 inet_ntop(pr
->family
, ip_addr
, abuf
, sizeof (abuf
)));
1600 Fprintf(stderr
, " from %s", source
);
1601 Fprintf(stderr
, ", %d hops max, %d byte packets\n", max_ttl
,
1603 (void) fflush(stderr
);
1606 * Setup the source routing for IPv4. For IPv6, we did the required
1607 * setup in the caller function, trace_it(), because it's independent
1608 * from the IP address of target.
1610 if (pr
->family
== AF_INET
&& gw_count
> 0)
1611 set_IPv4opt_sourcerouting(sndsock
, ip_addr
, pr
->gwIPlist
);
1614 /* interrupt handler sig_handler() jumps back to here */
1615 if ((longjmp_return
= setjmp(env
)) != 0) {
1616 switch (longjmp_return
) {
1618 Printf("(skipping)\n");
1621 Printf("(exiting)\n");
1623 default: /* should never happen */
1627 (void) signal(SIGINT
, sig_handler
);
1630 for (ttl
= first_ttl
; ttl
<= max_ttl
; ++ttl
) {
1631 union any_in_addr lastaddr
;
1633 double rtt
; /* for statistics */
1635 double rttmin
, rttmax
;
1636 double rttsum
, rttssq
;
1639 got_there
= B_FALSE
;
1643 * The following line clears both IPv4 and IPv6 address stored
1646 lastaddr
.addr6
= in6addr_any
;
1648 if ((ttl
== (first_ttl
+ 1)) && (options
& SO_DONTROUTE
)) {
1650 "%s: host %s is not on a directly-attached"
1651 " network\n", prog
, hostname
);
1655 Printf("%2d ", ttl
);
1656 (void) fflush(stdout
);
1658 for (probe
= 0; (probe
< nprobes
) && (timeouts
< max_timeout
);
1661 struct timeval t1
, t2
;
1664 * Put a delay before sending this probe packet. Don't
1665 * delay it if it's the very first packet.
1668 if (delay
.tv_sec
> 0)
1669 (void) sleep((uint_t
)delay
.tv_sec
);
1670 if (delay
.tv_usec
> 0)
1671 (void) usleep(delay
.tv_usec
);
1673 first_pkt
= B_FALSE
;
1676 (void) gettimeofday(&t1
, NULL
);
1678 if (pr
->family
== AF_INET
) {
1679 send_probe(sndsock
, pr
->to
, outip4
, seq
, ttl
,
1682 send_probe6(sndsock
, msg6
, outip6
, seq
, ttl
,
1686 /* prepare msghdr for recvmsg() */
1687 in_msg
.msg_name
= pr
->from
;
1688 in_msg
.msg_namelen
= pr
->sock_size
;
1690 iov
.iov_base
= (char *)packet
;
1691 iov
.iov_len
= sizeof (packet
);
1693 in_msg
.msg_iov
= &iov
;
1694 in_msg
.msg_iovlen
= 1;
1696 in_msg
.msg_control
= ancillary_data
;
1697 in_msg
.msg_controllen
= sizeof (ancillary_data
);
1699 while ((cc
= wait_for_reply(rcvsock
, &in_msg
,
1701 (void) gettimeofday(&t2
, NULL
);
1703 reply
= (*pr
->check_reply_fn
) (&in_msg
, cc
, seq
,
1706 in_msg
.msg_controllen
=
1707 sizeof (ancillary_data
);
1708 /* Skip short packet */
1709 if (reply
== REPLY_SHORT_PKT
) {
1716 * if reply comes from a different host, print
1719 if (memcmp(pr
->from_sin_addr
, &lastaddr
,
1720 pr
->addr_len
) != 0) {
1721 (*pr
->print_addr_fn
) ((uchar_t
*)packet
,
1723 /* store the address response */
1724 (void) memcpy(&lastaddr
,
1725 pr
->from_sin_addr
, pr
->addr_len
);
1728 rtt
= deltaT(&t1
, &t2
);
1730 record_stats(rtt
, &nreceived
, &rttmin
,
1731 &rttmax
, &rttsum
, &rttssq
);
1733 Printf(" %.3f ms", rtt
);
1736 if (pr
->family
== AF_INET6
) {
1737 intp
= find_ancillary_data(&in_msg
,
1738 IPPROTO_IPV6
, IPV6_HOPLIMIT
);
1742 "IPV6_HOPLIMIT ancillary "
1749 if (reply
== REPLY_GOT_TARGET
) {
1752 if (((pr
->family
== AF_INET
) &&
1753 (ip
->ip_ttl
<= 1)) ||
1754 ((pr
->family
== AF_INET6
) &&
1759 if (!collect_stat
&& showttl
) {
1760 if (pr
->family
== AF_INET
) {
1763 } else if (hoplimit
!= -1) {
1764 Printf(" (hop limit=%d)",
1769 if (reply
== REPLY_GOT_OTHER
) {
1770 if ((*pr
->print_icmp_other_fn
)
1777 if (pr
->family
== AF_INET
&&
1778 type
== ICMP_UNREACH
&&
1779 code
== ICMP_UNREACH_PROTOCOL
)
1785 seq
= (seq
+ 1) % (MAX_SEQ
+ 1);
1792 (void) fflush(stdout
);
1796 print_stats(probe
, nreceived
, rttmin
, rttmax
, rttsum
,
1800 (void) putchar('\n');
1802 /* either we hit the target or received too many unreachables */
1804 (unreachable
> 0 && unreachable
>= nprobes
- 1))
1808 /* Ignore the SIGINT between traceroute() runs */
1810 (void) signal(SIGINT
, SIG_IGN
);
1814 * for a given destination address and address family, it finds out what
1815 * source address kernel is going to pick
1818 select_src_addr(union any_in_addr
*dst_addr
, union any_in_addr
*src_addr
,
1822 struct sockaddr
*sock
;
1823 struct sockaddr_in
*sin
;
1824 struct sockaddr_in6
*sin6
;
1827 sock
= (struct sockaddr
*)malloc(sizeof (struct sockaddr_in6
));
1829 Fprintf(stderr
, "%s: malloc %s\n", prog
, strerror(errno
));
1832 (void) bzero(sock
, sizeof (struct sockaddr_in6
));
1834 if (family
== AF_INET
) {
1835 /* LINTED E_BAD_PTR_CAST_ALIGN */
1836 sin
= (struct sockaddr_in
*)sock
;
1837 sin
->sin_family
= AF_INET
;
1838 sin
->sin_addr
= dst_addr
->addr
;
1839 sin
->sin_port
= IPPORT_ECHO
; /* port shouldn't be 0 */
1840 sock_len
= sizeof (struct sockaddr_in
);
1842 /* LINTED E_BAD_PTR_CAST_ALIGN */
1843 sin6
= (struct sockaddr_in6
*)sock
;
1844 sin6
->sin6_family
= AF_INET6
;
1845 sin6
->sin6_addr
= dst_addr
->addr6
;
1846 sin6
->sin6_port
= IPPORT_ECHO
; /* port shouldn't be 0 */
1847 sock_len
= sizeof (struct sockaddr_in6
);
1850 /* open a UDP socket */
1851 if ((tmp_fd
= socket(family
, SOCK_DGRAM
, 0)) < 0) {
1852 Fprintf(stderr
, "%s: udp socket: %s\n", prog
,
1858 if (connect(tmp_fd
, sock
, sock_len
) < 0) {
1860 * If there's no route to the destination, this connect() call
1861 * fails. We just return all-zero (wildcard) as the source
1862 * address, so that user can get to see "no route to dest"
1863 * message, as it'll try to send the probe packet out and will
1864 * receive ICMP unreachable.
1866 if (family
== AF_INET
)
1867 src_addr
->addr
.s_addr
= INADDR_ANY
;
1869 src_addr
->addr6
= in6addr_any
;
1874 /* get the local sock info */
1875 if (getsockname(tmp_fd
, sock
, &sock_len
) < 0) {
1876 Fprintf(stderr
, "%s: getsockname: %s\n", prog
,
1881 if (family
== AF_INET
) {
1882 /* LINTED E_BAD_PTR_CAST_ALIGN */
1883 sin
= (struct sockaddr_in
*)sock
;
1884 src_addr
->addr
= sin
->sin_addr
;
1886 /* LINTED E_BAD_PTR_CAST_ALIGN */
1887 sin6
= (struct sockaddr_in6
*)sock
;
1888 src_addr
->addr6
= sin6
->sin6_addr
;
1892 (void) close(tmp_fd
);
1896 * Checksum routine for Internet Protocol family headers (C Version)
1899 in_cksum(ushort_t
*addr
, int len
)
1907 * Our algorithm is simple, using a 32 bit accumulator (sum),
1908 * we add sequential 16 bit words to it, and at the end, fold
1909 * back all the carry bits from the top 16 bits into the lower
1917 /* mop up an odd byte, if necessary */
1919 sum
+= *(uchar_t
*)w
;
1921 /* add back carry outs from top 16 bits to low 16 bits */
1922 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1923 sum
+= (sum
>> 16); /* add carry */
1924 answer
= ~sum
; /* truncate to 16 bits */
1929 * Wait until a reply arrives or timeout occurs. If packet arrived, read it
1930 * return the size of the packet read.
1933 wait_for_reply(int sock
, struct msghdr
*msg
, struct timeval
*tp
)
1936 struct timeval now
, wait
;
1940 (void) FD_ZERO(&fds
);
1943 wait
.tv_sec
= tp
->tv_sec
+ waittime
;
1944 wait
.tv_usec
= tp
->tv_usec
;
1945 (void) gettimeofday(&now
, NULL
);
1946 tv_sub(&wait
, &now
);
1948 if (wait
.tv_sec
< 0 || wait
.tv_usec
< 0)
1951 result
= select(sock
+ 1, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &wait
);
1954 if (errno
!= EINTR
) {
1955 Fprintf(stderr
, "%s: select: %s\n", prog
,
1958 } else if (result
> 0)
1959 cc
= recvmsg(sock
, msg
, 0);
1965 * Construct an Internet address representation. If the nflag has been supplied,
1966 * give numeric value, otherwise try for symbolic name.
1969 inet_name(union any_in_addr
*in
, int family
)
1972 static boolean_t first
= B_TRUE
;
1973 static char domain
[NI_MAXHOST
+ 1];
1974 static char line
[NI_MAXHOST
+ 1]; /* assuming */
1975 /* (NI_MAXHOST + 1) >= INET6_ADDRSTRLEN */
1976 char hbuf
[NI_MAXHOST
];
1978 struct sockaddr_in sin
;
1979 struct sockaddr_in6 sin6
;
1980 struct sockaddr
*sa
;
1985 slen
= sizeof (struct sockaddr_in
);
1986 sin
.sin_addr
= in
->addr
;
1988 sa
= (struct sockaddr
*)&sin
;
1991 slen
= sizeof (struct sockaddr_in6
);
1992 sin6
.sin6_addr
= in
->addr6
;
1994 sin6
.sin6_scope_id
= 0;
1995 sa
= (struct sockaddr
*)&sin6
;
1998 (void) snprintf(line
, sizeof (line
),
1999 "<invalid address family>");
2002 sa
->sa_family
= family
;
2004 if (first
&& !nflag
) {
2005 /* find out the domain name */
2007 mutex_enter(&tr_nslock
);
2008 tr_nsactive
= B_TRUE
;
2009 tr_nsstarttime
= gethrtime();
2010 mutex_exit(&tr_nslock
);
2011 if (gethostname(domain
, MAXHOSTNAMELEN
) == 0 &&
2012 (cp
= strchr(domain
, '.')) != NULL
) {
2013 (void) strncpy(domain
, cp
+ 1, sizeof (domain
) - 1);
2014 domain
[sizeof (domain
) - 1] = '\0';
2018 mutex_enter(&tr_nslock
);
2019 tr_nsactive
= B_FALSE
;
2020 mutex_exit(&tr_nslock
);
2023 flags
= (nflag
) ? NI_NUMERICHOST
: NI_NAMEREQD
;
2024 mutex_enter(&tr_nslock
);
2025 tr_nsactive
= B_TRUE
;
2026 tr_nsstarttime
= gethrtime();
2027 mutex_exit(&tr_nslock
);
2028 if (getnameinfo(sa
, slen
, hbuf
, sizeof (hbuf
), NULL
, 0, flags
) != 0) {
2029 if (inet_ntop(family
, (const void *)&in
->addr6
,
2030 hbuf
, sizeof (hbuf
)) == NULL
)
2032 } else if (!nflag
&& (cp
= strchr(hbuf
, '.')) != NULL
&&
2033 strcmp(cp
+ 1, domain
) == 0) {
2036 mutex_enter(&tr_nslock
);
2037 tr_nsactive
= B_FALSE
;
2038 mutex_exit(&tr_nslock
);
2039 (void) strlcpy(line
, hbuf
, sizeof (line
));
2045 * return the difference (in msec) between two time values
2048 deltaT(struct timeval
*t1p
, struct timeval
*t2p
)
2052 dt
= (double)(t2p
->tv_sec
- t1p
->tv_sec
) * 1000.0 +
2053 (double)(t2p
->tv_usec
- t1p
->tv_usec
) / 1000.0;
2058 * Subtract 2 timeval structs: out = out - in.
2059 * Out is assumed to be >= in.
2062 tv_sub(struct timeval
*out
, struct timeval
*in
)
2064 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
2066 out
->tv_usec
+= 1000000;
2068 out
->tv_sec
-= in
->tv_sec
;
2075 record_stats(double rtt
, int *nreceived
, double *rttmin
, double *rttmax
,
2076 double *rttsum
, double *rttssq
)
2078 if (*nreceived
== 0) {
2082 *rttssq
= rtt
* rtt
;
2091 *rttssq
+= rtt
* rtt
;
2098 * display statistics
2101 print_stats(int ntransmitted
, int nreceived
, double rttmin
, double rttmax
,
2102 double rttsum
, double rttssq
)
2104 double rttavg
; /* average round-trip time */
2105 double rttstd
; /* rtt standard deviation */
2107 if (ntransmitted
> 0 && ntransmitted
>= nreceived
) {
2108 int missed
= ntransmitted
- nreceived
;
2109 double loss
= 100 * (double)missed
/ (double)ntransmitted
;
2111 if (nreceived
> 0) {
2112 rttavg
= rttsum
/ nreceived
;
2113 rttstd
= rttssq
- (rttavg
* rttsum
);
2114 rttstd
= xsqrt(rttstd
/ nreceived
);
2116 Printf(" %.3f", rttmin
);
2117 Printf("/%.3f", rttavg
);
2118 Printf("/%.3f", rttmax
);
2120 Printf(" (%.3f) ms ", rttstd
);
2123 Printf(" %d/%d pkts", nreceived
, ntransmitted
);
2126 Printf(" (100%% loss)");
2128 Printf(" (%.2g%% loss)", loss
);
2133 * square root function
2144 x
= (y
< 1.0) ? 1.0 : y
;
2147 x
= (t
+ (y
/t
))/2.0;
2148 } while (0 < x
&& x
< t
);
2154 * String to double with optional min and max.
2157 str2dbl(const char *str
, const char *what
, double mi
, double ma
)
2164 val
= strtod(str
, &ep
);
2165 if (errno
!= 0 || *ep
!= '\0') {
2166 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
2170 if (val
< mi
&& mi
>= 0) {
2171 Fprintf(stderr
, "%s: %s must be >= %f\n", prog
, what
, mi
);
2174 if (val
> ma
&& ma
>= 0) {
2175 Fprintf(stderr
, "%s: %s must be <= %f\n", prog
, what
, ma
);
2182 * String to int with optional min and max. Handles decimal and hex.
2185 str2int(const char *str
, const char *what
, int mi
, int ma
)
2193 if (str
[0] == '0' && (str
[1] == 'x' || str
[1] == 'X')) {
2195 val
= (int)strtol(cp
, &ep
, 16);
2197 val
= (int)strtol(str
, &ep
, 10);
2199 if (errno
!= 0 || *ep
!= '\0') {
2200 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
2204 if (val
< mi
&& mi
>= 0) {
2206 Fprintf(stderr
, "%s: %s must be >= %d\n",
2209 Fprintf(stderr
, "%s: %s must be > %d\n",
2210 prog
, what
, mi
- 1);
2214 if (val
> ma
&& ma
>= 0) {
2215 Fprintf(stderr
, "%s: %s must be <= %d\n", prog
, what
, ma
);
2222 * This is the interrupt handler for SIGINT and SIGQUIT. It's completely handled
2223 * where it jumps to.
2226 sig_handler(int sig
)
2232 * display the usage of traceroute
2237 Fprintf(stderr
, "Usage: %s [-adFIlnSvx] [-A address_family] "
2238 "[-c traffic_class]\n"
2239 "\t[-f first_hop] [-g gateway [-g gateway ...]| -r] [-i iface]\n"
2240 "\t[-L flow_label] [-m max_hop] [-P pause_sec] [-p port] "
2241 "[-Q max_timeout]\n"
2242 "\t[-q nqueries] [-s src_addr] [-t tos] [-w wait_time] host "
2243 "[packetlen]\n", prog
);
2249 ns_warning_thr(void *unused
)
2254 (void) sleep(tr_nssleeptime
);
2257 mutex_enter(&tr_nslock
);
2258 if (tr_nsactive
&& now
- tr_nsstarttime
>=
2259 tr_nswarntime
* NANOSEC
) {
2260 Fprintf(stderr
, "%s: warning: responses "
2261 "received, but name service lookups are "
2262 "taking a while. Use %s -n to disable "
2263 "name service lookups.\n",
2265 mutex_exit(&tr_nslock
);
2268 mutex_exit(&tr_nslock
);
2271 /* LINTED: E_STMT_NOT_REACHED */