4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
26 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
27 * All Rights Reserved.
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California.
33 * All Rights Reserved.
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
41 * Copyright 2015, Joyent, Inc.
58 #include <sys/param.h>
59 #include <sys/socket.h>
60 #include <sys/sockio.h>
61 #include <sys/stropts.h>
63 #include <sys/sysmacros.h>
64 #include <sys/debug.h>
66 #include <arpa/inet.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/in.h>
70 #include <netinet/ip.h>
71 #include <netinet/ip_icmp.h>
72 #include <netinet/ip_var.h>
73 #include <netinet/ip6.h>
74 #include <netinet/icmp6.h>
75 #include <netinet/udp.h>
78 #include <priv_utils.h>
80 #include <libinetutil.h>
84 * This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
85 * TCP's SEQ_LEQ macro.
87 #define PINGSEQ_LEQ(a, b) ((int16_t)((a)-(b)) <= 0)
89 #define MAX_WAIT 10 /* max sec. to wait for response */
90 #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
91 #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
92 #define MAX_TOS 255 /* max type-of-service for IPv4 */
94 #define TIMEOUT 20 /* default timeout value */
95 #define DEFAULT_DATALEN 56
97 #define MULTICAST_NOLOOP 1 /* multicast options */
98 #define MULTICAST_TTL 2
99 #define MULTICAST_IF 4
101 #define IF_INDEX 0 /* types of -i argument */
107 #define setbuf(s, b) setlinebuf((s))
111 /* interface identification */
113 int index
; /* interface index (e.g., 1, 2) */
114 char *name
; /* interface name (e.g., le0, hme0) */
115 union any_in_addr addr
; /* interface address (e.g., 10.123.4.5) */
118 /* stores the interface supplied by the user */
120 char *str
; /* unresolved, string input */
121 int id_type
; /* type of ID (index, name, addr, addr6) */
122 union if_id id
; /* ID */
129 static int send_sock
; /* send sockets */
130 static int send_sock6
;
131 static struct sockaddr_in to
; /* where to send */
132 static struct sockaddr_in6 to6
;
133 static union any_in_addr gw_IP_list
[MAX_GWS
]; /* gateways */
134 static union any_in_addr gw_IP_list6
[MAX_GWS6
];
135 static int if_index
= 0; /* outgoing interface index */
136 boolean_t is_alive
= _B_FALSE
; /* is target host alive */
137 struct targetaddr
*current_targetaddr
; /* current target IP address to probe */
138 static struct targetaddr
*targetaddr_list
; /* list of IP addresses to probe */
139 static int num_targetaddrs
; /* no of target addresses to probe */
140 static int num_v4
= 0; /* count of IPv4 addresses */
141 static int num_v6
= 0; /* count of IPv6 addresses */
142 boolean_t verbose
= _B_FALSE
; /* verbose output */
143 boolean_t stats
= _B_FALSE
; /* display statistics */
144 static boolean_t settos
= _B_FALSE
; /* set type-of-service value */
145 boolean_t rr_option
= _B_FALSE
; /* true if using record route */
146 boolean_t send_reply
= _B_FALSE
; /* Send an ICMP_{ECHO|TSTAMP}REPLY */
147 /* that goes to target and comes back */
148 /* to the the sender via src routing. */
149 boolean_t strict
= _B_FALSE
; /* true if using strict source route */
150 boolean_t ts_option
= _B_FALSE
; /* true if using timestamp option */
151 boolean_t use_icmp_ts
= _B_FALSE
; /* Use ICMP timestamp request */
152 boolean_t use_udp
= _B_FALSE
; /* Use UDP instead of ICMP */
153 boolean_t probe_all
= _B_FALSE
; /* probe all the IP addresses */
154 boolean_t nflag
= _B_FALSE
; /* do not reverse lookup addresses */
155 boolean_t bypass
= _B_FALSE
; /* bypass IPsec policy */
156 static int family_input
= AF_UNSPEC
; /* address family supplied by user */
157 int datalen
= DEFAULT_DATALEN
; /* How much data */
158 int ts_flag
; /* timestamp flag value */
159 static int num_gw
; /* number of gateways */
160 static int eff_num_gw
; /* effective number of gateways */
161 /* if send_reply, it's 2*num_gw+1 */
162 static int num_wraps
= -1; /* no of times 64K icmp_seq wrapped */
163 static ushort_t dest_port
= 32768 + 666; /* starting port for the UDP probes */
164 static char *gw_list
[MAXMAX_GWS
]; /* list of gateways as user enters */
165 static int options
; /* socket options */
166 static int moptions
; /* multicast options */
167 int npackets
; /* number of packets to send */
168 static ushort_t tos
; /* type-of-service value */
169 static int hoplimit
= -1; /* time-to-live value */
170 static int dontfrag
; /* IP*_DONTFRAG */
171 static int timeout
= TIMEOUT
; /* timeout value (sec) for probes */
172 static struct if_entry out_if
; /* interface argument */
173 int ident
; /* ID for this ping run */
174 static hrtime_t t_last_probe_sent
; /* the time we sent the last probe */
175 static timer_t timer
; /* timer for waiting */
176 static volatile boolean_t timer_done
= _B_FALSE
; /* timer finished? */
177 static struct itimerspec interval
= { { 0, 0 }, { 1, 0 } }; /* Interval for */
178 /* -I. The default interval is 1s. */
179 static hrtime_t mintime
= NSEC2MSEC(500); /* minimum time between pings */
182 * Globals for our name services warning. See ns_warning_thr() for more on why
185 static mutex_t ns_lock
= ERRORCHECKMUTEX
; /* Protects the following data */
186 static boolean_t ns_active
= _B_FALSE
; /* Lookup is going on */
187 static hrtime_t ns_starttime
; /* Time the lookup started */
188 static int ns_sleeptime
= 2; /* Time in seconds between checks */
189 static int ns_warntime
= 2; /* Time in seconds before warning */
190 static int ns_warninter
= 60; /* Time in seconds between warnings */
193 * This buffer stores the received packets. Currently it needs to be 32 bit
194 * aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
197 static uint64_t in_pkt
[(IP_MAXPACKET
+ 1)/8];
199 /* Used to store the ancillary data that comes with the received packets */
200 static uint64_t ancillary_data
[(IP_MAXPACKET
+ 1)/8];
202 static int ntransmitted
; /* number of packet sent to single IP address */
203 int nreceived
; /* # of packets we got back from target host */
204 int nreceived_last_target
; /* received from last target IP */
206 * These are used for statistics. tmin is initialized to maximum longint value.
207 * The max value is also used for timeouts. All times are in microseconds.
209 long long tmin
= LLONG_MAX
;
211 int64_t tsum
; /* sum of all times, for doing average */
212 int64_t tsum2
; /* sum of squared times, for std. dev. */
214 static struct targetaddr
*build_targetaddr_list(struct addrinfo
*,
215 union any_in_addr
*);
216 extern void check_reply(struct addrinfo
*, struct msghdr
*, int, ushort_t
);
217 extern void check_reply6(struct addrinfo
*, struct msghdr
*, int, ushort_t
);
218 static struct targetaddr
*create_targetaddr_item(int, union any_in_addr
*,
219 union any_in_addr
*);
220 void find_dstaddr(ushort_t
, union any_in_addr
*);
221 static struct ifaddrlist
*find_if(struct ifaddrlist
*, int);
222 static void finish();
223 static void get_gwaddrs(char *[], int, union any_in_addr
*,
224 union any_in_addr
*, int *, int *);
225 static void get_hostinfo(char *, int, struct addrinfo
**);
226 static ushort_t
in_cksum(ushort_t
*, int);
227 static int int_arg(char *s
, char *what
);
228 boolean_t
is_a_target(struct addrinfo
*, union any_in_addr
*);
229 static void mirror_gws(union any_in_addr
*, int);
230 static void *ns_warning_thr(void *);
231 static void parse_interval(char *s
);
232 static void pinger(int, struct sockaddr
*, struct msghdr
*, int);
233 char *pr_name(char *, int);
234 char *pr_protocol(int);
235 static void print_unknown_host_msg(const char *, const char *);
236 static void recv_icmp_packet(struct addrinfo
*, int, int, ushort_t
, ushort_t
);
237 static void resolve_nodes(struct addrinfo
**, struct addrinfo
**,
238 union any_in_addr
**);
239 void schedule_sigalrm();
240 static void select_all_src_addrs(union any_in_addr
**, struct addrinfo
*,
241 union any_in_addr
*, union any_in_addr
*);
242 static void select_src_addr(union any_in_addr
*, int, union any_in_addr
*);
243 void send_scheduled_probe();
244 boolean_t
seq_match(ushort_t
, int, ushort_t
);
245 extern void set_ancillary_data(struct msghdr
*, int, union any_in_addr
*, int,
247 extern void set_IPv4_options(int, union any_in_addr
*, int, struct in_addr
*,
249 static void set_nexthop(int, struct addrinfo
*, int);
250 static boolean_t
setup_socket(int, int *, int *, int *, ushort_t
*,
252 void sigalrm_handler();
253 void tvsub(struct timeval
*, struct timeval
*);
254 static void usage(char *);
260 main(int argc
, char *argv
[])
262 struct addrinfo
*ai_dst
= NULL
; /* addrinfo host list */
263 struct addrinfo
*ai_nexthop
= NULL
; /* addrinfo nexthop */
264 union any_in_addr
*src_addr_list
= NULL
; /* src addrs to use */
265 int recv_sock
= -1; /* receive sockets */
267 ushort_t udp_src_port
; /* src ports for UDP probes */
268 ushort_t udp_src_port6
; /* used to identify replies */
271 char abuf
[INET6_ADDRSTRLEN
];
274 boolean_t has_sys_ip_config
;
278 (void) setlocale(LC_ALL
, "");
281 * This program needs the net_icmpaccess privilege for creating
282 * raw ICMP sockets. It needs sys_ip_config for using the
283 * IP_NEXTHOP socket option (IPv4 only). We'll fail
284 * on the socket call and report the error there when we have
285 * insufficient privileges.
287 * Shared-IP zones don't have the sys_ip_config privilege, so
288 * we need to check for it in our limit set before trying
291 has_sys_ip_config
= priv_ineffect(PRIV_SYS_IP_CONFIG
);
293 (void) __init_suid_priv(PU_CLEARLIMITSET
, PRIV_NET_ICMPACCESS
,
294 has_sys_ip_config
? PRIV_SYS_IP_CONFIG
: NULL
, NULL
);
296 setbuf(stdout
, (char *)0);
298 while ((c
= getopt(argc
, argv
,
299 "abA:c:dDF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
302 if (strcmp(optarg
, "inet") == 0) {
303 family_input
= AF_INET
;
304 } else if (strcmp(optarg
, "inet6") == 0) {
305 family_input
= AF_INET6
;
308 "%s: unknown address family %s\n",
319 i
= int_arg(optarg
, "traffic class");
320 if (i
> MAX_TRAFFIC_CLASS
) {
321 Fprintf(stderr
, "%s: traffic class %d out of "
322 "range\n", progname
, i
);
341 i
= int_arg(optarg
, "flow label");
342 if (i
> MAX_FLOW_LABEL
) {
343 Fprintf(stderr
, "%s: flow label %d out of "
344 "range\n", progname
, i
);
347 flowinfo
= (uint_t
)i
;
352 parse_interval(optarg
);
357 * this can accept interface index, interface name, and
358 * address configured on the interface
360 moptions
|= MULTICAST_IF
;
363 if (inet_pton(AF_INET6
, optarg
, &out_if
.id
.addr
) > 0) {
364 out_if
.id_type
= IF_ADDR6
;
365 } else if (inet_pton(AF_INET
, optarg
,
366 &out_if
.id
.addr
) > 0) {
367 out_if
.id_type
= IF_ADDR
;
368 } else if (strcmp(optarg
, "0") == 0) {
369 out_if
.id_type
= IF_INDEX
;
371 } else if ((out_if
.id
.index
= atoi(optarg
)) != 0) {
372 out_if
.id_type
= IF_INDEX
;
374 out_if
.id
.name
= optarg
;
375 out_if
.id_type
= IF_NAME
;
380 moptions
|= MULTICAST_NOLOOP
;
384 send_reply
= _B_TRUE
;
394 i
= int_arg(optarg
, "type-of-service");
396 Fprintf(stderr
, "%s: tos value %d out of "
397 "range\n", progname
, i
);
404 i
= int_arg(optarg
, "port number");
406 Fprintf(stderr
, "%s: port number %d out of "
407 "range\n", progname
, i
);
410 dest_port
= (ushort_t
)i
;
414 options
|= SO_DONTROUTE
;
422 send_reply
= _B_TRUE
;
435 moptions
|= MULTICAST_TTL
;
436 hoplimit
= int_arg(optarg
, "ttl");
437 if (hoplimit
> MAXTTL
) {
438 Fprintf(stderr
, "%s: ttl %d out of range\n",
446 use_icmp_ts
= _B_FALSE
;
453 * 'x' and 'X' has been undocumented flags for source routing.
454 * Now we document loose source routing with the new flag 'g',
455 * which is same as in traceroute. We still keep x/X as
456 * as undocumented. 'G', which is for strict source routing is
462 if (num_gw
> MAXMAX_GWS
) {
463 Fprintf(stderr
, "%s: too many gateways\n",
467 gw_list
[num_gw
++] = optarg
;
473 if (num_gw
> MAXMAX_GWS
) {
474 Fprintf(stderr
, "%s: too many gateways\n",
478 gw_list
[num_gw
++] = optarg
;
482 if (nexthop
!= NULL
) {
483 Fprintf(stderr
, "%s: only one next hop gateway"
484 " allowed\n", progname
);
491 use_icmp_ts
= _B_TRUE
;
499 ts_flag
= (char)c
- '0';
514 if (optind
>= argc
) {
520 * send_reply, which sends the probe packet back to itself
521 * doesn't work with UDP
524 send_reply
= _B_FALSE
;
526 if (getenv("MACHINE_THAT_GOES_PING") != NULL
)
529 targethost
= argv
[optind
];
533 datalen
= int_arg(argv
[optind
], "data size");
536 npackets
= int_arg(argv
[optind
],
539 Fprintf(stderr
, "%s: packet count %d "
540 "out of range\n", progname
,
546 timeout
= int_arg(argv
[optind
], "timeout");
551 * Let's prepare sockaddr_in* structures, cause we might need both of
554 bzero((char *)&to
, sizeof (struct sockaddr_in
));
555 to
.sin_family
= AF_INET
;
557 bzero((char *)&to6
, sizeof (struct sockaddr_in6
));
558 to6
.sin6_family
= AF_INET6
;
559 to6
.sin6_flowinfo
= htonl((class << 20) | flowinfo
);
562 (void) sigset(SIGINT
, finish
);
564 ident
= (int)getpid() & 0xFFFF;
566 /* resolve the hostnames */
567 resolve_nodes(&ai_dst
, &ai_nexthop
, &src_addr_list
);
570 * We should make sure datalen is reasonable.
571 * IP_MAXPACKET >= IPv4/IPv6 header length +
572 * IPv4 options/IPv6 routing header length +
573 * ICMP/ICMP6/UDP header length +
577 if (family_input
== AF_INET6
||
578 (family_input
== AF_UNSPEC
&& num_v6
!= 0)) {
579 size_t exthdr_len
= 0;
582 exthdr_len
= sizeof (struct ip6_rthdr0
) +
583 2 * num_gw
* sizeof (struct in6_addr
);
584 } else if (num_gw
> 0) {
585 exthdr_len
= sizeof (struct ip6_rthdr0
) +
586 num_gw
* sizeof (struct in6_addr
);
590 * Size of ICMP6 header and UDP header are the same. Let's
593 if (datalen
> (IP_MAXPACKET
- (sizeof (struct ip6_hdr
) +
594 exthdr_len
+ ICMP6_MINLEN
))) {
596 "%s: data size too large for IPv6 packet\n",
602 if (family_input
== AF_INET
||
603 (family_input
== AF_UNSPEC
&& num_v4
!= 0)) {
608 * Includes 3 bytes code+ptr+len, the intermediate
609 * gateways, the actual and the effective target.
612 (2 * num_gw
+ 2) * sizeof (struct in_addr
);
613 } else if (num_gw
> 0) {
614 opt_len
= 3 + (num_gw
+ 1) * sizeof (struct in_addr
);
618 opt_len
= MAX_IPOPTLEN
;
619 } else if (ts_option
) {
620 if ((ts_flag
& 0x0f) <= IPOPT_TS_TSANDADDR
) {
621 opt_len
= MAX_IPOPTLEN
;
623 opt_len
+= IPOPT_MINOFF
+
624 2 * sizeof (struct ipt_ta
);
626 * Note: BSD/4.X is broken in their check so we
627 * have to bump up this number by at least one.
633 /* Round up to 4 byte boundary */
635 opt_len
= (opt_len
& ~0x3) + 4;
637 if (datalen
> (IP_MAXPACKET
- (sizeof (struct ip
) + opt_len
+
640 "%s: data size too large for IPv4 packet\n",
646 if (num_v4
== 0 && num_v6
== 0) {
650 /* setup the sockets */
652 if (!setup_socket(AF_INET6
, &send_sock6
, &recv_sock6
,
653 &if_index
, &udp_src_port6
, ai_nexthop
))
658 if (!setup_socket(AF_INET
, &send_sock
, &recv_sock
, &if_index
,
659 &udp_src_port
, ai_nexthop
))
666 * If sending back to ourself, add the mirror image of current
667 * gateways, so that the probes travel to and from the target
668 * by visiting the same gateways in reverse order.
672 mirror_gws(gw_IP_list6
, AF_INET6
);
674 mirror_gws(gw_IP_list
, AF_INET
);
676 /* We add 1 because we put the target as the middle gateway */
677 eff_num_gw
= 2 * num_gw
+ 1;
683 targetaddr_list
= build_targetaddr_list(ai_dst
, src_addr_list
);
684 current_targetaddr
= targetaddr_list
;
687 * Set the starting_seq_num for the first targetaddr.
688 * If we are sending ICMP Echo Requests, the sequence number is same as
689 * ICMP sequence number, and it starts from zero. If we are sending UDP
690 * packets, the sequence number is the destination UDP port number,
691 * which starts from dest_port. At each probe, this sequence number is
692 * incremented by one.
693 * We set the starting_seq_num for first targetaddr here. The
694 * following ones will be set by looking at where we left with the last
697 current_targetaddr
->starting_seq_num
= use_udp
? dest_port
: 0;
700 if (probe_all
|| !nflag
) {
701 Printf("PING %s: %d data bytes\n", targethost
, datalen
);
703 if (ai_dst
->ai_family
== AF_INET
) {
704 (void) inet_ntop(AF_INET
,
705 &((struct sockaddr_in
*)(void *)
706 ai_dst
->ai_addr
)->sin_addr
,
707 abuf
, sizeof (abuf
));
709 (void) inet_ntop(AF_INET6
,
710 &((struct sockaddr_in6
*)(void *)
711 ai_dst
->ai_addr
)->sin6_addr
,
712 abuf
, sizeof (abuf
));
714 Printf("PING %s (%s): %d data bytes\n",
715 targethost
, abuf
, datalen
);
719 /* Create our timer for future use */
720 if (timer_create(CLOCK_REALTIME
, NULL
, &timer
) != 0) {
721 Fprintf(stderr
, "%s: failed to create timer: %s\n",
722 progname
, strerror(errno
));
727 * Finally start up the name services warning thread.
729 if (thr_create(NULL
, 0, ns_warning_thr
, NULL
,
730 THR_DETACHED
| THR_DAEMON
, NULL
) != 0) {
731 Fprintf(stderr
, "%s: failed to create name services "
732 "thread: %s\n", progname
, strerror(errno
));
736 /* Let's get things going */
737 send_scheduled_probe();
739 /* SIGALRM is used to send the next scheduled probe */
740 (void) sigset(SIGALRM
, sigalrm_handler
);
744 * From now on, we'll always be listening to ICMP packets. As SIGALRM
745 * comes in, sigalrm_handler() will be invoked and send another
748 recv_icmp_packet(ai_dst
, recv_sock6
, recv_sock
, udp_src_port6
,
751 return (EXIT_SUCCESS
); /* should never come here */
755 * Build the target IP address list. Use command line options and
756 * name lookup results returned from name server to determine which addresses
757 * to probe, how many times, in which order.
759 static struct targetaddr
*
760 build_targetaddr_list(struct addrinfo
*ai_dst
, union any_in_addr
*src_addr_list
)
762 struct targetaddr
*head
= NULL
;
763 struct targetaddr
*targetaddr
;
764 struct targetaddr
**nextp
;
767 struct addrinfo
*aip
;
771 num_dst
= num_v4
+ num_v6
;
774 num_targetaddrs
= num_dst
;
776 for (aip
= ai_dst
, i
= 0; aip
!= NULL
; aip
= aip
->ai_next
, i
++) {
777 if (aip
->ai_family
== AF_INET
&& num_v4
!= 0) {
778 targetaddr
= create_targetaddr_item(aip
->ai_family
,
779 (union any_in_addr
*)
780 /* LINTED E_BAD_PTR_CAST_ALIGN */
781 &((struct sockaddr_in
*)
782 aip
->ai_addr
)->sin_addr
,
784 } else if (aip
->ai_family
== AF_INET6
&& num_v6
!= 0) {
785 targetaddr
= create_targetaddr_item(aip
->ai_family
,
786 (union any_in_addr
*)
787 /* LINTED E_BAD_PTR_CAST_ALIGN */
788 &((struct sockaddr_in6
*)
789 aip
->ai_addr
)->sin6_addr
,
795 nextp
= &targetaddr
->next
;
796 if (num_targetaddrs
== 1)
799 if (npackets
== 0 && stats
)
800 *nextp
= head
; /* keep going indefinitely */
806 * Given an address family, dst and src addresses, by also looking at the
807 * options provided at the command line, this function creates a targetaddr
808 * to be linked with others, forming a global targetaddr list. Each targetaddr
809 * item contains information about probes sent to a specific IP address.
811 static struct targetaddr
*
812 create_targetaddr_item(int family
, union any_in_addr
*dst_addr
,
813 union any_in_addr
*src_addr
)
815 struct targetaddr
*targetaddr
;
817 targetaddr
= (struct targetaddr
*)malloc(sizeof (struct targetaddr
));
818 if (targetaddr
== NULL
) {
819 Fprintf(stderr
, "%s: malloc %s\n", progname
, strerror(errno
));
822 targetaddr
->family
= family
;
823 targetaddr
->dst_addr
= *dst_addr
;
824 targetaddr
->src_addr
= *src_addr
;
827 * npackets is only defined if we are in stats mode.
828 * npackets determines how many probes to send to each target
829 * IP address. npackets == 0 means send only 1 and move on to
833 targetaddr
->num_probes
= npackets
;
835 targetaddr
->num_probes
= 1;
837 targetaddr
->num_probes
= timeout
;
839 targetaddr
->num_sent
= 0;
840 targetaddr
->got_reply
= _B_FALSE
;
841 targetaddr
->probing_done
= _B_FALSE
;
842 targetaddr
->starting_seq_num
= 0; /* actual value will be set later */
843 targetaddr
->next
= NULL
; /* actual value will be set later */
849 * print "unknown host" message
852 print_unknown_host_msg(const char *protocol
, const char *hostname
)
854 Fprintf(stderr
, "%s: unknown%s host %s\n", progname
, protocol
,
859 * Resolve hostnames for the target host and gateways. Also, determine source
860 * addresses to use for each target address.
863 resolve_nodes(struct addrinfo
**ai_dstp
, struct addrinfo
**ai_nexthopp
,
864 union any_in_addr
**src_addr_listp
)
866 struct addrinfo
*ai_dst
= NULL
;
867 struct addrinfo
*ai_nexthop
= NULL
;
868 struct addrinfo
*aip
= NULL
;
869 union any_in_addr
*src_addr_list
= NULL
;
870 int num_resolved_gw
= 0;
871 int num_resolved_gw6
= 0;
873 get_hostinfo(targethost
, family_input
, &ai_dst
);
874 if (ai_dst
== NULL
) {
875 print_unknown_host_msg("", targethost
);
878 if (nexthop
!= NULL
) {
879 get_hostinfo(nexthop
, family_input
, &ai_nexthop
);
880 if (ai_nexthop
== NULL
) {
881 print_unknown_host_msg("", nexthop
);
885 /* Get a count of the v4 & v6 addresses */
886 for (aip
= ai_dst
; aip
!= NULL
; aip
= aip
->ai_next
) {
887 switch (aip
->ai_family
) {
897 if (family_input
== AF_UNSPEC
&& !probe_all
) {
898 family_input
= ai_dst
->ai_family
;
901 /* resolve gateways */
903 get_gwaddrs(gw_list
, family_input
, gw_IP_list
, gw_IP_list6
,
904 &num_resolved_gw
, &num_resolved_gw6
);
906 /* we couldn't resolve a gateway as an IPv6 host */
907 if (num_resolved_gw6
!= num_gw
&& num_v6
!= 0 &&
908 (family_input
== AF_INET6
|| family_input
== AF_UNSPEC
)) {
909 print_unknown_host_msg(" IPv6",
910 gw_list
[num_resolved_gw6
]);
914 /* we couldn't resolve a gateway as an IPv4 host */
915 if (num_resolved_gw
!= num_gw
&& num_v4
!= 0 &&
916 (family_input
== AF_INET
|| family_input
== AF_UNSPEC
)) {
917 print_unknown_host_msg(" IPv4",
918 gw_list
[num_resolved_gw
]);
923 if (num_v4
== 0 && num_v6
== 0)
926 select_all_src_addrs(&src_addr_list
, ai_dst
, gw_IP_list
, gw_IP_list6
);
928 *ai_nexthopp
= ai_nexthop
;
929 *src_addr_listp
= src_addr_list
;
933 * Resolve the gateway names, splitting results into v4 and v6 lists.
934 * Gateway addresses are added to the appropriate passed-in array; the
935 * number of resolved gateways for each af is returned in resolved[6].
936 * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
937 * and resolved[6] ptrs are non-null; ignores array and counter if the
938 * address family param makes them irrelevant.
941 get_gwaddrs(char **gw_list
, int family
, union any_in_addr
*gwIPlist
,
942 union any_in_addr
*gwIPlist6
, int *resolved
, int *resolved6
)
945 boolean_t check_v4
= _B_TRUE
, check_v6
= _B_TRUE
;
946 struct addrinfo
*ai
= NULL
;
947 struct addrinfo
*aip
= NULL
;
949 *resolved
= *resolved6
= 0;
963 if (check_v4
&& num_gw
>= MAX_GWS
) {
965 Fprintf(stderr
, "%s: too many IPv4 gateways\n", progname
);
967 if (check_v6
&& num_gw
> MAX_GWS6
) {
969 Fprintf(stderr
, "%s: too many IPv6 gateways\n", progname
);
972 for (i
= 0; i
< num_gw
; i
++) {
973 if (!check_v4
&& !check_v6
)
975 get_hostinfo(gw_list
[i
], family
, &ai
);
978 if (check_v4
&& num_v4
!= 0) {
979 for (aip
= ai
; aip
!= NULL
; aip
= aip
->ai_next
) {
980 if (aip
->ai_family
== AF_INET
) {
981 /* LINTED E_BAD_PTR_CAST_ALIGN */
982 bcopy(&((struct sockaddr_in
*)
983 aip
->ai_addr
)->sin_addr
,
990 } else if (check_v4
) {
993 if (check_v6
&& num_v6
!= 0) {
994 for (aip
= ai
; aip
!= NULL
; aip
= aip
->ai_next
) {
995 if (aip
->ai_family
== AF_INET6
) {
996 /* LINTED E_BAD_PTR_CAST_ALIGN */
997 bcopy(&((struct sockaddr_in6
*)
998 aip
->ai_addr
)->sin6_addr
,
1005 } else if (check_v6
) {
1006 check_v6
= _B_FALSE
;
1013 * Given the list of gateways, extends the list with its mirror image. This is
1014 * used when -l/-S is used. The middle gateway will be the target address. We'll
1015 * leave it blank for now.
1018 mirror_gws(union any_in_addr
*gwIPlist
, int family
)
1020 int effective_num_gw
;
1023 /* We add 1 because we put the target as the middle gateway */
1024 effective_num_gw
= 2 * num_gw
+ 1;
1026 if ((family
== AF_INET
&& effective_num_gw
>= MAX_GWS
) ||
1027 (family
== AF_INET6
&& effective_num_gw
> MAX_GWS6
)) {
1028 Fprintf(stderr
, "%s: too many %s gateways\n",
1029 progname
, (family
== AF_INET
) ? "IPv4" : "IPv6");
1033 for (i
= 0; i
< num_gw
; i
++)
1034 gwIPlist
[num_gw
+ i
+ 1].addr6
= gwIPlist
[num_gw
- i
- 1].addr6
;
1038 * Given IP address or hostname, return addrinfo list.
1039 * Assumes that addrinfo ** ptr is non-null.
1042 get_hostinfo(char *host
, int family
, struct addrinfo
**aipp
)
1044 struct addrinfo hints
, *ai
;
1045 struct in6_addr addr6
;
1046 struct in_addr addr
;
1047 boolean_t broadcast
; /* is this 255.255.255.255? */
1048 char tmp_buf
[INET6_ADDRSTRLEN
];
1051 /* check if broadcast */
1052 if (strcmp(host
, "255.255.255.255") == 0)
1053 broadcast
= _B_TRUE
;
1055 broadcast
= _B_FALSE
;
1057 /* check if IPv4-mapped address or broadcast */
1058 if (((inet_pton(AF_INET6
, host
, &addr6
) > 0) &&
1059 IN6_IS_ADDR_V4MAPPED(&addr6
)) || broadcast
) {
1062 * Peel off the "mapping" stuff, leaving 32 bit IPv4
1065 IN6_V4MAPPED_TO_INADDR(&addr6
, &addr
);
1067 /* convert it back to a string */
1068 (void) inet_ntop(AF_INET
, (void *)&addr
, tmp_buf
,
1071 * Now the host is an IPv4 address.
1072 * Since it previously was a v4 mapped v6 address
1073 * we can be sure that the size of buffer 'host'
1074 * is large enough to contain the associated v4
1075 * address and so we don't need to use a strn/lcpy
1078 (void) strcpy(host
, tmp_buf
);
1081 * If it's a broadcast address, it cannot be an IPv6 address.
1082 * Also, if it's a mapped address, we convert it into IPv4
1083 * address because ping will send and receive IPv4 packets for
1084 * that address. Therefore, it's a failure case to ask
1085 * get_hostinfo() to treat a broadcast or a mapped address
1086 * as an IPv6 address.
1088 if (family
== AF_INET6
) {
1093 (void) memset(&hints
, 0, sizeof (hints
));
1094 hints
.ai_family
= family
;
1095 hints
.ai_flags
= AI_ADDRCONFIG
;
1096 rc
= getaddrinfo(host
, NULL
, &hints
, &ai
);
1098 if (rc
!= EAI_NONAME
)
1099 Fprintf(stderr
, "%s: getaddrinfo: %s\n", progname
,
1107 * For each IP address of the target host, determine a source address to use.
1110 select_all_src_addrs(union any_in_addr
**src_addr_list
, struct addrinfo
*ai
,
1111 union any_in_addr
*gwv4
, union any_in_addr
*gwv6
)
1113 union any_in_addr
*list
;
1114 struct addrinfo
*aip
;
1119 for (aip
= ai
; aip
->ai_next
!= NULL
; aip
= aip
->ai_next
)
1123 list
= calloc((size_t)num_dst
, sizeof (union any_in_addr
));
1125 Fprintf(stderr
, "%s: calloc: %s\n", progname
, strerror(errno
));
1130 * If there's a gateway, a routing header as a consequence, our kernel
1131 * picks the source address based on the first hop address, rather than
1132 * final destination address.
1135 if (ai
->ai_family
== AF_INET
)
1136 select_src_addr(gwv4
, ai
->ai_family
, &list
[0]);
1138 select_src_addr(gwv6
, ai
->ai_family
, &list
[0]);
1140 * Since the first gateway address is fixed, we'll use the same
1141 * src address for every different final destination address
1144 for (i
= 1; i
< num_dst
; i
++)
1148 * Although something like 'ping -l host' results in a routing
1149 * header, the first gateway address is the target host's
1150 * address. Therefore, as far as src address selection goes,
1151 * the result is same as having no routing header.
1153 for (i
= 0, aip
= ai
; i
< num_dst
&& aip
!= NULL
;
1154 i
++, aip
= aip
->ai_next
) {
1155 if (aip
->ai_family
== AF_INET
) {
1157 select_src_addr((union any_in_addr
*)
1158 /* LINTED E_BAD_PTR_CAST_ALIGN */
1159 &((struct sockaddr_in
*)
1160 aip
->ai_addr
)->sin_addr
,
1166 select_src_addr((union any_in_addr
*)
1167 /* LINTED E_BAD_PTR_CAST_ALIGN */
1168 &((struct sockaddr_in6
*)
1169 aip
->ai_addr
)->sin6_addr
,
1177 *src_addr_list
= list
;
1181 * For a given destination address, determine a source address to use.
1182 * Returns wildcard address if it cannot determine the source address.
1185 select_src_addr(union any_in_addr
*dst_addr
, int family
,
1186 union any_in_addr
*src_addr
)
1188 struct sockaddr
*sock
;
1189 struct sockaddr_in
*sin
= NULL
;
1190 struct sockaddr_in6
*sin6
= NULL
;
1194 sock
= (struct sockaddr
*)malloc(sizeof (struct sockaddr_in6
));
1196 Fprintf(stderr
, "%s: malloc: %s\n", progname
, strerror(errno
));
1199 (void) bzero(sock
, sizeof (struct sockaddr_in6
));
1201 if (family
== AF_INET
) {
1202 /* LINTED E_BAD_PTR_CAST_ALIGN */
1203 sin
= (struct sockaddr_in
*)sock
;
1204 sin
->sin_family
= AF_INET
;
1205 sin
->sin_addr
= dst_addr
->addr
;
1206 sin
->sin_port
= IPPORT_ECHO
; /* port shouldn't be 0 */
1207 sock_len
= sizeof (struct sockaddr_in
);
1209 /* LINTED E_BAD_PTR_CAST_ALIGN */
1210 sin6
= (struct sockaddr_in6
*)sock
;
1211 sin6
->sin6_family
= AF_INET6
;
1212 sin6
->sin6_addr
= dst_addr
->addr6
;
1213 sin6
->sin6_port
= IPPORT_ECHO
; /* port shouldn't be 0 */
1214 sock_len
= sizeof (struct sockaddr_in6
);
1217 /* open a UDP socket */
1218 if ((tmp_fd
= socket(family
, SOCK_DGRAM
, 0)) < 0) {
1219 Fprintf(stderr
, "%s: udp socket: %s\n", progname
,
1225 if (connect(tmp_fd
, sock
, sock_len
) < 0) {
1227 * If there's no route to the destination, this connect() call
1228 * fails. We just return all-zero (wildcard) as the source
1229 * address, so that user can get to see "no route to dest"
1230 * message, as it'll try to send the probe packet out and will
1231 * receive ICMP unreachable.
1233 if (family
== AF_INET
)
1234 src_addr
->addr
.s_addr
= INADDR_ANY
;
1236 src_addr
->addr6
= in6addr_any
;
1241 /* get the local sock info */
1242 if (getsockname(tmp_fd
, sock
, &sock_len
) < 0) {
1243 Fprintf(stderr
, "%s: getsockname: %s\n", progname
,
1248 if (family
== AF_INET
) {
1249 assert(sin
!= NULL
);
1250 src_addr
->addr
= sin
->sin_addr
;
1252 assert(sin6
!= NULL
);
1253 src_addr
->addr6
= sin6
->sin6_addr
;
1256 (void) close(tmp_fd
);
1261 * Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
1265 set_nexthop(int family
, struct addrinfo
*ai_nexthop
, int sock
)
1267 if (family
== AF_INET
) {
1270 /* LINTED E_BAD_PTR_CAST_ALIGN */
1271 nh
= ((struct sockaddr_in
*)ai_nexthop
->
1272 ai_addr
)->sin_addr
.s_addr
;
1274 /* now we need the sys_ip_config privilege */
1275 (void) __priv_bracket(PRIV_ON
);
1276 if (setsockopt(sock
, IPPROTO_IP
, IP_NEXTHOP
,
1277 &nh
, sizeof (ipaddr_t
)) < 0) {
1279 Fprintf(stderr
, "%s: Insufficient privilege "
1280 "to specify IPv4 nexthop router.\n",
1283 Fprintf(stderr
, "%s: setsockopt %s\n",
1284 progname
, strerror(errno
));
1287 (void) __priv_bracket(PRIV_OFF
);
1288 /* revert to non-privileged user */
1290 struct sockaddr_in6
*nh
;
1292 /* LINTED E_BAD_PTR_CAST_ALIGN */
1293 nh
= (struct sockaddr_in6
*)ai_nexthop
->
1296 if (setsockopt(sock
, IPPROTO_IPV6
, IPV6_NEXTHOP
,
1297 nh
, sizeof (struct sockaddr_in6
)) < 0) {
1298 Fprintf(stderr
, "%s: setsockopt %s\n",
1299 progname
, strerror(errno
));
1306 * Setup the socket for the given address family.
1307 * Returns _B_TRUE on success, _B_FALSE on failure. Failure is the case when no
1308 * interface can be found, or the specified interface (-i) is not found. On
1309 * library call failures, it exit()s.
1312 setup_socket(int family
, int *send_sockp
, int *recv_sockp
, int *if_index
,
1313 ushort_t
*udp_src_port
, struct addrinfo
*ai_nexthop
)
1317 struct sockaddr_in6 sin6
;
1318 struct sockaddr_in sin
;
1319 struct sockaddr
*sp
;
1320 struct ipsec_req req
;
1326 /* now we need the net_icmpaccess privilege */
1327 (void) __priv_bracket(PRIV_ON
);
1329 recv_sock
= socket(family
, SOCK_RAW
,
1330 (family
== AF_INET
) ? IPPROTO_ICMP
: IPPROTO_ICMPV6
);
1332 if (recv_sock
< 0) {
1333 Fprintf(stderr
, "%s: socket %s\n", progname
, strerror(errno
));
1337 /* revert to non-privileged user after opening sockets */
1338 (void) __priv_bracket(PRIV_OFF
);
1341 (void) memset(&req
, 0, sizeof (req
));
1342 req
.ipsr_ah_req
= IPSEC_PREF_NEVER
;
1343 req
.ipsr_esp_req
= IPSEC_PREF_NEVER
;
1345 if (setsockopt(recv_sock
, (family
== AF_INET
) ? IPPROTO_IP
:
1346 IPPROTO_IPV6
, IP_SEC_OPT
, &req
, sizeof (req
)) < 0) {
1348 case EPROTONOSUPPORT
:
1350 * No IPsec subsystem or policy loaded.
1351 * Bypass implicitly allowed.
1355 Fprintf(stderr
, "%s: Insufficient privilege "
1356 "to bypass IPsec policy.\n", progname
);
1360 Fprintf(stderr
, "%s: setsockopt %s\n", progname
,
1369 * We always receive on raw icmp socket. But the sending socket can be
1370 * raw icmp or udp, depending on the use of -U flag.
1373 send_sock
= socket(family
, SOCK_DGRAM
, IPPROTO_UDP
);
1374 if (send_sock
< 0) {
1375 Fprintf(stderr
, "%s: socket %s\n", progname
,
1381 if (setsockopt(send_sock
, (family
== AF_INET
) ?
1382 IPPROTO_IP
: IPPROTO_IPV6
, IP_SEC_OPT
, &req
,
1383 sizeof (req
)) < 0) {
1385 case EPROTONOSUPPORT
:
1387 * No IPsec subsystem or policy loaded.
1388 * Bypass implicitly allowed.
1392 Fprintf(stderr
, "%s: Insufficient "
1393 "privilege to bypass IPsec "
1394 "policy.\n", progname
);
1398 Fprintf(stderr
, "%s: setsockopt %s\n",
1399 progname
, strerror(errno
));
1407 * In order to distinguish replies to our UDP probes from
1408 * other pings', we need to know our source port number.
1410 if (family
== AF_INET
) {
1411 sp
= (struct sockaddr
*)&sin
;
1412 slen
= sizeof (sin
);
1414 sp
= (struct sockaddr
*)&sin6
;
1415 slen
= sizeof (sin6
);
1418 sp
->sa_family
= family
;
1420 /* Let's bind() send_sock to wildcard address and port */
1421 if (bind(send_sock
, sp
, slen
) < 0) {
1422 Fprintf(stderr
, "%s: bind %s\n", progname
,
1427 /* .... and see what port kernel picked for us */
1428 if (getsockname(send_sock
, sp
, &slen
) < 0) {
1429 Fprintf(stderr
, "%s: getsockname %s\n", progname
,
1433 *udp_src_port
= (family
== AF_INET
) ? sin
.sin_port
:
1436 send_sock
= recv_sock
;
1439 if (nexthop
!= NULL
)
1440 set_nexthop(family
, ai_nexthop
, send_sock
);
1443 if (int_op
< datalen
)
1445 if (setsockopt(recv_sock
, SOL_SOCKET
, SO_RCVBUF
, (char *)&int_op
,
1446 sizeof (int_op
)) == -1) {
1447 Fprintf(stderr
, "%s: setsockopt SO_RCVBUF %s\n", progname
,
1452 if (setsockopt(send_sock
, SOL_SOCKET
, SO_SNDBUF
, (char *)&int_op
,
1453 sizeof (int_op
)) == -1) {
1454 Fprintf(stderr
, "%s: setsockopt SO_SNDBUF %s\n", progname
,
1459 if (options
& SO_DEBUG
) {
1460 if (setsockopt(send_sock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
1461 sizeof (on
)) == -1) {
1462 Fprintf(stderr
, "%s: setsockopt SO_DEBUG %s\n",
1463 progname
, strerror(errno
));
1468 if (options
& SO_DONTROUTE
) {
1469 if (setsockopt(send_sock
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
1470 sizeof (on
)) == -1) {
1471 Fprintf(stderr
, "%s: setsockopt SO_DONTROUTE %s\n",
1472 progname
, strerror(errno
));
1477 if (moptions
& MULTICAST_NOLOOP
) {
1478 if (family
== AF_INET
) {
1479 char_op
= 0; /* used to turn off option */
1481 if (setsockopt(send_sock
, IPPROTO_IP
, IP_MULTICAST_LOOP
,
1482 (char *)&char_op
, sizeof (char_op
)) == -1) {
1483 Fprintf(stderr
, "%s: setsockopt "
1484 "IP_MULTICAST_NOLOOP %s\n", progname
,
1489 int_op
= 0; /* used to turn off option */
1491 if (setsockopt(send_sock
, IPPROTO_IPV6
,
1492 IPV6_MULTICAST_LOOP
, (char *)&int_op
,
1493 sizeof (int_op
)) == -1) {
1494 Fprintf(stderr
, "%s: setsockopt "
1495 "IPV6_MULTICAST_NOLOOP %s\n", progname
,
1502 if (moptions
& MULTICAST_TTL
) {
1505 /* Applies to unicast and multicast. */
1506 if (family
== AF_INET
) {
1507 if (setsockopt(send_sock
, IPPROTO_IP
, IP_MULTICAST_TTL
,
1508 (char *)&char_op
, sizeof (char)) == -1) {
1509 Fprintf(stderr
, "%s: setsockopt "
1510 "IP_MULTICAST_TTL %s\n", progname
,
1514 if (setsockopt(send_sock
, IPPROTO_IP
, IP_TTL
,
1515 (char *)&hoplimit
, sizeof (hoplimit
)) == -1) {
1516 Fprintf(stderr
, "%s: setsockopt IP_TTL %s\n",
1517 progname
, strerror(errno
));
1522 * AF_INET6 case is handled in set_ancillary_data() function.
1523 * This is because when ancillary data is used (for routing
1524 * header and outgoing interface index), the hoplimit set using
1525 * setsockopt() is ignored.
1530 * did the user specify an interface?
1531 * Applies to unicast, broadcast and multicast.
1533 if (moptions
& MULTICAST_IF
) {
1534 struct ifaddrlist
*al
= NULL
; /* interface list */
1535 struct ifaddrlist
*my_if
;
1536 char errbuf
[ERRBUFSIZE
];
1538 int num_src_ifs
; /* exclude down and loopback */
1541 /* pull out the interface list */
1542 num_ifs
= ifaddrlist(&al
, family
, LIFC_UNDER_IPMP
, errbuf
);
1543 if (num_ifs
== -1) {
1544 Fprintf(stderr
, "%s: %s\n", progname
, errbuf
);
1548 /* filter out down and loopback interfaces */
1550 for (i
= 0; i
< num_ifs
; i
++) {
1551 if (!(al
[i
].flags
& IFF_LOOPBACK
) &&
1552 (al
[i
].flags
& IFF_UP
))
1556 if (num_src_ifs
== 0) {
1557 Fprintf(stderr
, "%s: can't find any %s interface\n",
1558 progname
, (family
== AF_INET
) ? "IPv4" : "IPv6");
1560 return (_B_FALSE
); /* failure */
1563 /* locate the specified interface */
1564 my_if
= find_if(al
, num_ifs
);
1565 if (my_if
== NULL
) {
1566 Fprintf(stderr
, "%s: %s is an invalid %s interface\n",
1567 progname
, out_if
.str
,
1568 (family
== AF_INET
) ? "IPv4" : "IPv6");
1573 if (family
== AF_INET
) {
1574 struct in_pktinfo pktinfo
;
1576 if (setsockopt(send_sock
, IPPROTO_IP
, IP_MULTICAST_IF
,
1577 (char *)&my_if
->addr
.addr
,
1578 sizeof (struct in_addr
)) == -1) {
1579 Fprintf(stderr
, "%s: setsockopt "
1580 "IP_MULTICAST_IF %s\n", progname
,
1584 bzero(&pktinfo
, sizeof (pktinfo
));
1585 pktinfo
.ipi_ifindex
= my_if
->index
;
1586 if (setsockopt(send_sock
, IPPROTO_IP
, IP_PKTINFO
,
1587 (char *)&pktinfo
, sizeof (pktinfo
)) == -1) {
1588 Fprintf(stderr
, "%s: setsockopt "
1589 "IP_PKTINFO %s\n", progname
,
1595 * the outgoing interface is set in set_ancillary_data()
1598 *if_index
= my_if
->index
;
1604 if (settos
&& family
== AF_INET
) {
1606 if (setsockopt(send_sock
, IPPROTO_IP
, IP_TOS
, (char *)&int_op
,
1607 sizeof (int_op
)) == -1) {
1608 Fprintf(stderr
, "%s: setsockopt IP_TOS %s\n",
1609 progname
, strerror(errno
));
1614 /* We enable or disable to not depend on the kernel default */
1615 if (family
== AF_INET
) {
1616 if (setsockopt(send_sock
, IPPROTO_IP
, IP_DONTFRAG
,
1617 (char *)&dontfrag
, sizeof (dontfrag
)) == -1) {
1618 Fprintf(stderr
, "%s: setsockopt IP_DONTFRAG %s\n",
1619 progname
, strerror(errno
));
1623 if (setsockopt(send_sock
, IPPROTO_IPV6
, IPV6_DONTFRAG
,
1624 (char *)&dontfrag
, sizeof (dontfrag
)) == -1) {
1625 Fprintf(stderr
, "%s: setsockopt IPV6_DONTFRAG %s\n",
1626 progname
, strerror(errno
));
1631 /* receiving IPv6 extension headers in verbose mode */
1632 if (verbose
&& family
== AF_INET6
) {
1633 if (setsockopt(recv_sock
, IPPROTO_IPV6
, IPV6_RECVHOPOPTS
,
1634 (char *)&on
, sizeof (on
)) == -1) {
1635 Fprintf(stderr
, "%s: setsockopt IPV6_RECVHOPOPTS %s\n",
1636 progname
, strerror(errno
));
1640 if (setsockopt(recv_sock
, IPPROTO_IPV6
, IPV6_RECVDSTOPTS
,
1641 (char *)&on
, sizeof (on
)) == -1) {
1642 Fprintf(stderr
, "%s: setsockopt IPV6_RECVDSTOPTS %s\n",
1643 progname
, strerror(errno
));
1647 if (setsockopt(recv_sock
, IPPROTO_IPV6
, IPV6_RECVRTHDR
,
1648 (char *)&on
, sizeof (on
)) == -1) {
1649 Fprintf(stderr
, "%s: setsockopt IPV6_RECVRTHDR %s\n",
1650 progname
, strerror(errno
));
1655 /* Ensure that timestamping is requested on the receive socket */
1656 if (setsockopt(recv_sock
, SOL_SOCKET
, SO_TIMESTAMP
,
1657 &on
, sizeof (on
)) == -1) {
1658 Fprintf(stderr
, "%s: warning: timing accuracy diminished -- "
1659 "setsockopt SO_TIMESTAMP failed %s", progname
,
1663 *send_sockp
= send_sock
;
1664 *recv_sockp
= recv_sock
;
1671 * Pull out the record containing all the info about the interface specified by
1672 * `out_if'. Skips interfaces which are down or loopback.
1674 static struct ifaddrlist
*
1675 find_if(struct ifaddrlist
*al
, int num_ifs
)
1677 static struct ifaddrlist tmp_if
;
1684 while (i
< num_ifs
&& !found
) {
1687 /* skip down or loopback interfaces */
1688 if ((tmp_if
.flags
& IFF_LOOPBACK
) || !(tmp_if
.flags
& IFF_UP
)) {
1693 /* the type of interface id is variable */
1694 switch (out_if
.id_type
) {
1696 if (out_if
.id
.index
== tmp_if
.index
)
1701 if (strcmp(out_if
.id
.name
, tmp_if
.device
) == 0)
1706 if (out_if
.id
.addr
.addr
.s_addr
==
1707 tmp_if
.addr
.addr
.s_addr
) {
1713 if (IN6_ARE_ADDR_EQUAL(&out_if
.id
.addr
.addr6
,
1714 &tmp_if
.addr
.addr6
)) {
1733 * Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
1734 * send_scheduled_probe() to send next probe.
1737 sigalrm_handler(void)
1740 * If we've been told that we're done, the timer should be cancelled
1741 * and not rescheduled, just return.
1743 if (timer_done
== _B_TRUE
)
1747 * Guard against denial-of-service attacks. Make sure ping doesn't send
1748 * probes for every SIGALRM it receives in the case of errant SIGALRMs.
1749 * ping will ignore those which are received too soon (the smaller of
1750 * 0.5 sec and the ping interval, if in effect) after it sent the last
1751 * probe. We use gethrtime() instead of gettimeofday() because the
1752 * latter is not linear and is prone to resetting or drifting.
1754 if ((gethrtime() - t_last_probe_sent
) < mintime
) {
1757 send_scheduled_probe();
1762 * Schedule next SIGALRM.
1765 schedule_sigalrm(void)
1768 struct itimerspec it
;
1770 bzero(&it
, sizeof (struct itimerspec
));
1771 if (npackets
== 0 ||
1772 current_targetaddr
->num_sent
< current_targetaddr
->num_probes
) {
1775 if (current_targetaddr
->got_reply
) {
1776 waittime
= 2 * tmax
/ MICROSEC
;
1780 waittime
= MAX_WAIT
;
1782 it
.it_value
.tv_sec
= waittime
;
1785 if (timer_settime(timer
, TIMER_RELTIME
, &it
, NULL
) != 0) {
1786 Fprintf(stderr
, "%s: unexpected error updating time: %s\n",
1787 progname
, strerror(errno
));
1793 * Called by sigalrm_handler(), check_reply() or check_reply6(),
1794 * send_scheduled_probe() looks at the current_targetaddr and determines what
1795 * should be sent next and calls pinger().
1798 send_scheduled_probe()
1800 static struct msghdr msg6
;
1801 static boolean_t first_probe
= _B_TRUE
;
1802 char tmp_buf
[INET6_ADDRSTRLEN
];
1805 * We are about to move to next targetaddr if it's either we sent
1806 * all the probes, or somebody set the probing_done flag to
1807 * _B_TRUE prompting us to move on.
1809 if (current_targetaddr
->num_sent
== current_targetaddr
->num_probes
||
1810 current_targetaddr
->probing_done
) {
1812 * is this a dead target?
1814 if (!stats
&& !current_targetaddr
->got_reply
) {
1816 Printf("no answer from %s\n", targethost
);
1818 Printf("no answer from %s(%s)\n", targethost
,
1819 inet_ntop(current_targetaddr
->family
,
1820 ¤t_targetaddr
->dst_addr
,
1821 tmp_buf
, sizeof (tmp_buf
)));
1825 * Before we move onto next item, let's do some clean up.
1827 current_targetaddr
->got_reply
= _B_FALSE
;
1828 current_targetaddr
->probing_done
= _B_FALSE
;
1830 * If this is probe-all without stats mode, then we need to
1831 * preserve this count. This is needed when we try to map an
1832 * icmp_seq to IP address. Otherwise, clear it.
1834 if (stats
|| !probe_all
)
1835 current_targetaddr
->num_sent
= 0;
1836 nreceived_last_target
= 0;
1838 current_targetaddr
= current_targetaddr
->next
;
1841 * Did we reach the end of road?
1843 if (current_targetaddr
== NULL
) {
1844 timer_done
= _B_TRUE
;
1853 * We use starting_seq_num for authenticating replies.
1854 * Each time we move to a new targetaddr, which has
1855 * a different target IP address, we update this field.
1857 current_targetaddr
->starting_seq_num
= use_udp
?
1858 dest_port
: (ntransmitted
% (MAX_ICMP_SEQ
+ 1));
1862 if (current_targetaddr
->family
== AF_INET6
) {
1864 /* sending back to ourself */
1865 to6
.sin6_addr
= current_targetaddr
->src_addr
.addr6
;
1867 to6
.sin6_addr
= current_targetaddr
->dst_addr
.addr6
;
1870 * Setting the ancillary data once is enough, if we are
1871 * not using source routing through target (-l/-S). In
1872 * case -l/-S used, the middle gateway will be the
1873 * IP address of the source, which can be different
1874 * for each target IP.
1877 (send_reply
&& current_targetaddr
->num_sent
== 0)) {
1879 /* target is the middle gateway now */
1880 gw_IP_list6
[num_gw
].addr6
=
1881 current_targetaddr
->dst_addr
.addr6
;
1883 set_ancillary_data(&msg6
, hoplimit
, gw_IP_list6
,
1884 eff_num_gw
, if_index
);
1885 first_probe
= _B_FALSE
;
1887 pinger(send_sock6
, (struct sockaddr
*)&to6
, &msg6
, AF_INET6
);
1889 to
.sin_addr
= current_targetaddr
->dst_addr
.addr
;
1891 * Set IPv4 options when sending the first probe to a target
1892 * IP address. Some options change when the target address
1895 if (current_targetaddr
->num_sent
== 0) {
1896 if (eff_num_gw
> 0) {
1897 gw_IP_list
[num_gw
].addr
=
1898 current_targetaddr
->dst_addr
.addr
;
1900 * If send_reply, the target becomes the
1901 * middle gateway, sender becomes the last
1905 gw_IP_list
[eff_num_gw
].addr
=
1906 current_targetaddr
->src_addr
.addr
;
1910 * In IPv4, if source routing is used, the target
1911 * address shows up as the last gateway, hence +1.
1913 set_IPv4_options(send_sock
, gw_IP_list
,
1914 (eff_num_gw
> 0) ? eff_num_gw
+ 1 : 0,
1915 ¤t_targetaddr
->src_addr
.addr
, &to
.sin_addr
);
1917 pinger(send_sock
, (struct sockaddr
*)&to
, NULL
, AF_INET
);
1920 current_targetaddr
->num_sent
++;
1924 * recv_icmp_packet()'s job is to listen to icmp packets and filter out
1925 * those ping is interested in.
1928 recv_icmp_packet(struct addrinfo
*ai_dst
, int recv_sock6
, int recv_sock
,
1929 ushort_t udp_src_port6
, ushort_t udp_src_port
)
1931 struct msghdr in_msg
;
1933 struct sockaddr_in6 from6
;
1937 boolean_t always_true
= _B_TRUE
; /* lint doesn't like while(_B_TRUE) */
1939 while (always_true
) {
1940 (void) FD_ZERO(&fds
);
1941 if (recv_sock6
!= -1)
1942 FD_SET(recv_sock6
, &fds
);
1943 if (recv_sock
!= -1)
1944 FD_SET(recv_sock
, &fds
);
1946 result
= select(MAX(recv_sock6
, recv_sock
) + 1, &fds
,
1947 (fd_set
*)NULL
, (fd_set
*)NULL
, NULL
);
1949 if (errno
== EINTR
) {
1952 Fprintf(stderr
, "%s: select %s\n", progname
,
1956 } else if (result
> 0) {
1957 in_msg
.msg_name
= &from6
;
1958 in_msg
.msg_namelen
= sizeof (from6
);
1959 iov
.iov_base
= in_pkt
;
1960 iov
.iov_len
= sizeof (in_pkt
);
1961 in_msg
.msg_iov
= &iov
;
1962 in_msg
.msg_iovlen
= 1;
1963 in_msg
.msg_control
= ancillary_data
;
1964 in_msg
.msg_controllen
= sizeof (ancillary_data
);
1966 /* Do we have an ICMP6 packet waiting? */
1967 if ((recv_sock6
!= -1) &&
1968 (FD_ISSET(recv_sock6
, &fds
))) {
1969 cc
= recvmsg(recv_sock6
, &in_msg
, 0);
1971 if (errno
!= EINTR
) {
1974 progname
, strerror(errno
));
1977 } else if (cc
> 0) {
1978 check_reply6(ai_dst
, &in_msg
, cc
,
1982 /* Do we have an ICMP packet waiting? */
1983 if ((recv_sock
!= -1) && (FD_ISSET(recv_sock
, &fds
))) {
1984 cc
= recvmsg(recv_sock
, &in_msg
, 0);
1986 if (errno
!= EINTR
) {
1989 progname
, strerror(errno
));
1993 check_reply(ai_dst
, &in_msg
, cc
,
1999 * If we were probing last IP address of the target host and
2000 * received a reply for each probe sent to this address,
2003 if ((npackets
> 0) && (current_targetaddr
->next
== NULL
) &&
2004 (nreceived_last_target
== npackets
)) {
2005 timer_done
= _B_TRUE
;
2008 } /* infinite loop */
2012 * Given a host (with possibly multiple IP addresses) and an IP address, this
2013 * function determines if this IP address is one of the host's addresses to
2014 * which we're sending probes. Used to determine if we are interested in a
2018 is_a_target(struct addrinfo
*ai
, union any_in_addr
*addr
)
2022 struct addrinfo
*aip
;
2026 num_addrs
= num_v4
+ num_v6
;
2029 for (i
= 0; i
< num_addrs
&& aip
!= NULL
; i
++) {
2030 if (aip
->ai_family
== AF_INET6
) {
2031 /* LINTED E_BAD_PTR_CAST_ALIGN */
2032 if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6
*)
2033 aip
->ai_addr
)->sin6_addr
, &addr
->addr6
))
2036 /* LINTED E_BAD_PTR_CAST_ALIGN */
2037 if (((struct sockaddr_in
*)
2038 aip
->ai_addr
)->sin_addr
.s_addr
== addr
->addr
.s_addr
)
2047 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
2048 * will be added on by the kernel. The ID field is our UNIX process ID,
2049 * and the sequence number is an ascending integer. The first 8 bytes
2050 * of the data portion are used to hold a UNIX "timeval" struct in network
2051 * byte-order, to compute the round-trip time.
2054 pinger(int send_sock
, struct sockaddr
*whereto
, struct msghdr
*msg6
,
2057 static uint64_t out_pkt_buf
[(IP_MAXPACKET
+ 1) / 8];
2058 uchar_t
*out_pkt
= (uchar_t
*)&out_pkt_buf
;
2059 /* LINTED E_BAD_PTR_CAST_ALIGN */
2060 struct icmp
*icp
= (struct icmp
*)out_pkt
;
2061 /* LINTED E_BAD_PTR_CAST_ALIGN */
2062 struct sockaddr_in6
*to6
= (struct sockaddr_in6
*)whereto
;
2063 /* LINTED E_BAD_PTR_CAST_ALIGN */
2064 struct sockaddr_in
*to
= (struct sockaddr_in
*)whereto
;
2066 struct timeval t_snd
;
2077 /* LINTED E_BAD_PTR_CAST_ALIGN */
2078 tp
= (struct timeval
*)out_pkt
;
2079 datap
= &out_pkt
[sizeof (struct timeval
)];
2082 * This sets the port whether we are handling a v4 or v6
2083 * sockaddr structure.
2085 to
->sin_port
= htons(dest_port
);
2087 dest_port
= (dest_port
+ 1) % (MAX_PORT
+ 1);
2089 } else { /* using ICMP */
2090 cc
= datalen
+ ICMP_MINLEN
;
2092 if (family
== AF_INET6
) {
2093 icp
->icmp_type
= send_reply
?
2094 ICMP6_ECHO_REPLY
: ICMP6_ECHO_REQUEST
;
2095 } else if (use_icmp_ts
) { /* family is AF_INET */
2096 icp
->icmp_type
= send_reply
?
2097 ICMP_TSTAMPREPLY
: ICMP_TSTAMP
;
2099 icp
->icmp_type
= send_reply
?
2100 ICMP_ECHOREPLY
: ICMP_ECHO
;
2104 icp
->icmp_cksum
= 0;
2105 icp
->icmp_seq
= htons(ntransmitted
++ % (MAX_ICMP_SEQ
+ 1));
2106 if (icp
->icmp_seq
== 0)
2108 icp
->icmp_id
= htons(ident
); /* ID */
2110 /* LINTED E_BAD_PTR_CAST_ALIGN */
2111 tp
= (struct timeval
*)&out_pkt
[ICMP_MINLEN
];
2112 datap
= &out_pkt
[ICMP_MINLEN
+ sizeof (struct timeval
)];
2115 start
= sizeof (struct timeval
); /* skip for time */
2117 (void) gettimeofday(&t_snd
, NULL
);
2119 /* if packet is big enough to store timeval OR ... */
2120 if ((datalen
>= sizeof (struct timeval
)) ||
2121 (family
== AF_INET
&& use_icmp_ts
))
2124 if (family
== AF_INET
&& use_icmp_ts
) {
2125 start
= sizeof (struct id_ts
); /* skip for ICMP timestamps */
2126 /* Number of milliseconds since midnight */
2127 icp
->icmp_otime
= htonl((tp
->tv_sec
% (24*60*60)) * 1000 +
2128 tp
->tv_usec
/ 1000);
2131 for (i
= start
; i
< datalen
; i
++)
2134 if (family
== AF_INET
) {
2136 icp
->icmp_cksum
= in_cksum((ushort_t
*)icp
, cc
);
2138 i
= sendto(send_sock
, (char *)out_pkt
, cc
, 0, whereto
,
2139 sizeof (struct sockaddr_in
));
2142 * Fill in the rest of the msghdr structure. msg_control is set
2143 * in set_ancillary_data().
2145 msg6
->msg_name
= to6
;
2146 msg6
->msg_namelen
= sizeof (struct sockaddr_in6
);
2148 iov
.iov_base
= out_pkt
;
2151 msg6
->msg_iov
= &iov
;
2152 msg6
->msg_iovlen
= 1;
2154 i
= sendmsg(send_sock
, msg6
, 0);
2157 /* This is a more precise time (right after we send the packet) */
2158 t_last_probe_sent
= gethrtime();
2160 if (i
< 0 || i
!= cc
) {
2162 Fprintf(stderr
, "%s: sendto %s\n", progname
,
2167 Printf("ping: wrote %s %d chars, ret=%d\n",
2169 (void) fflush(stdout
);
2174 * Return a hostname for the given IP address.
2177 pr_name(char *addr
, int family
)
2179 struct sockaddr_in sin
;
2180 struct sockaddr_in6 sin6
;
2181 struct sockaddr
*sa
;
2182 static struct in6_addr prev_addr
= IN6ADDR_ANY_INIT
;
2184 char abuf
[INET6_ADDRSTRLEN
];
2185 static char buf
[NI_MAXHOST
+ INET6_ADDRSTRLEN
+ 3];
2186 uint_t slen
, alen
, hlen
;
2190 (void) memset(&sin
, 0, sizeof (sin
));
2191 slen
= sizeof (struct sockaddr_in
);
2192 alen
= sizeof (struct in_addr
);
2193 /* LINTED E_BAD_PTR_CAST_ALIGN */
2194 sin
.sin_addr
= *(struct in_addr
*)addr
;
2196 sa
= (struct sockaddr
*)&sin
;
2199 (void) memset(&sin6
, 0, sizeof (sin6
));
2200 slen
= sizeof (struct sockaddr_in6
);
2201 alen
= sizeof (struct in6_addr
);
2202 /* LINTED E_BAD_PTR_CAST_ALIGN */
2203 sin6
.sin6_addr
= *(struct in6_addr
*)addr
;
2205 sa
= (struct sockaddr
*)&sin6
;
2208 (void) snprintf(buf
, sizeof (buf
), "<invalid address family>");
2211 sa
->sa_family
= family
;
2213 /* compare with the buffered (previous) lookup */
2214 if (memcmp(addr
, &prev_addr
, alen
) != 0) {
2215 int flags
= (nflag
) ? NI_NUMERICHOST
: NI_NAMEREQD
;
2216 mutex_enter(&ns_lock
);
2217 ns_active
= _B_TRUE
;
2218 ns_starttime
= gethrtime();
2219 mutex_exit(&ns_lock
);
2220 if (getnameinfo(sa
, slen
, buf
, sizeof (buf
),
2221 NULL
, 0, flags
) != 0) {
2222 /* getnameinfo() failed; return just the address */
2223 if (inet_ntop(family
, (const void*)addr
,
2224 buf
, sizeof (buf
)) == NULL
)
2226 } else if (!nflag
) {
2227 /* append numeric address to hostname string */
2229 cp
= (char *)(buf
+ hlen
);
2230 (void) snprintf(cp
, sizeof (buf
) - hlen
, " (%s)",
2231 inet_ntop(family
, (const void *)addr
, abuf
,
2234 mutex_enter(&ns_lock
);
2235 ns_active
= _B_FALSE
;
2236 mutex_exit(&ns_lock
);
2238 /* LINTED E_BAD_PTR_CAST_ALIGN */
2239 prev_addr
= *(struct in6_addr
*)addr
;
2245 * Return the protocol string, given its protocol number.
2248 pr_protocol(int prot
)
2250 static char buf
[20];
2253 case IPPROTO_ICMPV6
:
2254 (void) strlcpy(buf
, "icmp6", sizeof (buf
));
2258 (void) strlcpy(buf
, "icmp", sizeof (buf
));
2262 (void) strlcpy(buf
, "tcp", sizeof (buf
));
2266 (void) strlcpy(buf
, "udp", sizeof (buf
));
2270 (void) snprintf(buf
, sizeof (buf
), "prot %d", prot
);
2278 * Checks if value is between seq_begin and seq_begin+seq_len. Note that
2279 * sequence numbers wrap around after MAX_ICMP_SEQ (== MAX_PORT).
2282 seq_match(ushort_t seq_begin
, int seq_len
, ushort_t value
)
2285 * If seq_len is too big, like some value greater than MAX_ICMP_SEQ/2,
2286 * truncate it down to MAX_ICMP_SEQ/2. We are not going to accept any
2287 * reply which come 83hr later!
2289 if (seq_len
> MAX_ICMP_SEQ
/ 2) {
2290 seq_begin
= (seq_begin
+ seq_len
- MAX_ICMP_SEQ
/ 2) %
2292 seq_len
= MAX_ICMP_SEQ
/ 2;
2295 if (PINGSEQ_LEQ(seq_begin
, value
) &&
2296 PINGSEQ_LEQ(value
, (seq_begin
+ seq_len
- 1) % (MAX_ICMP_SEQ
+ 1)))
2303 * For a given icmp_seq, find which destination address we must have sent this
2307 find_dstaddr(ushort_t icmpseq
, union any_in_addr
*ipaddr
)
2309 struct targetaddr
*target
= targetaddr_list
;
2311 int targetaddr_index
;
2315 ipaddr
->addr6
= in6addr_any
;
2318 * If this is probe_all and not stats, then the number of probes sent to
2319 * each IP address may be different (remember, we stop sending to one IP
2320 * address as soon as it replies). They are stored in target->num_sent
2321 * field. Since we don't wrap around the list (!stats), they are also
2324 if (probe_all
&& !stats
) {
2326 if (seq_match(target
->starting_seq_num
,
2327 target
->num_sent
, icmpseq
)) {
2328 ipaddr
->addr6
= target
->dst_addr
.addr6
;
2330 * We are not immediately return()ing here.
2331 * Because of wrapping, we might find another
2332 * match later, which is more likely to be the
2336 target
= target
->next
;
2337 } while (target
!= NULL
);
2340 * Find the absolute (non-wrapped) seq number within the last
2343 if (icmpseq
< (ntransmitted
% (MAX_ICMP_SEQ
+ 1))) {
2344 real_seq
= num_wraps
* (MAX_ICMP_SEQ
+ 1) + icmpseq
;
2346 real_seq
= (num_wraps
- 1) * (MAX_ICMP_SEQ
+ 1) +
2350 /* Make sure it's non-negative */
2353 real_npackets
= (npackets
== 0) ? 1 : npackets
;
2356 * We sent npackets many packets to each of those
2357 * num_targetaddrs many IP addresses.
2360 (real_seq
% (num_targetaddrs
* real_npackets
)) /
2362 for (i
= 0; i
< targetaddr_index
; i
++)
2363 target
= target
->next
;
2364 ipaddr
->addr6
= target
->dst_addr
.addr6
;
2369 * Checksum routine for Internet Protocol family headers (C Version)
2372 in_cksum(ushort_t
*addr
, int len
)
2377 ushort_t odd_byte
= 0;
2381 * Our algorithm is simple, using a 32 bit accumulator (sum),
2382 * we add sequential 16 bit words to it, and at the end, fold
2383 * back all the carry bits from the top 16 bits into the lower
2391 /* mop up an odd byte, if necessary */
2393 *(uchar_t
*)(&odd_byte
) = *(uchar_t
*)w
;
2398 * add back carry outs from top 16 bits to low 16 bits
2400 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
2401 sum
+= (sum
>> 16); /* add carry */
2402 answer
= ~sum
; /* truncate to 16 bits */
2407 * Subtract 2 timeval structs: out = out - in.
2408 * Out is assumed to be >= in.
2411 tvsub(struct timeval
*out
, struct timeval
*in
)
2413 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
2415 out
->tv_usec
+= 1000000;
2417 out
->tv_sec
-= in
->tv_sec
;
2421 * Print out statistics, and give up.
2422 * Heavily buffered STDIO is used here, so that all the statistics
2423 * will be written with 1 sys-write call. This is nice when more
2424 * than one copy of the program is running on a terminal; it prevents
2425 * the statistics output from becoming intermingled.
2430 Printf("\n----%s PING Statistics----\n", targethost
);
2431 Printf("%d packets transmitted, ", ntransmitted
);
2432 Printf("%d packets received, ", nreceived
);
2434 if (nreceived
<= ntransmitted
) {
2435 Printf("%d%% packet loss",
2436 (int)(((ntransmitted
-nreceived
)*100) /
2439 Printf("%.2f times amplification",
2440 (double)nreceived
/ (double)ntransmitted
);
2443 (void) putchar('\n');
2445 /* if packet is big enough to store timeval AND ... */
2446 if ((datalen
>= sizeof (struct timeval
)) && (nreceived
> 0)) {
2447 double mean
= (double)tsum
/ nreceived
;
2448 double smean
= (double)tsum2
/ nreceived
;
2450 sqrt(((smean
- mean
*mean
) * nreceived
) / (nreceived
-1));
2452 Printf("round-trip (ms) min/avg/max/stddev = "
2453 TIMEFORMAT
"/" TIMEFORMAT
"/"
2454 TIMEFORMAT
"/" TIMEFORMAT
"\n",
2455 (double)tmin
/ 1000, mean
/ 1000,
2456 (double)tmax
/ 1000, sd
/ 1000);
2458 (void) fflush(stdout
);
2460 exit(is_alive
? EXIT_SUCCESS
: EXIT_FAILURE
);
2464 * print the usage line
2467 usage(char *cmdname
)
2469 Fprintf(stderr
, "usage: %s host [timeout]\n", cmdname
);
2472 "usage: %s -s [-l | -U] [-abdDLnRrv] [-A addr_family] [-c traffic_class]\n\t"
2473 "[-g gateway [-g gateway ...]] [-N nexthop] [-F flow_label] [-I interval]\n\t"
2474 "[-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]\n",
2479 * Parse integer argument; exit with an error if it's not a number.
2480 * Now it also accepts hex. values.
2483 int_arg(char *s
, char *what
)
2490 if (s
[0] == '0' && (s
[1] == 'x' || s
[1] == 'X')) {
2492 num
= (int)strtol(cp
, &ep
, 16);
2494 num
= (int)strtol(s
, &ep
, 10);
2497 if (errno
|| *ep
!= '\0' || num
< 0) {
2498 Fprintf(stderr
, "%s: bad %s: %s\n", progname
, what
, s
);
2506 * Parse the interval into a itimerspec. The interval used to originally be
2507 * parsed as an integer argument. That means that one used to be able to specify
2508 * an interval in hex. The strtod() family honors that at times, with strtod
2509 * sometimes doing so depending on the compilation environment and strtof() and
2510 * srtold() always doing that. To facilitiate that and not worry about a
2511 * careless Makefile change breaking us, we instead just use strtold here, even
2512 * though we really don't need the precision.
2515 parse_interval(char *s
)
2521 val
= strtold(s
, &end
);
2522 if (errno
!= 0 || *end
!= '\0') {
2523 Fprintf(stderr
, "%s: bad interval: %s\n", progname
, s
);
2528 * Check values that we know are going to be bad. Anything greater than
2529 * INT_MAX, anything less than 0, look for specific NaNs. Also, clamp
2530 * the value at 0.01 seconds.
2532 if (val
== NAN
|| val
<= 0.0 || val
>= INT_MAX
) {
2533 Fprintf(stderr
, "%s: bad interval: %s\n", progname
, s
);
2538 Fprintf(stderr
, "%s: interval too small: %Lf\n", progname
, val
);
2542 interval
.it_value
.tv_sec
= (long)val
;
2543 interval
.it_value
.tv_nsec
= (long)((val
- interval
.it_value
.tv_sec
) *
2546 if (interval
.it_value
.tv_sec
== 0 &&
2547 interval
.it_value
.tv_nsec
< mintime
) {
2548 mintime
= interval
.it_value
.tv_nsec
;
2553 * We should have an SO_TIMESTAMP message for this socket to indicate
2554 * the actual time that the message took. If we don't we'll fall back to
2555 * gettimeofday(); however, that can cause any delays due to DNS
2556 * resolution and the like to end up wreaking havoc on us.
2559 ping_gettime(struct msghdr
*msg
, struct timeval
*tv
)
2561 struct cmsghdr
*cmsg
;
2563 for (cmsg
= CMSG_FIRSTHDR(msg
); cmsg
!= NULL
;
2564 cmsg
= CMSG_NXTHDR(msg
, cmsg
)) {
2565 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
2566 cmsg
->cmsg_type
== SO_TIMESTAMP
&&
2567 cmsg
->cmsg_len
== CMSG_LEN(sizeof (*tv
))) {
2568 bcopy(CMSG_DATA(cmsg
), tv
, sizeof (*tv
));
2573 (void) gettimeofday(tv
, NULL
);
2577 * The purpose of this thread is to try and inform a user that we're blocked
2578 * doing name lookups. For various reasons, ping has to try and look up the IP
2579 * addresses it receives via name services unless the -n flag is specified. The
2580 * irony of this is that when trying to use ping to actually diagnose a broken
2581 * network, name services are unlikely to be available and that will result in a
2582 * lot of confusion as to why pings seem like they're not working. As such, we
2583 * basically wake up every 2 seconds and check whether or not we've hit such a
2584 * condition where we should inform the user via stderr.
2586 * Once they've been informed, we do not inform them again until approximately a
2587 * minute of time has passed, in case that things are working intermittently.
2591 ns_warning_thr(void *unused
)
2593 hrtime_t last_warn
= 0;
2597 (void) sleep(ns_sleeptime
);
2599 mutex_enter(&ns_lock
);
2600 if (ns_active
== _B_TRUE
&&
2601 now
- ns_starttime
>= ns_warntime
* NANOSEC
) {
2602 if (now
- last_warn
>=
2603 ns_warninter
* NANOSEC
) {
2605 Fprintf(stderr
, "%s: warning: ICMP responses "
2606 "received, but name service lookups are "
2607 "taking a while. Use ping -n to disable "
2608 "name service lookups.\n",
2612 mutex_exit(&ns_lock
);
2615 /* LINTED: E_STMT_NOT_REACHED */