2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
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
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>
32 #include <sys/ioctl.h>
33 #include <sys/socket.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>
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 */
76 /* store the information about a host */
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 */
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" */
93 int sock_size
; /* size of sockaddr_in or sockaddr_in6 */
95 struct sockaddr
*from
;
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 */
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 */
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
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 */
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
*,
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,
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);
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
254 boolean_t probing_successful
= _B_FALSE
;
255 int longjmp_return
; /* return value from longjump */
260 char temp_buf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
264 * A raw socket will be used for IPv4 if there is sufficient
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
)
284 while ((op
= getopt(argc
, argv
, "adFIlnrSvxA:c:f:g:i:L:m:P:p:Q:q:s:"
288 if (strcmp(optarg
, "inet") == 0) {
289 family_input
= AF_INET
;
290 } else if (strcmp(optarg
, "inet6") == 0) {
291 family_input
= AF_INET6
;
294 "%s: unknown address family %s\n",
305 class = str2int(optarg
, "traffic class", 0,
314 first_ttl
= str2int(optarg
, "first ttl", 1, MAXTTL
);
325 "%s: privilege to specify a loose source "
326 "route gateway is unavailable\n",
330 if (gw_count
>= MAXMAX_GWS
) {
332 "%s: Too many gateways\n", prog
);
335 gwlist
[gw_count
] = strdup(optarg
);
336 if (gwlist
[gw_count
] == NULL
) {
337 Fprintf(stderr
, "%s: strdup %s\n", prog
,
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') {
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
));
368 device
= (char *)malloc(LIFNAMSIZ
+ 1);
369 if (device
== NULL
) {
370 Fprintf(stderr
, "%s: malloc: %s\n",
371 prog
, strerror(errno
));
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
383 Fprintf(stderr
, "%s: if_indextoname:"
384 "%s\n", prog
, strerror(errno
));
389 if (device
== NULL
|| if_index
== 0) {
390 Fprintf(stderr
, "%s: interface %s "
391 "doesn't match any actual interfaces\n",
402 flow
= str2int(optarg
, "flow label", 0, MAX_FLOW_LABEL
);
406 max_ttl
= str2int(optarg
, "max ttl(hop limit)", 1,
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
) *
422 port
= str2int(optarg
, "port", 1, MAX_PORT
);
426 max_timeout
= str2int(optarg
, "max timeout", 1, -1);
430 nprobes
= str2int(optarg
, "nprobes", 1, -1);
434 options
|= SO_DONTROUTE
;
438 collect_stat
= _B_TRUE
;
443 * set the ip source address of the outbound
444 * probe (e.g., on a multi-homed host).
446 source_input
= optarg
;
450 tos
= (uchar_t
)str2int(optarg
, "tos", 0, MAX_TOS
);
463 waittime
= str2int(optarg
, "wait time", 2, -1);
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.
478 if ((longjmp_return
= setjmp(env
)) != 0) {
479 if (longjmp_return
== SIGQUIT
) {
480 Printf("(exiting)\n");
482 } else { /* should never happen */
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",
498 if (i
== 1 || i
== 2) {
499 hostname
= argv
[optind
];
502 /* accept any length now, we'll check it later */
503 packlen_input
= str2int(argv
[optind
+ 1],
504 "packet length", 0, -1);
510 if (first_ttl
> max_ttl
) {
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
);
518 /* resolve hostnames */
519 resolve_nodes(&family_input
, &ai_dst
);
520 if (ai_dst
== NULL
) {
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.
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
) {
541 pr4
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
544 "%s: malloc %s\n", prog
, strerror(errno
));
547 pr6
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
550 "%s: malloc %s\n", prog
, strerror(errno
));
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
);
564 pr6
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
567 "%s: malloc %s\n", prog
, strerror(errno
));
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
);
576 pr4
= (struct pr_set
*)malloc(sizeof (struct pr_set
));
579 "%s: malloc %s\n", prog
, strerror(errno
));
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
);
588 Fprintf(stderr
, "%s: unknow address family.\n", prog
);
592 if (num_v4
+ num_v6
> 1 && !probe_all
) {
593 if (ai_dst
->ai_family
== AF_INET
) {
595 "%s: Warning: %s has multiple addresses;"
596 " using %s\n", prog
, hostname
,
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
)));
604 "%s: Warning: %s has multiple addresses;"
605 " using %s\n", prog
, hostname
,
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) {
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
);
631 return (EXIT_FAILURE
);
635 * print "unknown host" message
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
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
);
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
) {
671 if (*family
== AF_UNSPEC
&& !probe_all
) {
672 *family
= ai_dst
->ai_family
;
675 /* resolve gateways */
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
]);
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
]);
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.
705 get_hostinfo(char *host
, int family
, struct addrinfo
**aipp
)
707 struct addrinfo hints
, *ai
;
708 struct in6_addr addr6
;
710 char abuf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
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
735 if (family
== AF_INET6
) {
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
);
745 if (rc
!= EAI_NONAME
)
746 Fprintf(stderr
, "%s: getaddrinfo: %s\n", prog
,
755 * Calculate the packet length to be used, and check against the valid range.
756 * Returns -1 if range check fails.
759 calc_packetlen(int plen_input
, struct pr_set
*pr
)
761 int minpacket
; /* min ip packet size */
762 int optlen
; /* length of ip options */
766 * LBNL bug fixed: miscalculation of optlen
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
781 * Well, formula is different, but the result is same.
782 * 8 byte fixed part for Type 0 Routing header, followed by
785 optlen
= 8 + gw_count
* pr
->addr_len
;
790 /* take care of the packet length calculations and checks */
791 minpacket
= pr
->ip_hdr_len
+ sizeof (struct outdata
) + optlen
;
793 minpacket
+= pr
->icmp_minlen
; /* minimum ICMP header size */
795 minpacket
+= sizeof (struct udphdr
);
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
);
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.
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 */
832 uint_t ifaddrflags
= 0;
834 source
= source_input
;
837 ifaddrflags
|= LIFC_UNDER_IPMP
;
839 /* get the interface address list */
840 num_ifs
= ifaddrlist(&al
, pr
->family
, ifaddrflags
, errbuf
);
842 Fprintf(stderr
, "%s: ifaddrlist: %s\n", prog
, errbuf
);
847 for (i
= 0; i
< num_ifs
; i
++) {
848 if (!(al
[i
].flags
& IFF_LOOPBACK
) && (al
[i
].flags
& IFF_UP
))
852 if (num_src_ifs
== 0) {
853 Fprintf(stderr
, "%s: can't find any %s network interfaces\n",
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
);
870 /* verify the source address */
871 if (source
!= NULL
) {
872 get_hostinfo(source
, pr
->family
, &aip
);
875 "%s: %s is an invalid %s source address\n",
876 prog
, source
, pr
->name
);
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
;
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
);
909 if (source
== NULL
) { /* no -s used */
910 if (device
== NULL
) { /* no -i used, no -s used */
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
918 if (pr
->family
== AF_INET
)
919 set_sin(pr
->from
, &(tmp1_al
->addr
), pr
->family
);
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
,
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
)) {
943 "%s: %s is not on interface %s\n",
944 prog
, source
, device
);
948 * make sure we use the one matching the
949 * interface's address
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
965 * For raw IPv4 datagrams, the source address is initialized
966 * within traceroute() along with the outbound destination
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
,
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
,
988 whereto6
.sin6_flowinfo
= htonl((class << 20) | flow
);
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
,
1002 struct ifaddrlist
*tmp_al
= al
;
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))
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
;
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))
1046 * returns _B_TRUE if given hostinfo contains the given address
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
)
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)
1064 if (ai_tmp
!= NULL
) {
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.
1080 get_gwaddrs(char **gwlist
, int family
, union any_in_addr
*gwIPlist
,
1081 union any_in_addr
*gwIPlist6
, int *resolved
, int *resolved6
)
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;
1093 check_v6
= _B_FALSE
;
1096 check_v4
= _B_FALSE
;
1102 if (check_v4
&& gw_count
>= MAX_GWS
) {
1103 check_v4
= _B_FALSE
;
1104 Fprintf(stderr
, "%s: too many IPv4 gateways\n", prog
);
1107 if (check_v6
&& gw_count
>= MAX_GWS6
) {
1108 check_v6
= _B_FALSE
;
1109 Fprintf(stderr
, "%s: too many IPv6 gateways\n", prog
);
1113 for (i
= 0; i
< gw_count
; i
++) {
1114 if (!check_v4
&& !check_v6
)
1116 get_hostinfo(gwlist
[i
], family
, &ai
);
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
,
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
,
1150 } else if (check_v6
) {
1151 check_v6
= _B_FALSE
;
1158 * set protocol specific values here
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
) {
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
);
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)
1211 * setup the sockets for the given protocol's address family
1214 setup_socket(struct pr_set
*pr
, int packet_len
)
1217 struct protoent
*pe
;
1224 if ((pe
= getprotobyname(pr
->icmp
)) == NULL
) {
1225 Fprintf(stderr
, "%s: unknown protocol %s\n", prog
, pr
->icmp
);
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
));
1237 if (options
& SO_DEBUG
) {
1238 if (setsockopt(rsock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1240 Fprintf(stderr
, "%s: SO_DEBUG: %s\n", prog
,
1245 if (options
& SO_DONTROUTE
) {
1246 if (setsockopt(rsock
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
1248 Fprintf(stderr
, "%s: SO_DONTROUTE: %s\n", prog
,
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
,
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
,
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
) {
1292 proto
= IPPROTO_RAW
;
1293 } else if (useicmp
) {
1295 if (pr
->family
== AF_INET
)
1296 proto
= IPPROTO_ICMP
;
1298 proto
= IPPROTO_ICMPV6
;
1301 proto
= IPPROTO_UDP
;
1303 ssock
= socket(pr
->family
, type
, proto
);
1306 if (proto
== IPPROTO_RAW
) {
1307 Fprintf(stderr
, "%s: raw socket: %s\n", prog
,
1309 } else if (proto
== IPPROTO_UDP
) {
1310 Fprintf(stderr
, "%s: udp socket: %s\n", prog
,
1313 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
,
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
));
1325 if (pr
->family
== AF_INET
&& raw_req
) {
1326 if (setsockopt(ssock
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
1328 Fprintf(stderr
, "%s: IP_HDRINCL: %s\n", prog
,
1334 if (options
& SO_DEBUG
) {
1335 if (setsockopt(ssock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1337 Fprintf(stderr
, "%s: SO_DEBUG: %s\n", prog
,
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
,
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
1357 if (settos
&& !raw_req
) {
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
,
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
,
1376 if (setsockopt(ssock
, IPPROTO_IPV6
, IPV6_DONTFRAG
,
1377 (char *)&dontfrag
, sizeof (dontfrag
)) == -1) {
1378 Fprintf(stderr
, "%s: IPV6_DONTFRAG %s\n", prog
,
1384 if (pr
->family
== AF_INET
) {
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()
1401 trace_it(struct addrinfo
*ai_dst
)
1404 int num_dst_IPaddrs
;
1405 struct addrinfo
*aip
;
1409 num_dst_IPaddrs
= 1;
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
,
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
,
1434 traceroute(addrp
, &msg6
, pr4
, num_ifs4
, al4
);
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
,
1442 traceroute(addrp
, &msg6
, pr6
, num_ifs6
, al6
);
1445 if (i
< (num_dst_IPaddrs
- 1))
1446 (void) putchar('\n');
1451 * set the IP address in a sockaddr struct
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
;
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
1470 device_name(struct ifaddrlist
*al
, int len
, union any_in_addr
*ip_addr
,
1474 struct ifaddrlist
*tmp_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
);
1488 * Trace the route to the host with given IP address.
1491 traceroute(union any_in_addr
*ip_addr
, struct msghdr
*msg6
, struct pr_set
*pr
,
1492 int num_ifs
, struct ifaddrlist
*al
)
1496 uchar_t type
; /* icmp type */
1497 uchar_t code
; /* icmp code */
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
;
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 */
1521 union any_in_addr src_addr
;
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.
1531 (void) select_src_addr(pr
->gwIPlist
, &src_addr
,
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 */
1540 for (i
= 0; i
< num_ifs
; i
++) {
1541 if (!(al
[i
].flags
& IFF_LOOPBACK
) &&
1542 (al
[i
].flags
& IFF_UP
))
1546 if (num_src_ifs
> 1) {
1547 dev_name
= device_name(al
, num_ifs
, &src_addr
, pr
);
1548 if (dev_name
== NULL
)
1551 (void) inet_ntop(pr
->family
, pr
->from_sin_addr
, abuf
,
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
);
1571 Fprintf(stderr
, "%s to %s (%s)", prog
, hostname
,
1572 inet_ntop(pr
->family
, ip_addr
, abuf
, sizeof (abuf
)));
1576 Fprintf(stderr
, " from %s", source
);
1577 Fprintf(stderr
, ", %d hops max, %d byte packets\n", max_ttl
,
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
);
1590 /* interrupt handler sig_handler() jumps back to here */
1591 if ((longjmp_return
= setjmp(env
)) != 0) {
1592 switch (longjmp_return
) {
1594 Printf("(skipping)\n");
1597 Printf("(exiting)\n");
1599 default: /* should never happen */
1603 (void) signal(SIGINT
, sig_handler
);
1606 for (ttl
= first_ttl
; ttl
<= max_ttl
; ++ttl
) {
1607 union any_in_addr lastaddr
;
1609 double rtt
; /* for statistics */
1611 double rttmin
, rttmax
;
1612 double rttsum
, rttssq
;
1615 got_there
= _B_FALSE
;
1619 * The following line clears both IPv4 and IPv6 address stored
1622 lastaddr
.addr6
= in6addr_any
;
1624 if ((ttl
== (first_ttl
+ 1)) && (options
& SO_DONTROUTE
)) {
1626 "%s: host %s is not on a directly-attached"
1627 " network\n", prog
, hostname
);
1631 Printf("%2d ", ttl
);
1632 (void) fflush(stdout
);
1634 for (probe
= 0; (probe
< nprobes
) && (timeouts
< max_timeout
);
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.
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
);
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
,
1658 send_probe6(sndsock
, msg6
, outip6
, seq
, ttl
,
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
,
1677 (void) gettimeofday(&t2
, NULL
);
1679 reply
= (*pr
->check_reply_fn
) (&in_msg
, cc
, seq
,
1682 in_msg
.msg_controllen
=
1683 sizeof (ancillary_data
);
1684 /* Skip short packet */
1685 if (reply
== REPLY_SHORT_PKT
) {
1692 * if reply comes from a different host, print
1695 if (memcmp(pr
->from_sin_addr
, &lastaddr
,
1696 pr
->addr_len
) != 0) {
1697 (*pr
->print_addr_fn
) ((uchar_t
*)packet
,
1699 /* store the address response */
1700 (void) memcpy(&lastaddr
,
1701 pr
->from_sin_addr
, pr
->addr_len
);
1704 rtt
= deltaT(&t1
, &t2
);
1706 record_stats(rtt
, &nreceived
, &rttmin
,
1707 &rttmax
, &rttsum
, &rttssq
);
1709 Printf(" %.3f ms", rtt
);
1712 if (pr
->family
== AF_INET6
) {
1713 intp
= find_ancillary_data(&in_msg
,
1714 IPPROTO_IPV6
, IPV6_HOPLIMIT
);
1718 "IPV6_HOPLIMIT ancillary "
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
) &&
1735 if (!collect_stat
&& showttl
) {
1736 if (pr
->family
== AF_INET
) {
1739 } else if (hoplimit
!= -1) {
1740 Printf(" (hop limit=%d)",
1745 if (reply
== REPLY_GOT_OTHER
) {
1746 if ((*pr
->print_icmp_other_fn
)
1753 if (pr
->family
== AF_INET
&&
1754 type
== ICMP_UNREACH
&&
1755 code
== ICMP_UNREACH_PROTOCOL
)
1756 got_there
= _B_TRUE
;
1761 seq
= (seq
+ 1) % (MAX_SEQ
+ 1);
1768 (void) fflush(stdout
);
1772 print_stats(probe
, nreceived
, rttmin
, rttmax
, rttsum
,
1776 (void) putchar('\n');
1778 /* either we hit the target or received too many unreachables */
1780 (unreachable
> 0 && unreachable
>= nprobes
- 1))
1784 /* Ignore the SIGINT between traceroute() runs */
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
1794 select_src_addr(union any_in_addr
*dst_addr
, union any_in_addr
*src_addr
,
1798 struct sockaddr
*sock
;
1799 struct sockaddr_in
*sin
;
1800 struct sockaddr_in6
*sin6
;
1803 sock
= (struct sockaddr
*)malloc(sizeof (struct sockaddr_in6
));
1805 Fprintf(stderr
, "%s: malloc %s\n", prog
, strerror(errno
));
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
);
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
,
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
;
1845 src_addr
->addr6
= in6addr_any
;
1850 /* get the local sock info */
1851 if (getsockname(tmp_fd
, sock
, &sock_len
) < 0) {
1852 Fprintf(stderr
, "%s: getsockname: %s\n", prog
,
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
;
1862 /* LINTED E_BAD_PTR_CAST_ALIGN */
1863 sin6
= (struct sockaddr_in6
*)sock
;
1864 src_addr
->addr6
= sin6
->sin6_addr
;
1868 (void) close(tmp_fd
);
1872 * Checksum routine for Internet Protocol family headers (C Version)
1875 in_cksum(ushort_t
*addr
, int len
)
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
1893 /* mop up an odd byte, if necessary */
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 */
1905 * Wait until a reply arrives or timeout occurs. If packet arrived, read it
1906 * return the size of the packet read.
1909 wait_for_reply(int sock
, struct msghdr
*msg
, struct timeval
*tp
)
1912 struct timeval now
, wait
;
1916 (void) FD_ZERO(&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)
1927 result
= select(sock
+ 1, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &wait
);
1930 if (errno
!= EINTR
) {
1931 Fprintf(stderr
, "%s: select: %s\n", prog
,
1934 } else if (result
> 0)
1935 cc
= recvmsg(sock
, msg
, 0);
1941 * Construct an Internet address representation. If the nflag has been supplied,
1942 * give numeric value, otherwise try for symbolic name.
1945 inet_name(union any_in_addr
*in
, int family
)
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
];
1954 struct sockaddr_in sin
;
1955 struct sockaddr_in6 sin6
;
1956 struct sockaddr
*sa
;
1961 slen
= sizeof (struct sockaddr_in
);
1962 sin
.sin_addr
= in
->addr
;
1964 sa
= (struct sockaddr
*)&sin
;
1967 slen
= sizeof (struct sockaddr_in6
);
1968 sin6
.sin6_addr
= in
->addr6
;
1970 sin6
.sin6_scope_id
= 0;
1971 sa
= (struct sockaddr
*)&sin6
;
1974 (void) snprintf(line
, sizeof (line
),
1975 "<invalid address family>");
1978 sa
->sa_family
= family
;
1980 if (first
&& !nflag
) {
1981 /* find out the domain name */
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';
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
)
1997 } else if (!nflag
&& (cp
= strchr(hbuf
, '.')) != NULL
&&
1998 strcmp(cp
+ 1, domain
) == 0) {
2001 (void) strlcpy(line
, hbuf
, sizeof (line
));
2007 * return the difference (in msec) between two time values
2010 deltaT(struct timeval
*t1p
, struct timeval
*t2p
)
2014 dt
= (double)(t2p
->tv_sec
- t1p
->tv_sec
) * 1000.0 +
2015 (double)(t2p
->tv_usec
- t1p
->tv_usec
) / 1000.0;
2020 * Subtract 2 timeval structs: out = out - in.
2021 * Out is assumed to be >= in.
2024 tv_sub(struct timeval
*out
, struct timeval
*in
)
2026 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
2028 out
->tv_usec
+= 1000000;
2030 out
->tv_sec
-= in
->tv_sec
;
2037 record_stats(double rtt
, int *nreceived
, double *rttmin
, double *rttmax
,
2038 double *rttsum
, double *rttssq
)
2040 if (*nreceived
== 0) {
2044 *rttssq
= rtt
* rtt
;
2053 *rttssq
+= rtt
* rtt
;
2060 * display statistics
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
);
2088 Printf(" (100%% loss)");
2090 Printf(" (%.2g%% loss)", loss
);
2095 * square root function
2106 x
= (y
< 1.0) ? 1.0 : y
;
2109 x
= (t
+ (y
/t
))/2.0;
2110 } while (0 < x
&& x
< t
);
2116 * String to double with optional min and max.
2119 str2dbl(const char *str
, const char *what
, double mi
, double ma
)
2126 val
= strtod(str
, &ep
);
2127 if (errno
!= 0 || *ep
!= '\0') {
2128 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
2132 if (val
< mi
&& mi
>= 0) {
2133 Fprintf(stderr
, "%s: %s must be >= %f\n", prog
, what
, mi
);
2136 if (val
> ma
&& ma
>= 0) {
2137 Fprintf(stderr
, "%s: %s must be <= %f\n", prog
, what
, ma
);
2144 * String to int with optional min and max. Handles decimal and hex.
2147 str2int(const char *str
, const char *what
, int mi
, int ma
)
2155 if (str
[0] == '0' && (str
[1] == 'x' || str
[1] == 'X')) {
2157 val
= (int)strtol(cp
, &ep
, 16);
2159 val
= (int)strtol(str
, &ep
, 10);
2161 if (errno
!= 0 || *ep
!= '\0') {
2162 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
2166 if (val
< mi
&& mi
>= 0) {
2168 Fprintf(stderr
, "%s: %s must be >= %d\n",
2171 Fprintf(stderr
, "%s: %s must be > %d\n",
2172 prog
, what
, mi
- 1);
2176 if (val
> ma
&& ma
>= 0) {
2177 Fprintf(stderr
, "%s: %s must be <= %d\n", prog
, what
, ma
);
2184 * This is the interrupt handler for SIGINT and SIGQUIT. It's completely handled
2185 * where it jumps to.
2188 sig_handler(int sig
)
2194 * display the usage of traceroute
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
);