2 * Copyright 2007 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 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
37 #include <sys/sysmacros.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip_var.h>
43 #include <netinet/ip_icmp.h>
44 #include <netinet/udp.h>
45 #include <netinet/udp_var.h>
46 #include <netinet/ip6.h>
47 #include <netinet/icmp6.h>
49 #include <arpa/inet.h>
67 #include <priv_utils.h>
69 #include <libinetutil.h>
70 #include "traceroute.h"
72 #define MAX_SEQ 65535 /* max sequence value for ICMP */
73 #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
74 #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
75 #define MAX_TOS 255 /* max type-of-service for IPv4 */
78 /* store the information about a host */
80 char *name
; /* hostname */
81 int family
; /* address family of the IP addresses */
82 int num_addr
; /* number of IP addresses */
83 union any_in_addr
*addrs
; /* list of IP addresses */
86 /* used to store a bunch of protocol specific values */
88 int family
; /* AF_INET or AF_INET6 */
89 char name
[STR_LEN
]; /* "IPv4" or "IPv6" */
90 char icmp
[STR_LEN
]; /* "icmp" or "ipv6-icmp" */
95 int sock_size
; /* size of sockaddr_in or sockaddr_in6 */
97 struct sockaddr
*from
;
99 union any_in_addr
*gwIPlist
;
100 /* pointers to v4/v6 functions */
101 struct ip
*(*set_buffers_fn
) (int);
102 int (*check_reply_fn
)(struct msghdr
*, int, int, uchar_t
*, uchar_t
*);
103 boolean_t (*print_icmp_other_fn
)(uchar_t
, uchar_t
);
104 void (*print_addr_fn
)(uchar_t
*, int, struct sockaddr
*);
109 * LBNL bug fixed: in LBNL traceroute 'uchar_t packet[512];'
110 * Not sufficient to hold the complete packet for ECHO REPLY of a big probe.
111 * Packet size is reported incorrectly in such a case.
112 * Also this buffer needs to be 32 bit aligned. In the future the alignment
113 * requirement will be increased to 64 bit. So, let's use 64 bit alignment now.
115 static uint64_t packet
[(IP_MAXPACKET
+ 1)/8]; /* received packet */
117 static struct ip
*outip4
; /* output buffer to send as an IPv4 datagram */
118 static struct ip
*outip6
; /* output buffer to send as an IPv6 datagram */
120 /* Used to store the ancillary data that comes with the received packets */
121 static uint64_t ancillary_data
[(IP_MAXPACKET
+ 1)/8];
123 /* first get the gw names, later you'll resolve them based on the family */
124 static char *gwlist
[MAXMAX_GWS
]; /* gateway names list */
125 static union any_in_addr gwIPlist
[MAX_GWS
]; /* gateway IPv4 address list */
126 static union any_in_addr gwIP6list
[MAX_GWS6
]; /* gateway IPv6 address list */
128 static int family_input
= AF_UNSPEC
; /* User supplied protocol family */
129 static int rcvsock4
; /* receive (icmp) socket file descriptor */
130 static int sndsock4
; /* send (udp/icmp) socket file descriptor */
131 static int rcvsock6
; /* receive (icmp6) socket file descriptor */
132 static int sndsock6
; /* send (udp6/icmp6) socket file descriptor */
133 int gw_count
= 0; /* number of gateways */
134 static struct sockaddr_in whereto
; /* Who to try to reach */
135 static struct sockaddr_in6 whereto6
;
136 static struct sockaddr_in wherefrom
; /* Who we are */
137 static struct sockaddr_in6 wherefrom6
;
138 static int packlen_input
= 0; /* user input for packlen */
141 static char *source_input
= NULL
; /* this is user arg. source, doesn't change */
142 static char *source
= NULL
; /* this gets modified after name lookup */
144 static char *device
= NULL
; /* interface name */
145 static struct pr_set
*pr4
; /* protocol info for IPv4 */
146 static struct pr_set
*pr6
; /* protocol info for IPv6 */
147 static struct ifaddrlist
*al4
; /* list of interfaces */
148 static struct ifaddrlist
*al6
; /* list of interfaces */
149 static uint_t if_index
= 0; /* interface index */
150 static int num_v4
= 0; /* count of IPv4 addresses */
151 static int num_v6
= 0; /* count of IPv6 addresses */
152 static int num_ifs4
= 0; /* count of local IPv4 interfaces */
153 static int num_ifs6
= 0; /* count of local IPv6 interfaces */
155 static int nprobes
= 3; /* number of probes */
156 static int max_ttl
= 30; /* max number of hops */
157 static int first_ttl
= 1; /* initial number of hops */
158 ushort_t ident
; /* used to authenticate replies */
159 ushort_t port
= 32768 + 666; /* start udp dest port # for probe packets */
161 static int options
= 0; /* socket options */
162 boolean_t verbose
= _B_FALSE
; /* verbose output */
163 static int waittime
= 5; /* time to wait for response (in seconds) */
164 static struct timeval delay
= {0, 0}; /* delay between consecutive probe */
165 boolean_t nflag
= _B_FALSE
; /* print addresses numerically */
166 static boolean_t showttl
= _B_FALSE
; /* print the ttl(hop limit) of recvd pkt */
167 boolean_t useicmp
= _B_FALSE
; /* use icmp echo instead of udp packets */
168 boolean_t docksum
= _B_TRUE
; /* calculate checksums */
169 static boolean_t collect_stat
= _B_FALSE
; /* print statistics */
170 boolean_t settos
= _B_FALSE
; /* set type-of-service field */
171 static int max_timeout
= 5; /* quit after this consecutive timeouts */
172 static boolean_t probe_all
= _B_FALSE
; /* probe all the IFs of the target */
173 static boolean_t pick_src
= _B_FALSE
; /* traceroute picks the src address */
176 * flow and class are specific to IPv6, tos and off are specific to IPv4.
177 * Each protocol uses the ones that are specific to itself, and ignores
180 static uint_t flow
= 0; /* IPv6 flow info */
181 static uint_t
class = 0; /* IPv6 class */
182 uchar_t tos
= 0; /* IPv4 type-of-service */
183 ushort_t off
= 0; /* set DF bit */
185 static jmp_buf env
; /* stack environment for longjmp() */
186 boolean_t raw_req
; /* if sndsock for IPv4 must be raw */
189 static uint_t
calc_packetlen(int, struct pr_set
*);
190 extern int check_reply(struct msghdr
*, int, int, uchar_t
*, uchar_t
*);
191 extern int check_reply6(struct msghdr
*, int, int, uchar_t
*, uchar_t
*);
192 static double deltaT(struct timeval
*, struct timeval
*);
193 static char *device_name(struct ifaddrlist
*, int, union any_in_addr
*,
195 extern void *find_ancillary_data(struct msghdr
*, int, int);
196 static boolean_t
has_addr(struct addrinfo
*, union any_in_addr
*);
197 static struct ifaddrlist
*find_device(struct ifaddrlist
*, int, char *);
198 static struct ifaddrlist
*find_ifaddr(struct ifaddrlist
*, int,
199 union any_in_addr
*, int);
200 static void get_gwaddrs(char **, int, union any_in_addr
*,
201 union any_in_addr
*, int *, int *);
202 static void get_hostinfo(char *, int, struct addrinfo
**);
203 char *inet_name(union any_in_addr
*, int);
204 ushort_t
in_cksum(ushort_t
*, int);
205 extern int ip_hdr_length_v6(ip6_t
*, int, uint8_t *);
206 extern char *pr_type(uchar_t
);
207 extern char *pr_type6(uchar_t
);
208 extern void print_addr(uchar_t
*, int, struct sockaddr
*);
209 extern void print_addr6(uchar_t
*, int, struct sockaddr
*);
210 extern boolean_t
print_icmp_other(uchar_t
, uchar_t
);
211 extern boolean_t
print_icmp_other6(uchar_t
, uchar_t
);
212 static void print_stats(int, int, double, double, double, double);
213 static void print_unknown_host_msg(const char *, const char *);
214 static void record_stats(double, int *, double *, double *, double *, double *);
215 static void resolve_nodes(int *, struct addrinfo
**);
216 static void select_src_addr(union any_in_addr
*, union any_in_addr
*, int);
217 extern void send_probe(int, struct sockaddr
*, struct ip
*, int, int,
218 struct timeval
*, int);
219 extern void send_probe6(int, struct msghdr
*, struct ip
*, int, int,
220 struct timeval
*, int);
221 extern void set_ancillary_data(struct msghdr
*, int, union any_in_addr
*, int,
223 extern struct ip
*set_buffers(int);
224 extern struct ip
*set_buffers6(int);
225 extern void set_IPv4opt_sourcerouting(int, union any_in_addr
*,
226 union any_in_addr
*);
227 static void set_sin(struct sockaddr
*, union any_in_addr
*, int);
228 static int set_src_addr(struct pr_set
*, struct ifaddrlist
**);
229 static void setup_protocol(struct pr_set
*, int);
230 static void setup_socket(struct pr_set
*, int);
231 static void sig_handler(int);
232 static int str2int(const char *, const char *, int, int);
233 static double str2dbl(const char *, const char *, double, double);
234 static void trace_it(struct addrinfo
*);
235 static void traceroute(union any_in_addr
*, struct msghdr
*, struct pr_set
*,
236 int, struct ifaddrlist
*);
237 static void tv_sub(struct timeval
*, struct timeval
*);
238 static void usage(void);
239 static int wait_for_reply(int, struct msghdr
*, struct timeval
*);
240 static double xsqrt(double);
246 main(int argc
, char **argv
)
248 struct addrinfo
*ai_dst
= NULL
; /* destination host */
250 * "probing_successful" indicates if we could successfully send probes,
251 * not necessarily received reply from the target (this behavior is from
252 * the original traceroute). It's _B_FALSE if packlen is invalid, or no
255 boolean_t probing_successful
= _B_FALSE
;
256 int longjmp_return
; /* return value from longjump */
261 char temp_buf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
265 * A raw socket will be used for IPv4 if there is sufficient
268 raw_req
= priv_ineffect(PRIV_NET_RAWACCESS
);
271 * We'll need the privilege only when we open the sockets; that's
272 * when we'll fail if the program has insufficient privileges.
274 (void) __init_suid_priv(PU_CLEARLIMITSET
, PRIV_NET_ICMPACCESS
,
275 raw_req
? PRIV_NET_RAWACCESS
: NULL
, NULL
);
277 (void) setlinebuf(stdout
);
279 if ((cp
= strrchr(argv
[0], '/')) != NULL
)
285 while ((op
= getopt(argc
, argv
, "adFIlnrSvxA:c:f:g:i:L:m:P:p:Q:q:s:"
289 if (strcmp(optarg
, "inet") == 0) {
290 family_input
= AF_INET
;
291 } else if (strcmp(optarg
, "inet6") == 0) {
292 family_input
= AF_INET6
;
295 "%s: unknown address family %s\n",
306 class = str2int(optarg
, "traffic class", 0,
315 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 temp_buf
[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
, (void *)&addr
, temp_buf
,
726 /* now the host is an IPv4 address */
727 (void) strcpy(host
, temp_buf
);
730 * If it's a mapped address, we convert it into IPv4
731 * address because traceroute will send and receive IPv4
732 * packets for that address. Therefore, it's a failure case to
733 * ask get_hostinfo() to treat a mapped address as an IPv6
736 if (family
== AF_INET6
) {
741 (void) memset(&hints
, 0, sizeof (hints
));
742 hints
.ai_family
= family
;
743 hints
.ai_flags
= AI_ADDRCONFIG
| AI_CANONNAME
;
744 rc
= getaddrinfo(host
, NULL
, &hints
, &ai
);
746 if (rc
!= EAI_NONAME
)
747 Fprintf(stderr
, "%s: getaddrinfo: %s\n", prog
,
756 * Calculate the packet length to be used, and check against the valid range.
757 * Returns -1 if range check fails.
760 calc_packetlen(int plen_input
, struct pr_set
*pr
)
762 int minpacket
; /* min ip packet size */
763 int optlen
; /* length of ip options */
767 * LBNL bug fixed: miscalculation of optlen
773 * 5 (NO OPs) + 3 (code, len, ptr) + gateways
774 * IP options field can hold up to 9 gateways. But the API
775 * allows you to specify only 8, because the last one is the
776 * destination host. When this packet is sent, on the wire
777 * you see one gateway replaced by 4 NO OPs. The other 1 NO
778 * OP is for alignment
782 * Well, formula is different, but the result is same.
783 * 8 byte fixed part for Type 0 Routing header, followed by
786 optlen
= 8 + gw_count
* pr
->addr_len
;
791 /* take care of the packet length calculations and checks */
792 minpacket
= pr
->ip_hdr_len
+ sizeof (struct outdata
) + optlen
;
794 minpacket
+= pr
->icmp_minlen
; /* minimum ICMP header size */
796 minpacket
+= sizeof (struct udphdr
);
799 plen
= minpacket
; /* minimum sized packet */
800 } else if (minpacket
> plen
|| plen
> IP_MAXPACKET
) {
801 Fprintf(stderr
, "%s: %s packet size must be >= %d and <= %d\n",
802 prog
, pr
->name
, minpacket
, IP_MAXPACKET
);
810 * Sets the source address by resolving -i and -s arguments, or if -i and -s
811 * don't dictate any, it sets the pick_src to make sure traceroute uses the
812 * kernel's pick of the source address.
813 * Returns number of interfaces configured on the source host, 0 on error or
814 * there's no interface which is up amd not a loopback.
817 set_src_addr(struct pr_set
*pr
, struct ifaddrlist
**alp
)
819 union any_in_addr
*ap
;
820 struct ifaddrlist
*al
= NULL
;
821 struct ifaddrlist
*tmp1_al
= NULL
;
822 struct ifaddrlist
*tmp2_al
= NULL
;
823 /* LINTED E_BAD_PTR_CAST_ALIGN */
824 struct sockaddr_in
*sin_from
= (struct sockaddr_in
*)pr
->from
;
825 /* LINTED E_BAD_PTR_CAST_ALIGN */
826 struct sockaddr_in6
*sin6_from
= (struct sockaddr_in6
*)pr
->from
;
827 struct addrinfo
*aip
;
828 char errbuf
[ERRBUFSIZE
];
829 char temp_buf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
830 int num_ifs
; /* all the interfaces */
831 int num_src_ifs
; /* exclude loopback and down */
834 source
= source_input
;
836 /* get the interface address list */
837 num_ifs
= ifaddrlist(&al
, pr
->family
, errbuf
);
839 Fprintf(stderr
, "%s: ifaddrlist: %s\n", prog
, errbuf
);
844 for (i
= 0; i
< num_ifs
; i
++) {
845 if (!(al
[i
].flags
& IFF_LOOPBACK
) && (al
[i
].flags
& IFF_UP
))
849 if (num_src_ifs
== 0) {
850 Fprintf(stderr
, "%s: can't find any %s network interfaces\n",
855 /* verify the device */
856 if (device
!= NULL
) {
857 tmp1_al
= find_device(al
, num_ifs
, device
);
859 if (tmp1_al
== NULL
) {
860 Fprintf(stderr
, "%s: %s (index %d) is an invalid %s"
861 " interface\n", prog
, device
, if_index
, pr
->name
);
867 /* verify the source address */
868 if (source
!= NULL
) {
869 get_hostinfo(source
, pr
->family
, &aip
);
872 "%s: %s is an invalid %s source address\n",
873 prog
, source
, pr
->name
);
879 source
= aip
->ai_canonname
;
881 if (pr
->family
== AF_INET
)
882 ap
= (union any_in_addr
*)
883 /* LINTED E_BAD_PTR_CAST_ALIGN */
884 &((struct sockaddr_in
*)
885 aip
->ai_addr
)->sin_addr
;
887 ap
= (union any_in_addr
*)
888 /* LINTED E_BAD_PTR_CAST_ALIGN */
889 &((struct sockaddr_in6
*)
890 aip
->ai_addr
)->sin6_addr
;
893 * LBNL bug fixed: used to accept any src address
895 tmp2_al
= find_ifaddr(al
, num_ifs
, ap
, pr
->family
);
897 if (tmp2_al
== NULL
) {
899 "%s: %s is not a local %s address\n",
900 prog
, inet_ntop(pr
->family
, ap
,
901 temp_buf
, sizeof (temp_buf
)),
912 if (source
== NULL
) { /* no -s used */
913 if (device
== NULL
) { /* no -i used, no -s used */
915 } else { /* -i used, no -s used */
917 * -i used, but not -s, and it's IPv4: set the source
918 * address to whatever the interface has configured on
921 if (pr
->family
== AF_INET
)
922 set_sin(pr
->from
, &(tmp1_al
->addr
), pr
->family
);
926 } else { /* -s used */
927 if (device
== NULL
) { /* no -i used, -s used */
928 set_sin(pr
->from
, ap
, pr
->family
);
930 if (aip
->ai_next
!= NULL
) {
932 "%s: Warning: %s has multiple "
933 "addresses; using %s\n",
935 inet_ntop(pr
->family
,
936 (const void *)pr
->from_sin_addr
,
937 temp_buf
, sizeof (temp_buf
)));
939 } else { /* -i and -s used */
941 * Make sure the source specified matches the
942 * interface address. You only care about this for IPv4
943 * IPv6 can handle IF not matching src address
945 if (pr
->family
== AF_INET
) {
946 if (!has_addr(aip
, &tmp1_al
->addr
)) {
948 "%s: %s is not on interface %s\n",
949 prog
, source
, device
);
953 * make sure we use the one matching the
954 * interface's address
959 set_sin(pr
->from
, ap
, pr
->family
);
964 * Binding at this point will set the source address to be used
965 * for both IPv4 (when raw IP datagrams are not required) and
966 * IPv6. If the address being bound to is zero, then the kernel
967 * will end up choosing the source address when the datagram is
970 * For raw IPv4 datagrams, the source address is initialized
971 * within traceroute() along with the outbound destination
974 if (pr
->family
== AF_INET
&& !raw_req
) {
975 sin_from
->sin_family
= AF_INET
;
976 sin_from
->sin_port
= htons(ident
);
977 if (bind(sndsock4
, (struct sockaddr
*)pr
->from
,
978 sizeof (struct sockaddr_in
)) < 0) {
979 Fprintf(stderr
, "%s: bind: %s\n", prog
,
983 } else if (pr
->family
== AF_INET6
) {
984 sin6_from
->sin6_family
= AF_INET6
;
985 sin6_from
->sin6_port
= htons(ident
);
986 if (bind(sndsock6
, (struct sockaddr
*)pr
->from
,
987 sizeof (struct sockaddr_in6
)) < 0) {
988 Fprintf(stderr
, "%s: bind: %s\n", prog
,
993 whereto6
.sin6_flowinfo
= htonl((class << 20) | flow
);
1000 * Returns the complete ifaddrlist structure matching the desired interface
1001 * address. Ignores interfaces which are either down or loopback.
1003 static struct ifaddrlist
*
1004 find_ifaddr(struct ifaddrlist
*al
, int len
, union any_in_addr
*addr
,
1007 struct ifaddrlist
*tmp_al
= al
;
1009 size_t addr_len
= (family
== AF_INET
) ? sizeof (struct in_addr
) :
1010 sizeof (struct in6_addr
);
1012 for (i
= 0; i
< len
; i
++, tmp_al
++) {
1013 if ((!(tmp_al
->flags
& IFF_LOOPBACK
) &&
1014 (tmp_al
->flags
& IFF_UP
)) &&
1015 (memcmp(&tmp_al
->addr
, addr
, addr_len
) == 0))
1027 * Returns the complete ifaddrlist structure matching the desired interface name
1028 * Ignores interfaces which are either down or loopback.
1030 static struct ifaddrlist
*
1031 find_device(struct ifaddrlist
*al
, int len
, char *device
)
1033 struct ifaddrlist
*tmp_al
= al
;
1036 for (i
= 0; i
< len
; i
++, tmp_al
++) {
1037 if ((!(tmp_al
->flags
& IFF_LOOPBACK
) &&
1038 (tmp_al
->flags
& IFF_UP
)) &&
1039 (strcmp(tmp_al
->device
, device
) == 0))
1051 * returns _B_TRUE if given hostinfo contains the given address
1054 has_addr(struct addrinfo
*ai
, union any_in_addr
*addr
)
1056 struct addrinfo
*ai_tmp
= NULL
;
1057 union any_in_addr
*ap
;
1059 for (ai_tmp
= ai
; ai_tmp
!= NULL
; ai_tmp
= ai_tmp
->ai_next
) {
1060 if (ai_tmp
->ai_family
== AF_INET6
)
1062 ap
= (union any_in_addr
*)
1063 /* LINTED E_BAD_PTR_CAST_ALIGN */
1064 &((struct sockaddr_in
*)ai_tmp
->ai_addr
)->sin_addr
;
1065 if (memcmp(ap
, addr
, sizeof (struct in_addr
)) == 0)
1069 if (ai_tmp
!= NULL
) {
1077 * Resolve the gateway names, splitting results into v4 and v6 lists.
1078 * Gateway addresses are added to the appropriate passed-in array; the
1079 * number of resolved gateways for each af is returned in resolved[6].
1080 * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
1081 * and resolved[6] ptrs are non-null; ignores array and counter if the
1082 * address family param makes them irrelevant.
1085 get_gwaddrs(char **gwlist
, int family
, union any_in_addr
*gwIPlist
,
1086 union any_in_addr
*gwIPlist6
, int *resolved
, int *resolved6
)
1089 boolean_t check_v4
= _B_TRUE
, check_v6
= _B_TRUE
;
1090 struct addrinfo
*ai
= NULL
;
1091 struct addrinfo
*aip
= NULL
;
1093 *resolved
= *resolved6
= 0;
1098 check_v6
= _B_FALSE
;
1101 check_v4
= _B_FALSE
;
1107 if (check_v4
&& gw_count
>= MAX_GWS
) {
1108 check_v4
= _B_FALSE
;
1109 Fprintf(stderr
, "%s: too many IPv4 gateways\n", prog
);
1112 if (check_v6
&& gw_count
>= MAX_GWS6
) {
1113 check_v6
= _B_FALSE
;
1114 Fprintf(stderr
, "%s: too many IPv6 gateways\n", prog
);
1118 for (i
= 0; i
< gw_count
; i
++) {
1119 if (!check_v4
&& !check_v6
)
1121 get_hostinfo(gwlist
[i
], family
, &ai
);
1124 if (check_v4
&& num_v4
!= 0) {
1125 check_v4
= _B_FALSE
;
1126 for (aip
= ai
; aip
!= NULL
; aip
= aip
->ai_next
) {
1127 if (aip
->ai_family
== AF_INET
) {
1128 /* LINTED E_BAD_PTR_CAST_ALIGN */
1129 bcopy(&((struct sockaddr_in
*)
1130 aip
->ai_addr
)->sin_addr
,
1138 } else if (check_v4
) {
1139 check_v4
= _B_FALSE
;
1141 if (check_v6
&& num_v6
!= 0) {
1142 check_v6
= _B_FALSE
;
1143 for (aip
= ai
; aip
!= NULL
; aip
= aip
->ai_next
) {
1144 if (aip
->ai_family
== AF_INET6
) {
1145 /* LINTED E_BAD_PTR_CAST_ALIGN */
1146 bcopy(&((struct sockaddr_in6
*)
1147 aip
->ai_addr
)->sin6_addr
,
1148 &gwIPlist6
[i
].addr6
,
1155 } else if (check_v6
) {
1156 check_v6
= _B_FALSE
;
1163 * set protocol specific values here
1166 setup_protocol(struct pr_set
*pr
, int family
)
1169 * Set the global variables for each AF. This is going to save us lots
1170 * of "if (family == AF_INET)... else .."
1172 pr
->family
= family
;
1174 if (family
== AF_INET
) {
1177 "%s: Warning: checksums disabled\n", prog
);
1179 (void) strcpy(pr
->name
, "IPv4");
1180 (void) strcpy(pr
->icmp
, "icmp");
1181 pr
->icmp_minlen
= ICMP_MINLEN
;
1182 pr
->addr_len
= sizeof (struct in_addr
);
1183 pr
->ip_hdr_len
= sizeof (struct ip
);
1184 pr
->sock_size
= sizeof (struct sockaddr_in
);
1185 pr
->to
= (struct sockaddr
*)&whereto
;
1186 pr
->from
= (struct sockaddr
*)&wherefrom
;
1187 pr
->from_sin_addr
= (void *)&wherefrom
.sin_addr
;
1188 pr
->gwIPlist
= gwIPlist
;
1189 pr
->set_buffers_fn
= set_buffers
;
1190 pr
->check_reply_fn
= check_reply
;
1191 pr
->print_icmp_other_fn
= print_icmp_other
;
1192 pr
->print_addr_fn
= print_addr
;
1193 pr
->packlen
= calc_packetlen(packlen_input
, pr
);
1195 (void) strcpy(pr
->name
, "IPv6");
1196 (void) strcpy(pr
->icmp
, "ipv6-icmp");
1197 pr
->icmp_minlen
= ICMP6_MINLEN
;
1198 pr
->addr_len
= sizeof (struct in6_addr
);
1199 pr
->ip_hdr_len
= sizeof (struct ip6_hdr
);
1200 pr
->sock_size
= sizeof (struct sockaddr_in6
);
1201 pr
->to
= (struct sockaddr
*)&whereto6
;
1202 pr
->from
= (struct sockaddr
*)&wherefrom6
;
1203 pr
->from_sin_addr
= (void *)&wherefrom6
.sin6_addr
;
1204 pr
->gwIPlist
= gwIP6list
;
1205 pr
->set_buffers_fn
= set_buffers6
;
1206 pr
->check_reply_fn
= check_reply6
;
1207 pr
->print_icmp_other_fn
= print_icmp_other6
;
1208 pr
->print_addr_fn
= print_addr6
;
1209 pr
->packlen
= calc_packetlen(packlen_input
, pr
);
1211 if (pr
->packlen
== 0)
1216 * setup the sockets for the given protocol's address family
1219 setup_socket(struct pr_set
*pr
, int packet_len
)
1222 struct protoent
*pe
;
1229 if ((pe
= getprotobyname(pr
->icmp
)) == NULL
) {
1230 Fprintf(stderr
, "%s: unknown protocol %s\n", prog
, pr
->icmp
);
1234 /* privilege bracketing */
1235 (void) __priv_bracket(PRIV_ON
);
1237 if ((rsock
= socket(pr
->family
, SOCK_RAW
, pe
->p_proto
)) < 0) {
1238 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
, strerror(errno
));
1242 if (options
& SO_DEBUG
) {
1243 if (setsockopt(rsock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1245 Fprintf(stderr
, "%s: SO_DEBUG: %s\n", prog
,
1250 if (options
& SO_DONTROUTE
) {
1251 if (setsockopt(rsock
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
1253 Fprintf(stderr
, "%s: SO_DONTROUTE: %s\n", prog
,
1259 if (pr
->family
== AF_INET6
) {
1260 /* Enable receipt of destination address info */
1261 if (setsockopt(rsock
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
,
1262 (char *)&on
, sizeof (on
)) < 0) {
1263 Fprintf(stderr
, "%s: IPV6_RECVPKTINFO: %s\n", prog
,
1267 /* Enable receipt of hoplimit info */
1268 if (setsockopt(rsock
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
,
1269 (char *)&on
, sizeof (on
)) < 0) {
1270 Fprintf(stderr
, "%s: IPV6_RECVHOPLIMIT: %s\n", prog
,
1278 * Initialize the socket type and protocol based on the address
1279 * family, whether or not a raw IP socket is required (for IPv4)
1280 * or whether ICMP will be used instead of UDP.
1282 * For historical reasons, the datagrams sent out by
1283 * traceroute(1M) do not have the "don't fragment" flag set. For
1284 * this reason as well as the ability to set the Loose Source and
1285 * Record Route (LSRR) option, a raw IP socket will be used for
1286 * IPv4 when run in the global zone. Otherwise, the actual
1287 * datagram that will be sent will be a regular UDP or ICMP echo
1288 * request packet. However for convenience and for future options
1289 * when other IP header information may be specified using
1290 * traceroute, the buffer including the raw IP and UDP or ICMP
1291 * header is always filled in. When the probe is actually sent,
1292 * the size of the request and the start of the packet is set
1293 * according to the type of datagram to send.
1295 if (pr
->family
== AF_INET
&& raw_req
) {
1297 proto
= IPPROTO_RAW
;
1298 } else if (useicmp
) {
1300 if (pr
->family
== AF_INET
)
1301 proto
= IPPROTO_ICMP
;
1303 proto
= IPPROTO_ICMPV6
;
1306 proto
= IPPROTO_UDP
;
1308 ssock
= socket(pr
->family
, type
, proto
);
1311 if (proto
== IPPROTO_RAW
) {
1312 Fprintf(stderr
, "%s: raw socket: %s\n", prog
,
1314 } else if (proto
== IPPROTO_UDP
) {
1315 Fprintf(stderr
, "%s: udp socket: %s\n", prog
,
1318 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
,
1324 if (setsockopt(ssock
, SOL_SOCKET
, SO_SNDBUF
, (char *)&packet_len
,
1325 sizeof (packet_len
)) < 0) {
1326 Fprintf(stderr
, "%s: SO_SNDBUF: %s\n", prog
, strerror(errno
));
1330 if (pr
->family
== AF_INET
&& raw_req
) {
1331 if (setsockopt(ssock
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
1333 Fprintf(stderr
, "%s: IP_HDRINCL: %s\n", prog
,
1339 if (options
& SO_DEBUG
) {
1340 if (setsockopt(ssock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1342 Fprintf(stderr
, "%s: SO_DEBUG: %s\n", prog
,
1347 if (options
& SO_DONTROUTE
) {
1348 if (setsockopt(ssock
, SOL_SOCKET
, SO_DONTROUTE
,
1349 (char *)&on
, sizeof (on
)) < 0) {
1350 Fprintf(stderr
, "%s: SO_DONTROUTE: %s\n", prog
,
1357 * If a raw IPv4 packet is going to be sent, the Type of Service
1358 * field in the packet will be initialized in set_buffers().
1359 * Otherwise, it is initialized here using the IPPROTO_IP level
1362 if (settos
&& !raw_req
) {
1364 if (setsockopt(ssock
, IPPROTO_IP
, IP_TOS
, (char *)&int_op
,
1365 sizeof (int_op
)) < 0) {
1366 Fprintf(stderr
, "%s: IP_TOS: %s\n", prog
,
1371 if (pr
->family
== AF_INET
) {
1378 /* Revert to non-privileged user after configuring sockets */
1379 (void) __priv_bracket(PRIV_OFF
);
1383 * If we are "probing all", this function calls traceroute() for each IP address
1384 * of the target, otherwise calls only once. Returns _B_FALSE if traceroute()
1388 trace_it(struct addrinfo
*ai_dst
)
1391 int num_dst_IPaddrs
;
1392 struct addrinfo
*aip
;
1396 num_dst_IPaddrs
= 1;
1398 num_dst_IPaddrs
= num_v4
+ num_v6
;
1401 * Initialize the msg6 structure using the hoplimit for the first
1402 * probe packet, gateway addresses and the outgoing interface index.
1404 if (ai_dst
->ai_family
== AF_INET6
|| (probe_all
&& num_v6
)) {
1405 msg6
.msg_control
= NULL
;
1406 msg6
.msg_controllen
= 0;
1407 set_ancillary_data(&msg6
, first_ttl
, pr6
->gwIPlist
, gw_count
,
1411 /* run traceroute for all the IP addresses of the multihomed dest */
1412 for (aip
= ai_dst
, i
= 0; i
< num_dst_IPaddrs
&& aip
!= NULL
; i
++) {
1413 union any_in_addr
*addrp
;
1414 if (aip
->ai_family
== AF_INET
) {
1415 addrp
= (union any_in_addr
*)
1416 /* LINTED E_BAD_PTR_CAST_ALIGN */
1417 &((struct sockaddr_in
*)
1418 aip
->ai_addr
)->sin_addr
;
1419 set_sin((struct sockaddr
*)pr4
->to
, addrp
,
1421 traceroute(addrp
, &msg6
, pr4
, num_ifs4
, al4
);
1423 addrp
= (union any_in_addr
*)
1424 /* LINTED E_BAD_PTR_CAST_ALIGN */
1425 &((struct sockaddr_in6
*)
1426 aip
->ai_addr
)->sin6_addr
;
1427 set_sin((struct sockaddr
*)pr6
->to
, addrp
,
1429 traceroute(addrp
, &msg6
, pr6
, num_ifs6
, al6
);
1432 if (i
< (num_dst_IPaddrs
- 1))
1433 (void) putchar('\n');
1438 * set the IP address in a sockaddr struct
1441 set_sin(struct sockaddr
*sock
, union any_in_addr
*addr
, int family
)
1443 sock
->sa_family
= family
;
1445 if (family
== AF_INET
)
1446 /* LINTED E_BAD_PTR_CAST_ALIGN */
1447 ((struct sockaddr_in
*)sock
)->sin_addr
= addr
->addr
;
1449 /* LINTED E_BAD_PTR_CAST_ALIGN */
1450 ((struct sockaddr_in6
*)sock
)->sin6_addr
= addr
->addr6
;
1454 * returns the IF name on which the given IP address is configured
1457 device_name(struct ifaddrlist
*al
, int len
, union any_in_addr
*ip_addr
,
1461 struct ifaddrlist
*tmp_al
;
1465 for (i
= 0; i
< len
; i
++, tmp_al
++) {
1466 if (memcmp(&tmp_al
->addr
, ip_addr
, pr
->addr_len
) == 0) {
1467 return (tmp_al
->device
);
1475 * Trace the route to the host with given IP address.
1478 traceroute(union any_in_addr
*ip_addr
, struct msghdr
*msg6
, struct pr_set
*pr
,
1479 int num_ifs
, struct ifaddrlist
*al
)
1483 uchar_t type
; /* icmp type */
1484 uchar_t code
; /* icmp code */
1487 char temp_buf
[INET6_ADDRSTRLEN
]; /* use for inet_ntop() */
1488 int longjmp_return
; /* return value from longjump */
1489 struct ip
*ip
= (struct ip
*)packet
;
1490 boolean_t got_there
= _B_FALSE
; /* we hit the destination */
1491 static boolean_t first_pkt
= _B_TRUE
;
1492 int hoplimit
; /* hoplimit for IPv6 packets */
1493 struct in6_addr addr6
;
1494 int num_src_ifs
; /* excludes down and loopback */
1495 struct msghdr in_msg
;
1501 msg6
->msg_name
= pr
->to
;
1502 msg6
->msg_namelen
= sizeof (struct sockaddr_in6
);
1503 sndsock
= (pr
->family
== AF_INET
) ? sndsock4
: sndsock6
;
1504 rcvsock
= (pr
->family
== AF_INET
) ? rcvsock4
: rcvsock6
;
1506 /* carry out the source address selection */
1508 union any_in_addr src_addr
;
1513 * If there's a gateway, a routing header as a consequence, our
1514 * kernel picks the source address based on the first hop
1515 * address, rather than final destination address.
1518 (void) select_src_addr(pr
->gwIPlist
, &src_addr
,
1521 (void) select_src_addr(ip_addr
, &src_addr
, pr
->family
);
1523 set_sin(pr
->from
, &src_addr
, pr
->family
);
1525 /* filter out down and loopback interfaces */
1527 for (i
= 0; i
< num_ifs
; i
++) {
1528 if (!(al
[i
].flags
& IFF_LOOPBACK
) &&
1529 (al
[i
].flags
& IFF_UP
))
1533 if (num_src_ifs
> 1) {
1534 dev_name
= device_name(al
, num_ifs
, &src_addr
, pr
);
1535 if (dev_name
== NULL
)
1539 "%s: Warning: Multiple interfaces found;"
1541 prog
, inet_ntop(pr
->family
,
1542 (const void *)pr
->from_sin_addr
,
1543 temp_buf
, sizeof (temp_buf
)),
1548 if (pr
->family
== AF_INET
) {
1549 outip4
->ip_src
= *(struct in_addr
*)pr
->from_sin_addr
;
1550 outip4
->ip_dst
= ip_addr
->addr
;
1554 * If the hostname is an IPv6 literal address, let's not print it twice.
1556 if (pr
->family
== AF_INET6
&&
1557 inet_pton(AF_INET6
, hostname
, &addr6
) > 0) {
1558 Fprintf(stderr
, "%s to %s", prog
, hostname
);
1560 Fprintf(stderr
, "%s to %s (%s)", prog
, hostname
,
1561 inet_ntop(pr
->family
, (const void *)ip_addr
, temp_buf
,
1562 sizeof (temp_buf
)));
1566 Fprintf(stderr
, " from %s", source
);
1567 Fprintf(stderr
, ", %d hops max, %d byte packets\n", max_ttl
,
1569 (void) fflush(stderr
);
1572 * Setup the source routing for IPv4. For IPv6, we did the required
1573 * setup in the caller function, trace_it(), because it's independent
1574 * from the IP address of target.
1576 if (pr
->family
== AF_INET
&& gw_count
> 0)
1577 set_IPv4opt_sourcerouting(sndsock
, ip_addr
, pr
->gwIPlist
);
1580 /* interrupt handler sig_handler() jumps back to here */
1581 if ((longjmp_return
= setjmp(env
)) != 0) {
1582 switch (longjmp_return
) {
1584 Printf("(skipping)\n");
1587 Printf("(exiting)\n");
1589 default: /* should never happen */
1593 (void) signal(SIGINT
, sig_handler
);
1596 for (ttl
= first_ttl
; ttl
<= max_ttl
; ++ttl
) {
1597 union any_in_addr lastaddr
;
1599 double rtt
; /* for statistics */
1601 double rttmin
, rttmax
;
1602 double rttsum
, rttssq
;
1605 got_there
= _B_FALSE
;
1609 * The following line clears both IPv4 and IPv6 address stored
1612 lastaddr
.addr6
= in6addr_any
;
1614 if ((ttl
== (first_ttl
+ 1)) && (options
& SO_DONTROUTE
)) {
1616 "%s: host %s is not on a directly-attached"
1617 " network\n", prog
, hostname
);
1621 Printf("%2d ", ttl
);
1622 (void) fflush(stdout
);
1624 for (probe
= 0; (probe
< nprobes
) && (timeouts
< max_timeout
);
1627 struct timeval t1
, t2
;
1630 * Put a delay before sending this probe packet. Don't
1631 * delay it if it's the very first packet.
1634 if (delay
.tv_sec
> 0)
1635 (void) sleep((uint_t
)delay
.tv_sec
);
1636 if (delay
.tv_usec
> 0)
1637 (void) usleep(delay
.tv_usec
);
1639 first_pkt
= _B_FALSE
;
1642 (void) gettimeofday(&t1
, NULL
);
1644 if (pr
->family
== AF_INET
) {
1645 send_probe(sndsock
, pr
->to
, outip4
, seq
, ttl
,
1648 send_probe6(sndsock
, msg6
, outip6
, seq
, ttl
,
1652 /* prepare msghdr for recvmsg() */
1653 in_msg
.msg_name
= pr
->from
;
1654 in_msg
.msg_namelen
= pr
->sock_size
;
1656 iov
.iov_base
= (char *)packet
;
1657 iov
.iov_len
= sizeof (packet
);
1659 in_msg
.msg_iov
= &iov
;
1660 in_msg
.msg_iovlen
= 1;
1662 in_msg
.msg_control
= ancillary_data
;
1663 in_msg
.msg_controllen
= sizeof (ancillary_data
);
1665 while ((cc
= wait_for_reply(rcvsock
, &in_msg
,
1667 (void) gettimeofday(&t2
, NULL
);
1669 reply
= (*pr
->check_reply_fn
) (&in_msg
, cc
, seq
,
1672 in_msg
.msg_controllen
=
1673 sizeof (ancillary_data
);
1674 /* Skip short packet */
1675 if (reply
== REPLY_SHORT_PKT
) {
1682 * if reply comes from a different host, print
1685 if (memcmp(pr
->from_sin_addr
, &lastaddr
,
1686 pr
->addr_len
) != 0) {
1687 (*pr
->print_addr_fn
) ((uchar_t
*)packet
,
1689 /* store the address response */
1690 (void) memcpy(&lastaddr
,
1691 pr
->from_sin_addr
, pr
->addr_len
);
1694 rtt
= deltaT(&t1
, &t2
);
1696 record_stats(rtt
, &nreceived
, &rttmin
,
1697 &rttmax
, &rttsum
, &rttssq
);
1699 Printf(" %.3f ms", rtt
);
1702 if (pr
->family
== AF_INET6
) {
1704 (int *)find_ancillary_data(&in_msg
,
1705 IPPROTO_IPV6
, IPV6_HOPLIMIT
);
1709 "IPV6_HOPLIMIT ancillary "
1716 if (reply
== REPLY_GOT_TARGET
) {
1717 got_there
= _B_TRUE
;
1719 if (((pr
->family
== AF_INET
) &&
1720 (ip
->ip_ttl
<= 1)) ||
1721 ((pr
->family
== AF_INET6
) &&
1726 if (!collect_stat
&& showttl
) {
1727 if (pr
->family
== AF_INET
) {
1730 } else if (hoplimit
!= -1) {
1731 Printf(" (hop limit=%d)",
1736 if (reply
== REPLY_GOT_OTHER
) {
1737 if ((*pr
->print_icmp_other_fn
)
1744 if (pr
->family
== AF_INET
&&
1745 type
== ICMP_UNREACH
&&
1746 code
== ICMP_UNREACH_PROTOCOL
)
1747 got_there
= _B_TRUE
;
1752 seq
= (seq
+ 1) % (MAX_SEQ
+ 1);
1759 (void) fflush(stdout
);
1763 print_stats(probe
, nreceived
, rttmin
, rttmax
, rttsum
,
1767 (void) putchar('\n');
1769 /* either we hit the target or received too many unreachables */
1771 (unreachable
> 0 && unreachable
>= nprobes
- 1))
1775 /* Ignore the SIGINT between traceroute() runs */
1777 (void) signal(SIGINT
, SIG_IGN
);
1781 * for a given destination address and address family, it finds out what
1782 * source address kernel is going to pick
1785 select_src_addr(union any_in_addr
*dst_addr
, union any_in_addr
*src_addr
,
1789 struct sockaddr
*sock
;
1790 struct sockaddr_in
*sin
;
1791 struct sockaddr_in6
*sin6
;
1794 sock
= (struct sockaddr
*)malloc(sizeof (struct sockaddr_in6
));
1796 Fprintf(stderr
, "%s: malloc %s\n", prog
, strerror(errno
));
1799 (void) bzero(sock
, sizeof (struct sockaddr_in6
));
1801 if (family
== AF_INET
) {
1802 /* LINTED E_BAD_PTR_CAST_ALIGN */
1803 sin
= (struct sockaddr_in
*)sock
;
1804 sin
->sin_family
= AF_INET
;
1805 sin
->sin_addr
= dst_addr
->addr
;
1806 sin
->sin_port
= IPPORT_ECHO
; /* port shouldn't be 0 */
1807 sock_len
= sizeof (struct sockaddr_in
);
1809 /* LINTED E_BAD_PTR_CAST_ALIGN */
1810 sin6
= (struct sockaddr_in6
*)sock
;
1811 sin6
->sin6_family
= AF_INET6
;
1812 sin6
->sin6_addr
= dst_addr
->addr6
;
1813 sin6
->sin6_port
= IPPORT_ECHO
; /* port shouldn't be 0 */
1814 sock_len
= sizeof (struct sockaddr_in6
);
1817 /* open a UDP socket */
1818 if ((tmp_fd
= socket(family
, SOCK_DGRAM
, 0)) < 0) {
1819 Fprintf(stderr
, "%s: udp socket: %s\n", prog
,
1825 if (connect(tmp_fd
, sock
, sock_len
) < 0) {
1827 * If there's no route to the destination, this connect() call
1828 * fails. We just return all-zero (wildcard) as the source
1829 * address, so that user can get to see "no route to dest"
1830 * message, as it'll try to send the probe packet out and will
1831 * receive ICMP unreachable.
1833 if (family
== AF_INET
)
1834 src_addr
->addr
.s_addr
= INADDR_ANY
;
1836 src_addr
->addr6
= in6addr_any
;
1841 /* get the local sock info */
1842 if (getsockname(tmp_fd
, sock
, &sock_len
) < 0) {
1843 Fprintf(stderr
, "%s: getsockname: %s\n", prog
,
1848 if (family
== AF_INET
) {
1849 /* LINTED E_BAD_PTR_CAST_ALIGN */
1850 sin
= (struct sockaddr_in
*)sock
;
1851 src_addr
->addr
= sin
->sin_addr
;
1853 /* LINTED E_BAD_PTR_CAST_ALIGN */
1854 sin6
= (struct sockaddr_in6
*)sock
;
1855 src_addr
->addr6
= sin6
->sin6_addr
;
1859 (void) close(tmp_fd
);
1863 * Checksum routine for Internet Protocol family headers (C Version)
1866 in_cksum(ushort_t
*addr
, int len
)
1874 * Our algorithm is simple, using a 32 bit accumulator (sum),
1875 * we add sequential 16 bit words to it, and at the end, fold
1876 * back all the carry bits from the top 16 bits into the lower
1884 /* mop up an odd byte, if necessary */
1886 sum
+= *(uchar_t
*)w
;
1888 /* add back carry outs from top 16 bits to low 16 bits */
1889 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1890 sum
+= (sum
>> 16); /* add carry */
1891 answer
= ~sum
; /* truncate to 16 bits */
1896 * Wait until a reply arrives or timeout occurs. If packet arrived, read it
1897 * return the size of the packet read.
1900 wait_for_reply(int sock
, struct msghdr
*msg
, struct timeval
*tp
)
1903 struct timeval now
, wait
;
1907 (void) FD_ZERO(&fds
);
1910 wait
.tv_sec
= tp
->tv_sec
+ waittime
;
1911 wait
.tv_usec
= tp
->tv_usec
;
1912 (void) gettimeofday(&now
, NULL
);
1913 tv_sub(&wait
, &now
);
1915 if (wait
.tv_sec
< 0 || wait
.tv_usec
< 0)
1918 result
= select(sock
+ 1, &fds
, (fd_set
*)NULL
, (fd_set
*)NULL
, &wait
);
1921 if (errno
!= EINTR
) {
1922 Fprintf(stderr
, "%s: select: %s\n", prog
,
1925 } else if (result
> 0)
1926 cc
= recvmsg(sock
, msg
, 0);
1932 * Construct an Internet address representation. If the nflag has been supplied,
1933 * give numeric value, otherwise try for symbolic name.
1936 inet_name(union any_in_addr
*in
, int family
)
1939 static boolean_t first
= _B_TRUE
;
1940 static char domain
[NI_MAXHOST
+ 1];
1941 static char line
[NI_MAXHOST
+ 1]; /* assuming */
1942 /* (NI_MAXHOST + 1) >= INET6_ADDRSTRLEN */
1943 char hbuf
[NI_MAXHOST
];
1945 struct sockaddr_in sin
;
1946 struct sockaddr_in6 sin6
;
1947 struct sockaddr
*sa
;
1952 slen
= sizeof (struct sockaddr_in
);
1953 sin
.sin_addr
= in
->addr
;
1955 sa
= (struct sockaddr
*)&sin
;
1958 slen
= sizeof (struct sockaddr_in6
);
1959 sin6
.sin6_addr
= in
->addr6
;
1961 sin6
.sin6_scope_id
= 0;
1962 sa
= (struct sockaddr
*)&sin6
;
1965 (void) snprintf(line
, sizeof (line
),
1966 "<invalid address family>");
1969 sa
->sa_family
= family
;
1971 if (first
&& !nflag
) {
1972 /* find out the domain name */
1974 if (gethostname(domain
, MAXHOSTNAMELEN
) == 0 &&
1975 (cp
= strchr(domain
, '.')) != NULL
) {
1976 (void) strncpy(domain
, cp
+ 1, sizeof (domain
) - 1);
1977 domain
[sizeof (domain
) - 1] = '\0';
1983 flags
= (nflag
) ? NI_NUMERICHOST
: NI_NAMEREQD
;
1984 if (getnameinfo(sa
, slen
, hbuf
, sizeof (hbuf
), NULL
, 0, flags
) != 0) {
1985 if (inet_ntop(family
, (const void *)&in
->addr6
,
1986 hbuf
, sizeof (hbuf
)) == NULL
)
1988 } else if (!nflag
&& (cp
= strchr(hbuf
, '.')) != NULL
&&
1989 strcmp(cp
+ 1, domain
) == 0) {
1992 (void) strlcpy(line
, hbuf
, sizeof (line
));
1998 * return the difference (in msec) between two time values
2001 deltaT(struct timeval
*t1p
, struct timeval
*t2p
)
2005 dt
= (double)(t2p
->tv_sec
- t1p
->tv_sec
) * 1000.0 +
2006 (double)(t2p
->tv_usec
- t1p
->tv_usec
) / 1000.0;
2011 * Subtract 2 timeval structs: out = out - in.
2012 * Out is assumed to be >= in.
2015 tv_sub(struct timeval
*out
, struct timeval
*in
)
2017 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
2019 out
->tv_usec
+= 1000000;
2021 out
->tv_sec
-= in
->tv_sec
;
2028 record_stats(double rtt
, int *nreceived
, double *rttmin
, double *rttmax
,
2029 double *rttsum
, double *rttssq
)
2031 if (*nreceived
== 0) {
2035 *rttssq
= rtt
* rtt
;
2044 *rttssq
+= rtt
* rtt
;
2051 * display statistics
2054 print_stats(int ntransmitted
, int nreceived
, double rttmin
, double rttmax
,
2055 double rttsum
, double rttssq
)
2057 double rttavg
; /* average round-trip time */
2058 double rttstd
; /* rtt standard deviation */
2060 if (ntransmitted
> 0 && ntransmitted
>= nreceived
) {
2061 int missed
= ntransmitted
- nreceived
;
2062 double loss
= 100 * (double)missed
/ (double)ntransmitted
;
2064 if (nreceived
> 0) {
2065 rttavg
= rttsum
/ nreceived
;
2066 rttstd
= rttssq
- (rttavg
* rttsum
);
2067 rttstd
= xsqrt(rttstd
/ nreceived
);
2069 Printf(" %.3f", rttmin
);
2070 Printf("/%.3f", rttavg
);
2071 Printf("/%.3f", rttmax
);
2073 Printf(" (%.3f) ms ", rttstd
);
2076 Printf(" %d/%d pkts", nreceived
, ntransmitted
);
2079 Printf(" (100%% loss)");
2081 Printf(" (%.2g%% loss)", loss
);
2086 * square root function
2097 x
= (y
< 1.0) ? 1.0 : y
;
2100 x
= (t
+ (y
/t
))/2.0;
2101 } while (0 < x
&& x
< t
);
2107 * String to double with optional min and max.
2110 str2dbl(const char *str
, const char *what
, double mi
, double ma
)
2117 val
= strtod(str
, &ep
);
2118 if (errno
!= 0 || *ep
!= '\0') {
2119 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
2123 if (val
< mi
&& mi
>= 0) {
2124 Fprintf(stderr
, "%s: %s must be >= %f\n", prog
, what
, mi
);
2127 if (val
> ma
&& ma
>= 0) {
2128 Fprintf(stderr
, "%s: %s must be <= %f\n", prog
, what
, ma
);
2135 * String to int with optional min and max. Handles decimal and hex.
2138 str2int(const char *str
, const char *what
, int mi
, int ma
)
2146 if (str
[0] == '0' && (str
[1] == 'x' || str
[1] == 'X')) {
2148 val
= (int)strtol(cp
, &ep
, 16);
2150 val
= (int)strtol(str
, &ep
, 10);
2152 if (errno
!= 0 || *ep
!= '\0') {
2153 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
2157 if (val
< mi
&& mi
>= 0) {
2159 Fprintf(stderr
, "%s: %s must be >= %d\n",
2162 Fprintf(stderr
, "%s: %s must be > %d\n",
2163 prog
, what
, mi
- 1);
2167 if (val
> ma
&& ma
>= 0) {
2168 Fprintf(stderr
, "%s: %s must be <= %d\n", prog
, what
, ma
);
2175 * This is the interrupt handler for SIGINT and SIGQUIT. It's completely handled
2176 * where it jumps to.
2179 sig_handler(int sig
)
2185 * display the usage of traceroute
2190 Fprintf(stderr
, "Usage: %s [-adFIlnSvx] [-A address_family] "
2191 "[-c traffic_class] \n"
2192 "\t[-f first_hop] [-g gateway [-g gateway ...]| -r] [-i iface]\n"
2193 "\t[-L flow_label] [-m max_hop] [-P pause_sec] [-p port] [-Q max_timeout]\n"
2194 "\t[-q nqueries] [-s src_addr] [-t tos] [-w wait_time] host [packetlen]\n",