xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c (revision ff56787d6488797571f1eaba7dcf3ff9903154ba)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  *
21  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
22  * Use is subject to license terms.
23  */
24 
25 /*
26  * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
27  * All Rights Reserved.
28  */
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California.
33  * All Rights Reserved.
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 /*
41  * Copyright (c) 2018, Joyent, Inc.
42  * Copyright 2023 Oxide computer Company
43  * Copyright 2024 Bill Sommerfeld <sommerfeld@hamachi.org>
44  */
45 
46 #include <assert.h>
47 #include <stdio.h>
48 #include <strings.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52 #include <signal.h>
53 #include <limits.h>
54 #include <math.h>
55 #include <locale.h>
56 #include <thread.h>
57 #include <synch.h>
58 
59 #include <sys/time.h>
60 #include <sys/param.h>
61 #include <sys/socket.h>
62 #include <sys/sockio.h>
63 #include <sys/stropts.h>
64 #include <sys/file.h>
65 #include <sys/sysmacros.h>
66 #include <sys/debug.h>
67 
68 #include <arpa/inet.h>
69 #include <net/if.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/in.h>
72 #include <netinet/ip.h>
73 #include <netinet/ip_icmp.h>
74 #include <netinet/ip_var.h>
75 #include <netinet/ip6.h>
76 #include <netinet/icmp6.h>
77 #include <netinet/udp.h>
78 #include <netdb.h>
79 #include <stdlib.h>
80 #include <priv_utils.h>
81 
82 #include <libinetutil.h>
83 #include "ping.h"
84 
85 /*
86  * This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
87  * TCP's SEQ_LEQ macro.
88  */
89 #define	PINGSEQ_LEQ(a, b)	((int16_t)((a)-(b)) <= 0)
90 
91 #define	MAX_WAIT		10	/* max sec. to wait for response */
92 #define	MAX_TRAFFIC_CLASS	255	/* max traffic class for IPv6 */
93 #define	MAX_FLOW_LABEL		0xFFFFF	/* max flow label for IPv6 */
94 #define	MAX_TOS			255	/* max type-of-service for IPv4 */
95 
96 #define	TIMEOUT			20	/* default timeout value */
97 #define	DEFAULT_DATALEN		56
98 
99 #define	MULTICAST_NOLOOP	1	/* multicast options */
100 #define	MULTICAST_TTL		2
101 #define	MULTICAST_IF		4
102 
103 #define	IF_INDEX		0	/* types of -i argument */
104 #define	IF_NAME			1
105 #define	IF_ADDR			2
106 #define	IF_ADDR6		3
107 
108 #ifdef BSD
109 #define	setbuf(s, b)	setlinebuf((s))
110 #endif /* BSD */
111 
112 
113 /* interface identification */
114 union if_id {
115 	int index;		/* interface index (e.g., 1, 2) */
116 	char *name;		/* interface name (e.g., le0, hme0) */
117 	union any_in_addr addr;	/* interface address (e.g., 10.123.4.5) */
118 };
119 
120 /* stores the interface supplied by the user */
121 struct if_entry {
122 	char *str;		/* unresolved, string input */
123 	int id_type;		/* type of ID (index, name, addr, addr6) */
124 	union if_id id;		/* ID */
125 };
126 
127 char *progname;
128 char *targethost;
129 char *nexthop;
130 
131 static int send_sock;			/* send sockets */
132 static int send_sock6;
133 static struct sockaddr_in to;		/* where to send */
134 static struct sockaddr_in6 to6;
135 static union any_in_addr gw_IP_list[MAX_GWS];	/* gateways */
136 static union any_in_addr gw_IP_list6[MAX_GWS6];
137 static int if_index = 0;		/* outgoing interface index */
138 boolean_t is_alive = _B_FALSE;		/* is target host alive */
139 struct targetaddr *current_targetaddr;	/* current target IP address to probe */
140 static struct targetaddr *targetaddr_list; /* list of IP addresses to probe */
141 static int num_targetaddrs;		/* no of target addresses to probe */
142 static int num_v4 = 0;			/* count of IPv4 addresses */
143 static int num_v6 = 0;			/* count of IPv6 addresses */
144 boolean_t verbose = _B_FALSE;		/* verbose output */
145 boolean_t stats = _B_FALSE;		/* display statistics */
146 static boolean_t settos = _B_FALSE;	/* set type-of-service value */
147 boolean_t rr_option = _B_FALSE;		/* true if using record route */
148 boolean_t send_reply = _B_FALSE;	/* Send an ICMP_{ECHO|TSTAMP}REPLY */
149 					/* that goes to target and comes back */
150 					/* to the the sender via src routing. */
151 boolean_t strict = _B_FALSE;		/* true if using strict source route */
152 boolean_t ts_option = _B_FALSE;		/* true if using timestamp option */
153 boolean_t use_icmp_ts = _B_FALSE;	/* Use ICMP timestamp request */
154 boolean_t use_udp = _B_FALSE;		/* Use UDP instead of ICMP */
155 boolean_t probe_all = _B_FALSE;		/* probe all the IP addresses */
156 boolean_t nflag = _B_FALSE;		/* do not reverse lookup addresses */
157 boolean_t bypass = _B_FALSE;		/* bypass IPsec policy */
158 static int family_input = AF_UNSPEC;	/* address family supplied by user */
159 int datalen = DEFAULT_DATALEN;		/* How much data */
160 int ts_flag;				/* timestamp flag value */
161 static int num_gw;			/* number of gateways */
162 static int eff_num_gw;			/* effective number of gateways */
163 					/* if send_reply, it's 2*num_gw+1 */
164 static int num_wraps = -1;		/* no of times 64K icmp_seq wrapped */
165 static ushort_t dest_port = 32768 + 666; /* starting port for the UDP probes */
166 static char *gw_list[MAXMAX_GWS];	/* list of gateways as user enters */
167 static int options;			/* socket options */
168 static int moptions;			/* multicast options */
169 int npackets;				/* number of packets to send */
170 static ushort_t tos;			/* type-of-service value */
171 static int hoplimit = -1;		/* time-to-live value */
172 static int dontfrag;			/* IP*_DONTFRAG */
173 static int timeout = TIMEOUT;		/* timeout value (sec) for probes */
174 static struct if_entry out_if;		/* interface argument */
175 int ident;				/* ID for this ping run */
176 static hrtime_t t_last_probe_sent;	/* the time we sent the last probe */
177 static timer_t timer;			/* timer for waiting */
178 static volatile boolean_t timer_done = _B_FALSE; /* timer finished? */
179 static struct itimerspec interval = { { 0, 0 }, { 1, 0 } }; /* Interval for */
180 					/* -I. The default interval is 1s. */
181 static hrtime_t mintime = NSEC2MSEC(500);	/* minimum time between pings */
182 
183 /*
184  * Globals for our name services warning. See ns_warning_thr() for more on why
185  * this exists.
186  */
187 static mutex_t ns_lock = ERRORCHECKMUTEX; /* Protects the following data */
188 static boolean_t ns_active = _B_FALSE;	/* Lookup is going on */
189 static hrtime_t ns_starttime;		/* Time the lookup started */
190 static int ns_sleeptime = 2;		/* Time in seconds between checks */
191 static int ns_warntime = 2;		/* Time in seconds before warning */
192 
193 /*
194  * This buffer stores the received packets. Currently it needs to be 32 bit
195  * aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
196  * alignment now.
197  */
198 static uint64_t in_pkt[(IP_MAXPACKET + 1)/8];
199 
200 /* Used to store the ancillary data that comes with the received packets */
201 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
202 
203 static int ntransmitted;	/* number of packet sent to single IP address */
204 int nreceived;			/* # of packets we got back from target host */
205 int nreceived_last_target;	/* received from last target IP */
206 /*
207  * These are used for statistics. tmin is initialized to maximum longint value.
208  * The max value is also used for timeouts.   All times are in microseconds.
209  */
210 long long tmin = LLONG_MAX;
211 long long tmax;
212 int64_t tsum;			/* sum of all times, for doing average */
213 int64_t tsum2;			/* sum of squared times, for std. dev. */
214 
215 static struct targetaddr *build_targetaddr_list(struct addrinfo *,
216     union any_in_addr *);
217 static struct targetaddr *create_targetaddr_item(struct sockaddr *,
218     union any_in_addr *);
219 static struct ifaddrlist *find_if(struct ifaddrlist *, int);
220 static void finish();
221 static void get_gwaddrs(char *[], int, union any_in_addr *,
222     union any_in_addr *, int *, int *);
223 static void get_hostinfo(char *, int, struct addrinfo **);
224 static ushort_t in_cksum(ushort_t *, int);
225 static int int_arg(char *s, char *what);
226 static void mirror_gws(union any_in_addr *, int);
227 static void *ns_warning_thr(void *);
228 static void parse_interval(const char *s);
229 static void pinger(int, struct sockaddr *, struct msghdr *, int);
230 static void print_unknown_host_msg(const char *, const char *);
231 static void recv_icmp_packet(struct addrinfo *, int, int, ushort_t, ushort_t);
232 static void resolve_nodes(struct addrinfo **, struct addrinfo **,
233     union any_in_addr **);
234 static void select_all_src_addrs(union any_in_addr **, struct addrinfo *,
235     union any_in_addr *, union any_in_addr *);
236 static void select_src_addr(union any_in_addr *, int, union any_in_addr *);
237 static void set_nexthop(int, struct addrinfo *, int);
238 static boolean_t setup_socket(int, int *, int *, int *, ushort_t *,
239     struct addrinfo *);
240 static void usage(char *);
241 
242 /*
243  * main()
244  */
245 int
246 main(int argc, char *argv[])
247 {
248 	struct addrinfo	*ai_dst = NULL;		/* addrinfo host list */
249 	struct addrinfo	*ai_nexthop = NULL;		/* addrinfo nexthop */
250 	union any_in_addr *src_addr_list = NULL;	/* src addrs to use */
251 	int recv_sock = -1;				/* receive sockets */
252 	int recv_sock6 = -1;
253 	ushort_t udp_src_port;			/* src ports for UDP probes */
254 	ushort_t udp_src_port6;			/* used to identify replies */
255 	uint_t flowinfo = 0;
256 	uint_t class = 0;
257 	char abuf[INET6_ADDRSTRLEN];
258 	int c;
259 	int i;
260 	boolean_t has_sys_ip_config;
261 
262 	progname = argv[0];
263 
264 	(void) setlocale(LC_ALL, "");
265 
266 	/*
267 	 * This program needs the net_icmpaccess privilege for creating
268 	 * raw ICMP sockets.  It needs sys_ip_config for using the
269 	 * IP_NEXTHOP socket option (IPv4 only).  We'll fail
270 	 * on the socket call and report the error there when we have
271 	 * insufficient privileges.
272 	 *
273 	 * Shared-IP zones don't have the sys_ip_config privilege, so
274 	 * we need to check for it in our limit set before trying
275 	 * to set it.
276 	 */
277 	has_sys_ip_config = priv_ineffect(PRIV_SYS_IP_CONFIG);
278 
279 	(void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
280 	    has_sys_ip_config ? PRIV_SYS_IP_CONFIG : (char *)NULL,
281 	    (char *)NULL);
282 
283 	setbuf(stdout, (char *)0);
284 
285 	while ((c = getopt(argc, argv,
286 	    "abA:c:dDF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
287 		switch ((char)c) {
288 		case 'A':
289 			if (strcmp(optarg, "inet") == 0) {
290 				family_input = AF_INET;
291 			} else if (strcmp(optarg, "inet6") == 0) {
292 				family_input = AF_INET6;
293 			} else {
294 				Fprintf(stderr,
295 				    "%s: unknown address family %s\n",
296 				    progname, optarg);
297 				exit(EXIT_FAILURE);
298 			}
299 			break;
300 
301 		case 'a':
302 			probe_all = _B_TRUE;
303 			break;
304 
305 		case 'c':
306 			i = int_arg(optarg, "traffic class");
307 			if (i > MAX_TRAFFIC_CLASS) {
308 				Fprintf(stderr, "%s: traffic class %d out of "
309 				    "range\n", progname, i);
310 				exit(EXIT_FAILURE);
311 			}
312 			class = (uint_t)i;
313 			break;
314 
315 		case 'd':
316 			options |= SO_DEBUG;
317 			break;
318 
319 		case 'D':
320 			dontfrag = 1;
321 			break;
322 
323 		case 'b':
324 			bypass = _B_TRUE;
325 			break;
326 
327 		case 'F':
328 			i = int_arg(optarg, "flow label");
329 			if (i > MAX_FLOW_LABEL) {
330 				Fprintf(stderr, "%s: flow label %d out of "
331 				    "range\n", progname, i);
332 				exit(EXIT_FAILURE);
333 			}
334 			flowinfo = (uint_t)i;
335 			break;
336 
337 		case 'I':
338 			stats = _B_TRUE;
339 			parse_interval(optarg);
340 			break;
341 
342 		case 'i':
343 			/*
344 			 * this can accept interface index, interface name, and
345 			 * address configured on the interface
346 			 */
347 			moptions |= MULTICAST_IF;
348 			out_if.str = optarg;
349 
350 			if (inet_pton(AF_INET6, optarg, &out_if.id.addr) > 0) {
351 				out_if.id_type = IF_ADDR6;
352 			} else if (inet_pton(AF_INET, optarg,
353 			    &out_if.id.addr) > 0) {
354 				out_if.id_type = IF_ADDR;
355 			} else if (strcmp(optarg, "0") == 0) {
356 				out_if.id_type = IF_INDEX;
357 				out_if.id.index = 0;
358 			} else if ((out_if.id.index = atoi(optarg)) != 0) {
359 				out_if.id_type = IF_INDEX;
360 			} else {
361 				out_if.id.name = optarg;
362 				out_if.id_type = IF_NAME;
363 			}
364 			break;
365 
366 		case 'L':
367 			moptions |= MULTICAST_NOLOOP;
368 			break;
369 
370 		case 'l':
371 			send_reply = _B_TRUE;
372 			strict = _B_FALSE;
373 			break;
374 
375 		case 'n':
376 			nflag = _B_TRUE;
377 			break;
378 
379 		case 'P':
380 			settos = _B_TRUE;
381 			i = int_arg(optarg, "type-of-service");
382 			if (i > MAX_TOS) {
383 				Fprintf(stderr, "%s: tos value %d out of "
384 				    "range\n", progname, i);
385 				exit(EXIT_FAILURE);
386 			}
387 			tos = (ushort_t)i;
388 			break;
389 
390 		case 'p':
391 			i = int_arg(optarg, "port number");
392 			if (i > MAX_PORT) {
393 				Fprintf(stderr, "%s: port number %d out of "
394 				    "range\n", progname, i);
395 				exit(EXIT_FAILURE);
396 			}
397 			dest_port = (ushort_t)i;
398 			break;
399 
400 		case 'r':
401 			options |= SO_DONTROUTE;
402 			break;
403 
404 		case 'R':
405 			rr_option = _B_TRUE;
406 			break;
407 
408 		case 'S':
409 			send_reply = _B_TRUE;
410 			strict = _B_TRUE;
411 			break;
412 
413 		case 's':
414 			stats = _B_TRUE;
415 			break;
416 
417 		case 'T':
418 			ts_option = _B_TRUE;
419 			break;
420 
421 		case 't':
422 			moptions |= MULTICAST_TTL;
423 			hoplimit = int_arg(optarg, "ttl");
424 			if (hoplimit > MAXTTL) {
425 				Fprintf(stderr, "%s: ttl %d out of range\n",
426 				    progname, hoplimit);
427 				exit(EXIT_FAILURE);
428 			}
429 			break;
430 
431 		case 'U':
432 			use_udp = _B_TRUE;
433 			use_icmp_ts = _B_FALSE;
434 			break;
435 
436 		case 'v':
437 			verbose = _B_TRUE;
438 			break;
439 		/*
440 		 * 'x' and 'X' has been undocumented flags for source routing.
441 		 * Now we document loose source routing with the new flag 'g',
442 		 * which is same as in traceroute. We still keep x/X as
443 		 * as undocumented. 'G', which is for strict source routing is
444 		 * also undocumented.
445 		 */
446 		case 'x':
447 		case 'g':
448 			strict = _B_FALSE;
449 			if (num_gw > MAXMAX_GWS) {
450 				Fprintf(stderr, "%s: too many gateways\n",
451 				    progname);
452 				exit(EXIT_FAILURE);
453 			}
454 			gw_list[num_gw++] = optarg;
455 			break;
456 
457 		case 'X':
458 		case 'G':
459 			strict = _B_TRUE;
460 			if (num_gw > MAXMAX_GWS) {
461 				Fprintf(stderr, "%s: too many gateways\n",
462 				    progname);
463 				exit(EXIT_FAILURE);
464 			}
465 			gw_list[num_gw++] = optarg;
466 			break;
467 
468 		case 'N':
469 			if (nexthop != NULL) {
470 				Fprintf(stderr, "%s: only one next hop gateway"
471 				    " allowed\n", progname);
472 				exit(EXIT_FAILURE);
473 			}
474 			nexthop = optarg;
475 			break;
476 
477 		case 'Y':
478 			use_icmp_ts = _B_TRUE;
479 			use_udp = _B_FALSE;
480 			break;
481 
482 		case '0':
483 		case '1':
484 		case '2':
485 		case '3':
486 			ts_flag = (char)c - '0';
487 			break;
488 
489 		case '?':
490 			usage(progname);
491 			exit(EXIT_FAILURE);
492 			break;
493 
494 		default:
495 			usage(progname);
496 			exit(EXIT_FAILURE);
497 			break;
498 		}
499 	}
500 
501 	if (optind >= argc) {
502 		usage(progname);
503 		exit(EXIT_FAILURE);
504 	}
505 
506 	/*
507 	 * send_reply, which sends the probe packet back to itself
508 	 * doesn't work with UDP
509 	 */
510 	if (use_udp)
511 		send_reply = _B_FALSE;
512 
513 	if (getenv("MACHINE_THAT_GOES_PING") != NULL)
514 		stats = _B_TRUE;
515 
516 	targethost = argv[optind];
517 	optind++;
518 	if (optind < argc) {
519 		if (stats) {
520 			datalen = int_arg(argv[optind], "data size");
521 			optind++;
522 			if (optind < argc) {
523 				npackets = int_arg(argv[optind],
524 				    "packet count");
525 				if (npackets < 1) {
526 					Fprintf(stderr, "%s: packet count %d "
527 					    "out of range\n", progname,
528 					    npackets);
529 					exit(EXIT_FAILURE);
530 				}
531 			}
532 		} else {
533 			timeout = int_arg(argv[optind], "timeout");
534 		}
535 	}
536 
537 	/*
538 	 * Let's prepare sockaddr_in* structures, cause we might need both of
539 	 * them.
540 	 */
541 	bzero((char *)&to, sizeof (struct sockaddr_in));
542 	to.sin_family = AF_INET;
543 
544 	bzero((char *)&to6, sizeof (struct sockaddr_in6));
545 	to6.sin6_family = AF_INET6;
546 	to6.sin6_flowinfo = htonl((class << 20) | flowinfo);
547 
548 	if (stats)
549 		(void) sigset(SIGINT, finish);
550 
551 	ident = (int)getpid() & 0xFFFF;
552 
553 	/* resolve the hostnames */
554 	resolve_nodes(&ai_dst, &ai_nexthop, &src_addr_list);
555 
556 	/*
557 	 * We should make sure datalen is reasonable.
558 	 *	IP_MAXPACKET >= IPv4/IPv6 header length +
559 	 *			IPv4 options/IPv6 routing header length +
560 	 *			ICMP/ICMP6/UDP header length +
561 	 *			datalen
562 	 */
563 
564 	if (family_input == AF_INET6 ||
565 	    (family_input == AF_UNSPEC && num_v6 != 0)) {
566 		size_t exthdr_len = 0;
567 
568 		if (send_reply) {
569 			exthdr_len = sizeof (struct ip6_rthdr0) +
570 			    2 * num_gw * sizeof (struct in6_addr);
571 		} else if (num_gw > 0) {
572 			exthdr_len = sizeof (struct ip6_rthdr0) +
573 			    num_gw * sizeof (struct in6_addr);
574 		}
575 
576 		/*
577 		 * Size of ICMP6 header and UDP header are the same. Let's
578 		 * use ICMP6_MINLEN.
579 		 */
580 		if (datalen > (IP_MAXPACKET - (sizeof (struct ip6_hdr) +
581 		    exthdr_len + ICMP6_MINLEN))) {
582 			Fprintf(stderr,
583 			    "%s: data size too large for IPv6 packet\n",
584 			    progname);
585 			num_v6 = 0;
586 		}
587 	}
588 
589 	if (family_input == AF_INET ||
590 	    (family_input == AF_UNSPEC && num_v4 != 0)) {
591 		size_t opt_len = 0;
592 
593 		if (send_reply) {
594 			/*
595 			 * Includes 3 bytes code+ptr+len, the intermediate
596 			 * gateways, the actual and the effective target.
597 			 */
598 			opt_len = 3 +
599 			    (2 * num_gw + 2) * sizeof (struct in_addr);
600 		} else if (num_gw > 0) {
601 			opt_len = 3 + (num_gw + 1) * sizeof (struct in_addr);
602 		}
603 
604 		if (rr_option) {
605 			opt_len = MAX_IPOPTLEN;
606 		} else if (ts_option) {
607 			if ((ts_flag & 0x0f) <= IPOPT_TS_TSANDADDR) {
608 				opt_len = MAX_IPOPTLEN;
609 			} else {
610 				opt_len += IPOPT_MINOFF +
611 				    2 * sizeof (struct ipt_ta);
612 				/*
613 				 * Note: BSD/4.X is broken in their check so we
614 				 * have to  bump up this number by at least one.
615 				 */
616 				opt_len++;
617 			}
618 		}
619 
620 		/* Round up to 4 byte boundary */
621 		if (opt_len & 0x3)
622 			opt_len = (opt_len & ~0x3) + 4;
623 
624 		if (datalen > (IP_MAXPACKET - (sizeof (struct ip) + opt_len +
625 		    ICMP_MINLEN))) {
626 			Fprintf(stderr,
627 			    "%s: data size too large for IPv4 packet\n",
628 			    progname);
629 			num_v4 = 0;
630 		}
631 	}
632 
633 	if (num_v4 == 0 && num_v6 == 0) {
634 		exit(EXIT_FAILURE);
635 	}
636 
637 	/* setup the sockets */
638 	if (num_v6 != 0) {
639 		if (!setup_socket(AF_INET6, &send_sock6, &recv_sock6,
640 		    &if_index, &udp_src_port6, ai_nexthop))
641 			exit(EXIT_FAILURE);
642 	}
643 
644 	if (num_v4 != 0) {
645 		if (!setup_socket(AF_INET, &send_sock, &recv_sock, &if_index,
646 		    &udp_src_port, ai_nexthop))
647 			exit(EXIT_FAILURE);
648 	}
649 
650 	__priv_relinquish();
651 
652 	/*
653 	 * If sending back to ourself, add the mirror image of current
654 	 * gateways, so that the probes travel to and from the target
655 	 * by visiting the same gateways in reverse order.
656 	 */
657 	if (send_reply) {
658 		if (num_v6 != 0)
659 			mirror_gws(gw_IP_list6, AF_INET6);
660 		if (num_v4 != 0)
661 			mirror_gws(gw_IP_list, AF_INET);
662 
663 		/* We add 1 because we put the target as the middle gateway */
664 		eff_num_gw = 2 * num_gw + 1;
665 
666 	} else {
667 		eff_num_gw = num_gw;
668 	}
669 
670 	targetaddr_list = build_targetaddr_list(ai_dst, src_addr_list);
671 	current_targetaddr = targetaddr_list;
672 
673 	/*
674 	 * Set the starting_seq_num for the first targetaddr.
675 	 * If we are sending ICMP Echo Requests, the sequence number is same as
676 	 * ICMP sequence number, and it starts from zero. If we are sending UDP
677 	 * packets, the sequence number is the destination UDP port number,
678 	 * which starts from dest_port. At each probe, this sequence number is
679 	 * incremented by one.
680 	 * We set the starting_seq_num for first targetaddr here. The
681 	 * following ones will be set by looking at where we left with the last
682 	 * targetaddr.
683 	 */
684 	current_targetaddr->starting_seq_num = use_udp ? dest_port : 0;
685 
686 	if (stats) {
687 		if (probe_all || !nflag) {
688 			Printf("PING %s: %d data bytes\n", targethost, datalen);
689 		} else {
690 			if (ai_dst->ai_family == AF_INET) {
691 				(void) inet_ntop(AF_INET,
692 				    &((struct sockaddr_in *)(void *)
693 				    ai_dst->ai_addr)->sin_addr,
694 				    abuf, sizeof (abuf));
695 			} else {
696 				(void) inet_ntop(AF_INET6,
697 				    &((struct sockaddr_in6 *)(void *)
698 				    ai_dst->ai_addr)->sin6_addr,
699 				    abuf, sizeof (abuf));
700 			}
701 			Printf("PING %s (%s): %d data bytes\n",
702 			    targethost, abuf, datalen);
703 		}
704 	}
705 
706 	/* Create our timer for future use */
707 	if (timer_create(CLOCK_REALTIME, NULL, &timer) != 0) {
708 		Fprintf(stderr, "%s: failed to create timer: %s\n",
709 		    progname, strerror(errno));
710 		exit(EXIT_FAILURE);
711 	}
712 
713 	/*
714 	 * Finally start up the name services warning thread.
715 	 */
716 	if (thr_create(NULL, 0, ns_warning_thr, NULL,
717 	    THR_DETACHED | THR_DAEMON, NULL) != 0) {
718 		Fprintf(stderr, "%s: failed to create name services "
719 		    "thread: %s\n", progname, strerror(errno));
720 		exit(EXIT_FAILURE);
721 	}
722 
723 	/* Let's get things going */
724 	send_scheduled_probe();
725 
726 	/* SIGALRM is used to send the next scheduled probe */
727 	(void) sigset(SIGALRM, sigalrm_handler);
728 	schedule_sigalrm();
729 
730 	/*
731 	 * From now on, we'll always be listening to ICMP packets. As SIGALRM
732 	 * comes in, sigalrm_handler() will be invoked and send another
733 	 * probe.
734 	 */
735 	recv_icmp_packet(ai_dst, recv_sock6, recv_sock, udp_src_port6,
736 	    udp_src_port);
737 
738 	return (EXIT_SUCCESS);	/* should never come here */
739 }
740 
741 /*
742  * Build the target IP address list. Use command line options and
743  * name lookup results returned from name server to determine which addresses
744  * to probe, how many times, in which order.
745  */
746 static struct targetaddr *
747 build_targetaddr_list(struct addrinfo *ai_dst, union any_in_addr *src_addr_list)
748 {
749 	struct targetaddr *head = NULL;
750 	struct targetaddr *targetaddr;
751 	struct targetaddr **nextp;
752 	int num_dst;
753 	int i;
754 	struct addrinfo *aip;
755 
756 	aip = ai_dst;
757 	if (probe_all)
758 		num_dst = num_v4 + num_v6;
759 	else
760 		num_dst = 1;
761 	num_targetaddrs = num_dst;
762 	nextp = &head;
763 	for (aip = ai_dst, i = 0; aip != NULL; aip = aip->ai_next, i++) {
764 		if (aip->ai_family == AF_INET && num_v4 != 0) {
765 			targetaddr = create_targetaddr_item(aip->ai_addr,
766 			    &src_addr_list[i]);
767 		} else if (aip->ai_family == AF_INET6 && num_v6 != 0) {
768 			targetaddr = create_targetaddr_item(aip->ai_addr,
769 			    &src_addr_list[i]);
770 		} else {
771 			continue;
772 		}
773 		*nextp = targetaddr;
774 		nextp = &targetaddr->next;
775 		if (num_targetaddrs == 1)
776 			break;
777 	}
778 	if (npackets == 0 && stats)
779 		*nextp = head;	/* keep going indefinitely */
780 
781 	return (head);
782 }
783 
784 /*
785  * Given a destination sockaddr (containing address family, address, and
786  * perhaps address scope) and a source address, this function creates a
787  * targetaddr structure that will become part of the global targetaddr
788  * list. Each targetaddr tracks the probes sent to a specific destination.
789  */
790 static struct targetaddr *
791 create_targetaddr_item(struct sockaddr *dst_addr, union any_in_addr *src_addr)
792 {
793 	struct targetaddr *targetaddr;
794 	struct sockaddr_in *dst4 = (struct sockaddr_in *)dst_addr;
795 	struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst_addr;
796 
797 	targetaddr = (struct targetaddr *)malloc(sizeof (struct targetaddr));
798 	if (targetaddr == NULL) {
799 		Fprintf(stderr, "%s: malloc %s\n", progname, strerror(errno));
800 		exit(EXIT_FAILURE);
801 	}
802 	targetaddr->family = dst_addr->sa_family;
803 	switch (dst_addr->sa_family) {
804 	case AF_INET:
805 		memset(&targetaddr->dst_addr, 0, sizeof (targetaddr->dst_addr));
806 		targetaddr->dst_addr.addr = dst4->sin_addr;
807 		targetaddr->dst_scope = 0;
808 		break;
809 	case AF_INET6:
810 		memset(&targetaddr->dst_addr, 0, sizeof (targetaddr->dst_addr));
811 		targetaddr->dst_addr.addr6 = dst6->sin6_addr;
812 		targetaddr->dst_scope = dst6->sin6_scope_id;
813 
814 		if (if_index != 0 && targetaddr->dst_scope != 0 &&
815 		    if_index != targetaddr->dst_scope) {
816 			Fprintf(stderr, "%s: warning: conflicting scopes; using"
817 			    " %s\n", progname, pr_if(targetaddr->dst_scope));
818 		}
819 		break;
820 	}
821 	targetaddr->src_addr = *src_addr;
822 	if (stats) {
823 		/*
824 		 * npackets is only defined if we are in stats mode.
825 		 * npackets determines how many probes to send to each target
826 		 * IP address. npackets == 0 means send only 1 and move on to
827 		 * next target IP.
828 		 */
829 		if (npackets > 0)
830 			targetaddr->num_probes = npackets;
831 		else
832 			targetaddr->num_probes = 1;
833 	} else {
834 		targetaddr->num_probes = timeout;
835 	}
836 	targetaddr->num_sent = 0;
837 	targetaddr->got_reply = _B_FALSE;
838 	targetaddr->probing_done = _B_FALSE;
839 	targetaddr->starting_seq_num = 0; /* actual value will be set later */
840 	targetaddr->next = NULL;	/* actual value will be set later */
841 
842 	return (targetaddr);
843 }
844 
845 /*
846  * print "unknown host" message
847  */
848 static void
849 print_unknown_host_msg(const char *protocol, const char *hostname)
850 {
851 	Fprintf(stderr, "%s: unknown%s host %s\n", progname, protocol,
852 	    hostname);
853 }
854 
855 /*
856  * Resolve hostnames for the target host and gateways. Also, determine source
857  * addresses to use for each target address.
858  */
859 static void
860 resolve_nodes(struct addrinfo **ai_dstp, struct addrinfo **ai_nexthopp,
861     union any_in_addr **src_addr_listp)
862 {
863 	struct addrinfo *ai_dst = NULL;
864 	struct addrinfo *ai_nexthop = NULL;
865 	struct addrinfo *aip = NULL;
866 	union any_in_addr *src_addr_list = NULL;
867 	int num_resolved_gw = 0;
868 	int num_resolved_gw6 = 0;
869 
870 	get_hostinfo(targethost, family_input, &ai_dst);
871 	if (ai_dst == NULL) {
872 		print_unknown_host_msg("", targethost);
873 		exit(EXIT_FAILURE);
874 	}
875 	if (nexthop != NULL) {
876 		get_hostinfo(nexthop, family_input, &ai_nexthop);
877 		if (ai_nexthop == NULL) {
878 			print_unknown_host_msg("", nexthop);
879 			exit(EXIT_FAILURE);
880 		}
881 	}
882 	/* Get a count of the v4 & v6 addresses */
883 	for (aip = ai_dst; aip != NULL; aip = aip->ai_next) {
884 		switch (aip->ai_family) {
885 		case AF_INET:
886 			num_v4++;
887 			break;
888 		case AF_INET6:
889 			num_v6++;
890 			break;
891 		}
892 	}
893 
894 	if (family_input == AF_UNSPEC && !probe_all) {
895 		family_input = ai_dst->ai_family;
896 	}
897 
898 	/* resolve gateways */
899 	if (num_gw > 0) {
900 		get_gwaddrs(gw_list, family_input, gw_IP_list, gw_IP_list6,
901 		    &num_resolved_gw, &num_resolved_gw6);
902 
903 		/* we couldn't resolve a gateway as an IPv6 host */
904 		if (num_resolved_gw6 != num_gw && num_v6 != 0 &&
905 		    (family_input == AF_INET6 || family_input == AF_UNSPEC)) {
906 			print_unknown_host_msg(" IPv6",
907 			    gw_list[num_resolved_gw6]);
908 			num_v6 = 0;
909 		}
910 
911 		/* we couldn't resolve a gateway as an IPv4 host */
912 		if (num_resolved_gw != num_gw && num_v4 != 0 &&
913 		    (family_input == AF_INET || family_input == AF_UNSPEC)) {
914 			print_unknown_host_msg(" IPv4",
915 			    gw_list[num_resolved_gw]);
916 			num_v4 = 0;
917 		}
918 	}
919 
920 	if (num_v4 == 0 && num_v6 == 0)
921 		exit(EXIT_FAILURE);
922 
923 	select_all_src_addrs(&src_addr_list, ai_dst, gw_IP_list, gw_IP_list6);
924 	*ai_dstp = ai_dst;
925 	*ai_nexthopp = ai_nexthop;
926 	*src_addr_listp = src_addr_list;
927 }
928 
929 /*
930  * Resolve the gateway names, splitting results into v4 and v6 lists.
931  * Gateway addresses are added to the appropriate passed-in array; the
932  * number of resolved gateways for each af is returned in resolved[6].
933  * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
934  * and resolved[6] ptrs are non-null; ignores array and counter if the
935  * address family param makes them irrelevant.
936  */
937 static void
938 get_gwaddrs(char **gw_list, int family, union any_in_addr *gwIPlist,
939     union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
940 {
941 	int i;
942 	boolean_t check_v4 = _B_TRUE, check_v6 = _B_TRUE;
943 	struct addrinfo	*ai = NULL;
944 	struct addrinfo	*aip = NULL;
945 
946 	*resolved = *resolved6 = 0;
947 	switch (family) {
948 	case AF_UNSPEC:
949 		break;
950 	case AF_INET:
951 		check_v6 = _B_FALSE;
952 		break;
953 	case AF_INET6:
954 		check_v4 = _B_FALSE;
955 		break;
956 	default:
957 		return;
958 	}
959 
960 	if (check_v4 && num_gw >= MAX_GWS) {
961 		check_v4 = _B_FALSE;
962 		Fprintf(stderr, "%s: too many IPv4 gateways\n", progname);
963 	}
964 	if (check_v6 && num_gw > MAX_GWS6) {
965 		check_v6 = _B_FALSE;
966 		Fprintf(stderr, "%s: too many IPv6 gateways\n", progname);
967 	}
968 
969 	for (i = 0; i < num_gw; i++) {
970 		if (!check_v4 && !check_v6)
971 			return;
972 		get_hostinfo(gw_list[i], family, &ai);
973 		if (ai == NULL)
974 			return;
975 		if (check_v4 && num_v4 != 0) {
976 			for (aip = ai; aip != NULL; aip = aip->ai_next) {
977 				if (aip->ai_family == AF_INET) {
978 					/* LINTED E_BAD_PTR_CAST_ALIGN */
979 					bcopy(&((struct sockaddr_in *)
980 					    aip->ai_addr)->sin_addr,
981 					    &gwIPlist[i].addr,
982 					    aip->ai_addrlen);
983 					(*resolved)++;
984 					break;
985 				}
986 			}
987 		} else if (check_v4) {
988 			check_v4 = _B_FALSE;
989 		}
990 		if (check_v6 && num_v6 != 0) {
991 			for (aip = ai; aip != NULL; aip = aip->ai_next) {
992 				if (aip->ai_family == AF_INET6) {
993 					/* LINTED E_BAD_PTR_CAST_ALIGN */
994 					bcopy(&((struct sockaddr_in6 *)
995 					    aip->ai_addr)->sin6_addr,
996 					    &gwIPlist6[i].addr6,
997 					    aip->ai_addrlen);
998 					(*resolved6)++;
999 					break;
1000 				}
1001 			}
1002 		} else if (check_v6) {
1003 			check_v6 = _B_FALSE;
1004 		}
1005 	}
1006 	freeaddrinfo(ai);
1007 }
1008 
1009 /*
1010  * Given the list of gateways, extends the list with its mirror image. This is
1011  * used when -l/-S is used. The middle gateway will be the target address. We'll
1012  * leave it blank for now.
1013  */
1014 static void
1015 mirror_gws(union any_in_addr *gwIPlist, int family)
1016 {
1017 	int effective_num_gw;
1018 	int i;
1019 
1020 	/* We add 1 because we put the target as the middle gateway */
1021 	effective_num_gw = 2 * num_gw + 1;
1022 
1023 	if ((family == AF_INET && effective_num_gw >= MAX_GWS) ||
1024 	    (family == AF_INET6 && effective_num_gw > MAX_GWS6)) {
1025 		Fprintf(stderr, "%s: too many %s gateways\n",
1026 		    progname, (family == AF_INET) ? "IPv4" : "IPv6");
1027 		exit(EXIT_FAILURE);
1028 	}
1029 
1030 	for (i = 0; i < num_gw; i++)
1031 		gwIPlist[num_gw + i + 1].addr6 = gwIPlist[num_gw - i - 1].addr6;
1032 }
1033 
1034 /*
1035  * Given IP address or hostname, return addrinfo list.
1036  * Assumes that addrinfo ** ptr is non-null.
1037  */
1038 static void
1039 get_hostinfo(char *host, int family, struct addrinfo **aipp)
1040 {
1041 	struct addrinfo hints, *ai;
1042 	struct in6_addr addr6;
1043 	struct in_addr addr;
1044 	boolean_t broadcast;		/* is this 255.255.255.255? */
1045 	char tmp_buf[INET6_ADDRSTRLEN];
1046 	int rc;
1047 
1048 	/* check if broadcast */
1049 	if (strcmp(host, "255.255.255.255") == 0)
1050 		broadcast = _B_TRUE;
1051 	else
1052 		broadcast = _B_FALSE;
1053 
1054 	/* check if IPv4-mapped address or broadcast */
1055 	if (((inet_pton(AF_INET6, host, &addr6) > 0) &&
1056 	    IN6_IS_ADDR_V4MAPPED(&addr6)) || broadcast) {
1057 		if (!broadcast) {
1058 			/*
1059 			 * Peel off the "mapping" stuff, leaving 32 bit IPv4
1060 			 * address.
1061 			 */
1062 			IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
1063 
1064 			/* convert it back to a string */
1065 			(void) inet_ntop(AF_INET, (void *)&addr, tmp_buf,
1066 			    sizeof (tmp_buf));
1067 			/*
1068 			 * Now the host is an IPv4 address.
1069 			 * Since it previously was a v4 mapped v6 address
1070 			 * we can be sure that the size of buffer 'host'
1071 			 * is large enough to contain the associated v4
1072 			 * address and so we don't need to use a strn/lcpy
1073 			 * here.
1074 			 */
1075 			(void) strcpy(host, tmp_buf);
1076 		}
1077 		/*
1078 		 * If it's a broadcast address, it cannot be an IPv6 address.
1079 		 * Also, if it's a mapped address, we convert it into IPv4
1080 		 * address because ping will send and receive IPv4 packets for
1081 		 * that address. Therefore, it's a failure case to ask
1082 		 * get_hostinfo() to treat a broadcast or a mapped address
1083 		 * as an IPv6 address.
1084 		 */
1085 		if (family == AF_INET6) {
1086 			return;
1087 		}
1088 	}
1089 
1090 	(void) memset(&hints, 0, sizeof (hints));
1091 	hints.ai_family = family;
1092 	hints.ai_flags = AI_ADDRCONFIG;
1093 	rc = getaddrinfo(host, NULL, &hints, &ai);
1094 	if (rc != 0) {
1095 		if (rc != EAI_NONAME)
1096 			Fprintf(stderr, "%s: getaddrinfo: %s\n", progname,
1097 			    gai_strerror(rc));
1098 		return;
1099 	}
1100 	*aipp = ai;
1101 }
1102 
1103 /*
1104  * For each IP address of the target host, determine a source address to use.
1105  */
1106 static void
1107 select_all_src_addrs(union any_in_addr **src_addr_list, struct addrinfo *ai,
1108     union any_in_addr *gwv4, union any_in_addr *gwv6)
1109 {
1110 	union any_in_addr *list;
1111 	struct addrinfo *aip;
1112 	int num_dst = 1;
1113 	int i;
1114 
1115 	if (probe_all) {
1116 		for (aip = ai; aip->ai_next != NULL; aip = aip->ai_next)
1117 			num_dst++;
1118 	}
1119 
1120 	list = calloc((size_t)num_dst, sizeof (union any_in_addr));
1121 	if (list == NULL) {
1122 		Fprintf(stderr, "%s: calloc: %s\n", progname, strerror(errno));
1123 		exit(EXIT_FAILURE);
1124 	}
1125 
1126 	/*
1127 	 * If there's a gateway, a routing header as a consequence, our kernel
1128 	 * picks the source address based on the first hop address, rather than
1129 	 * final destination address.
1130 	 */
1131 	if (num_gw > 0) {
1132 		if (ai->ai_family == AF_INET)
1133 			select_src_addr(gwv4, ai->ai_family, &list[0]);
1134 		else
1135 			select_src_addr(gwv6, ai->ai_family, &list[0]);
1136 		/*
1137 		 * Since the first gateway address is fixed, we'll use the same
1138 		 * src address for every different final destination address
1139 		 * we send to.
1140 		 */
1141 		for (i = 1; i < num_dst; i++)
1142 			list[i] = list[0];
1143 	} else {
1144 		/*
1145 		 * Although something like 'ping -l host' results in a routing
1146 		 * header, the first gateway address is the target host's
1147 		 * address. Therefore, as far as src address selection goes,
1148 		 * the result is same as having no routing header.
1149 		 */
1150 		for (i = 0, aip = ai; i < num_dst && aip != NULL;
1151 		    i++, aip = aip->ai_next) {
1152 			if (aip->ai_family == AF_INET) {
1153 				if (num_v4 != 0) {
1154 					select_src_addr((union any_in_addr *)
1155 					    /* LINTED E_BAD_PTR_CAST_ALIGN */
1156 					    &((struct sockaddr_in *)
1157 					    aip->ai_addr)->sin_addr,
1158 					    aip->ai_family,
1159 					    &list[i]);
1160 				}
1161 			} else {
1162 				if (num_v6 != 0) {
1163 					select_src_addr((union any_in_addr *)
1164 					    /* LINTED E_BAD_PTR_CAST_ALIGN */
1165 					    &((struct sockaddr_in6 *)
1166 					    aip->ai_addr)->sin6_addr,
1167 					    aip->ai_family,
1168 					    &list[i]);
1169 				}
1170 			}
1171 		}
1172 	}
1173 
1174 	*src_addr_list = list;
1175 }
1176 
1177 /*
1178  * For a given destination address, determine a source address to use.
1179  * Returns wildcard address if it cannot determine the source address.
1180  */
1181 static void
1182 select_src_addr(union any_in_addr *dst_addr, int family,
1183     union any_in_addr *src_addr)
1184 {
1185 	struct sockaddr *sock;
1186 	struct sockaddr_in *sin = NULL;
1187 	struct sockaddr_in6 *sin6 = NULL;
1188 	int tmp_fd;
1189 	size_t sock_len;
1190 
1191 	sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
1192 	if (sock == NULL) {
1193 		Fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
1194 		exit(EXIT_FAILURE);
1195 	}
1196 	(void) bzero(sock, sizeof (struct sockaddr_in6));
1197 
1198 	if (family == AF_INET) {
1199 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1200 		sin = (struct sockaddr_in *)sock;
1201 		sin->sin_family = AF_INET;
1202 		sin->sin_addr = dst_addr->addr;
1203 		sin->sin_port = IPPORT_ECHO;	/* port shouldn't be 0 */
1204 		sock_len = sizeof (struct sockaddr_in);
1205 	} else {
1206 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1207 		sin6 = (struct sockaddr_in6 *)sock;
1208 		sin6->sin6_family = AF_INET6;
1209 		sin6->sin6_addr = dst_addr->addr6;
1210 		sin6->sin6_port = IPPORT_ECHO;	/* port shouldn't be 0 */
1211 		sock_len = sizeof (struct sockaddr_in6);
1212 	}
1213 
1214 	/* open a UDP socket */
1215 	if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
1216 		Fprintf(stderr, "%s: udp socket: %s\n", progname,
1217 		    strerror(errno));
1218 		exit(EXIT_FAILURE);
1219 	}
1220 
1221 	/* connect it */
1222 	if (connect(tmp_fd, sock, sock_len) < 0) {
1223 		/*
1224 		 * If there's no route to the destination, this connect() call
1225 		 * fails. We just return all-zero (wildcard) as the source
1226 		 * address, so that user can get to see "no route to dest"
1227 		 * message, as it'll try to send the probe packet out and will
1228 		 * receive ICMP unreachable.
1229 		 */
1230 		if (family == AF_INET)
1231 			src_addr->addr.s_addr = INADDR_ANY;
1232 		else
1233 			src_addr->addr6 = in6addr_any;
1234 		free(sock);
1235 		return;
1236 	}
1237 
1238 	/* get the local sock info */
1239 	if (getsockname(tmp_fd, sock, &sock_len) < 0) {
1240 		Fprintf(stderr, "%s: getsockname: %s\n", progname,
1241 		    strerror(errno));
1242 		exit(EXIT_FAILURE);
1243 	}
1244 
1245 	if (family == AF_INET) {
1246 		assert(sin != NULL);
1247 		src_addr->addr = sin->sin_addr;
1248 	} else {
1249 		assert(sin6 != NULL);
1250 		src_addr->addr6 = sin6->sin6_addr;
1251 	}
1252 
1253 	(void) close(tmp_fd);
1254 	free(sock);
1255 }
1256 
1257 /*
1258  * Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
1259  * exits on failure
1260  */
1261 static void
1262 set_nexthop(int family, struct addrinfo	*ai_nexthop, int sock)
1263 {
1264 	if (family == AF_INET) {
1265 		ipaddr_t nh;
1266 
1267 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1268 		nh = ((struct sockaddr_in *)ai_nexthop->
1269 		    ai_addr)->sin_addr.s_addr;
1270 
1271 		/* now we need the sys_ip_config privilege */
1272 		(void) __priv_bracket(PRIV_ON);
1273 		if (setsockopt(sock, IPPROTO_IP, IP_NEXTHOP,
1274 		    &nh, sizeof (ipaddr_t)) < 0) {
1275 			if (errno == EPERM)
1276 				Fprintf(stderr, "%s: Insufficient privilege "
1277 				    "to specify IPv4 nexthop router.\n",
1278 				    progname);
1279 			else
1280 				Fprintf(stderr, "%s: setsockopt %s\n",
1281 				    progname, strerror(errno));
1282 			exit(EXIT_FAILURE);
1283 		}
1284 		(void) __priv_bracket(PRIV_OFF);
1285 		/* revert to non-privileged user */
1286 	} else {
1287 		struct sockaddr_in6 *nh;
1288 
1289 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1290 		nh = (struct sockaddr_in6 *)ai_nexthop->
1291 		    ai_addr;
1292 
1293 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_NEXTHOP,
1294 		    nh, sizeof (struct sockaddr_in6)) < 0) {
1295 			Fprintf(stderr, "%s: setsockopt %s\n",
1296 			    progname, strerror(errno));
1297 			exit(EXIT_FAILURE);
1298 		}
1299 	}
1300 }
1301 
1302 /*
1303  * Setup the socket for the given address family.
1304  * Returns _B_TRUE on success, _B_FALSE on failure. Failure is the case when no
1305  * interface can be found, or the specified interface (-i) is not found. On
1306  * library call failures, it exit()s.
1307  */
1308 static boolean_t
1309 setup_socket(int family, int *send_sockp, int *recv_sockp, int *if_index,
1310     ushort_t *udp_src_port, struct addrinfo *ai_nexthop)
1311 {
1312 	int send_sock;
1313 	int recv_sock;
1314 	struct sockaddr_in6 sin6;
1315 	struct sockaddr_in sin;
1316 	struct sockaddr *sp;
1317 	struct ipsec_req req;
1318 	size_t slen;
1319 	int on = 1;
1320 	uchar_t char_op;
1321 	int int_op;
1322 
1323 	/* now we need the net_icmpaccess privilege */
1324 	(void) __priv_bracket(PRIV_ON);
1325 
1326 	recv_sock = socket(family, SOCK_RAW,
1327 	    (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
1328 
1329 	if (recv_sock < 0) {
1330 		Fprintf(stderr, "%s: socket %s\n", progname, strerror(errno));
1331 		exit(EXIT_FAILURE);
1332 	}
1333 
1334 	/* revert to non-privileged user after opening sockets */
1335 	(void) __priv_bracket(PRIV_OFF);
1336 
1337 	if (bypass) {
1338 		(void) memset(&req, 0, sizeof (req));
1339 		req.ipsr_ah_req = IPSEC_PREF_NEVER;
1340 		req.ipsr_esp_req = IPSEC_PREF_NEVER;
1341 
1342 		if (setsockopt(recv_sock, (family == AF_INET) ? IPPROTO_IP :
1343 		    IPPROTO_IPV6, IP_SEC_OPT, &req, sizeof (req)) < 0) {
1344 			switch (errno) {
1345 			case EPROTONOSUPPORT:
1346 				/*
1347 				 * No IPsec subsystem or policy loaded.
1348 				 * Bypass implicitly allowed.
1349 				 */
1350 				break;
1351 			case EPERM:
1352 				Fprintf(stderr, "%s: Insufficient privilege "
1353 				    "to bypass IPsec policy.\n", progname);
1354 				exit(EXIT_FAILURE);
1355 				break;
1356 			default:
1357 				Fprintf(stderr, "%s: setsockopt %s\n", progname,
1358 				    strerror(errno));
1359 				exit(EXIT_FAILURE);
1360 				break;
1361 			}
1362 		}
1363 	}
1364 
1365 	/*
1366 	 * We always receive on raw icmp socket. But the sending socket can be
1367 	 * raw icmp or udp, depending on the use of -U flag.
1368 	 */
1369 	if (use_udp) {
1370 		send_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP);
1371 		if (send_sock < 0) {
1372 			Fprintf(stderr, "%s: socket %s\n", progname,
1373 			    strerror(errno));
1374 			exit(EXIT_FAILURE);
1375 		}
1376 
1377 		if (bypass) {
1378 			if (setsockopt(send_sock, (family == AF_INET) ?
1379 			    IPPROTO_IP : IPPROTO_IPV6, IP_SEC_OPT, &req,
1380 			    sizeof (req)) < 0) {
1381 				switch (errno) {
1382 				case EPROTONOSUPPORT:
1383 					/*
1384 					 * No IPsec subsystem or policy loaded.
1385 					 * Bypass implicitly allowed.
1386 					 */
1387 					break;
1388 				case EPERM:
1389 					Fprintf(stderr, "%s: Insufficient "
1390 					    "privilege to bypass IPsec "
1391 					    "policy.\n", progname);
1392 					exit(EXIT_FAILURE);
1393 					break;
1394 				default:
1395 					Fprintf(stderr, "%s: setsockopt %s\n",
1396 					    progname, strerror(errno));
1397 					exit(EXIT_FAILURE);
1398 					break;
1399 				}
1400 			}
1401 		}
1402 
1403 		/*
1404 		 * In order to distinguish replies to our UDP probes from
1405 		 * other pings', we need to know our source port number.
1406 		 */
1407 		if (family == AF_INET) {
1408 			sp = (struct sockaddr *)&sin;
1409 			slen = sizeof (sin);
1410 		} else {
1411 			sp = (struct sockaddr *)&sin6;
1412 			slen = sizeof (sin6);
1413 		}
1414 		bzero(sp, slen);
1415 		sp->sa_family = family;
1416 
1417 		/* Let's bind() send_sock to wildcard address and port */
1418 		if (bind(send_sock, sp, slen) < 0) {
1419 			Fprintf(stderr, "%s: bind %s\n", progname,
1420 			    strerror(errno));
1421 			exit(EXIT_FAILURE);
1422 		}
1423 
1424 		/* .... and see what port kernel picked for us */
1425 		if (getsockname(send_sock, sp, &slen) < 0) {
1426 			Fprintf(stderr, "%s: getsockname %s\n", progname,
1427 			    strerror(errno));
1428 			exit(EXIT_FAILURE);
1429 		}
1430 		*udp_src_port = (family == AF_INET) ? sin.sin_port :
1431 		    sin6.sin6_port;
1432 	} else {
1433 		send_sock = recv_sock;
1434 	}
1435 
1436 	if (nexthop != NULL)
1437 		set_nexthop(family, ai_nexthop, send_sock);
1438 
1439 	int_op = 48 * 1024;
1440 	if (int_op < datalen)
1441 		int_op = datalen;
1442 	if (setsockopt(recv_sock, SOL_SOCKET, SO_RCVBUF, (char *)&int_op,
1443 	    sizeof (int_op)) == -1) {
1444 		Fprintf(stderr, "%s: setsockopt SO_RCVBUF %s\n", progname,
1445 		    strerror(errno));
1446 		exit(EXIT_FAILURE);
1447 	}
1448 
1449 	if (setsockopt(send_sock, SOL_SOCKET, SO_SNDBUF, (char *)&int_op,
1450 	    sizeof (int_op)) == -1) {
1451 		Fprintf(stderr, "%s: setsockopt SO_SNDBUF %s\n", progname,
1452 		    strerror(errno));
1453 		exit(EXIT_FAILURE);
1454 	}
1455 
1456 	if (options & SO_DEBUG) {
1457 		if (setsockopt(send_sock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1458 		    sizeof (on)) == -1) {
1459 			Fprintf(stderr, "%s: setsockopt SO_DEBUG %s\n",
1460 			    progname, strerror(errno));
1461 			exit(EXIT_FAILURE);
1462 		}
1463 	}
1464 
1465 	if (options & SO_DONTROUTE) {
1466 		if (setsockopt(send_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1467 		    sizeof (on)) == -1) {
1468 			Fprintf(stderr, "%s: setsockopt SO_DONTROUTE %s\n",
1469 			    progname, strerror(errno));
1470 			exit(EXIT_FAILURE);
1471 		}
1472 	}
1473 
1474 	if (moptions & MULTICAST_NOLOOP) {
1475 		if (family == AF_INET) {
1476 			char_op = 0;	/* used to turn off option */
1477 
1478 			if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
1479 			    (char *)&char_op, sizeof (char_op)) == -1) {
1480 				Fprintf(stderr, "%s: setsockopt "
1481 				    "IP_MULTICAST_NOLOOP %s\n", progname,
1482 				    strerror(errno));
1483 				exit(EXIT_FAILURE);
1484 			}
1485 		} else {
1486 			int_op = 0;	/* used to turn off option */
1487 
1488 			if (setsockopt(send_sock, IPPROTO_IPV6,
1489 			    IPV6_MULTICAST_LOOP, (char *)&int_op,
1490 			    sizeof (int_op)) == -1) {
1491 				Fprintf(stderr, "%s: setsockopt "
1492 				    "IPV6_MULTICAST_NOLOOP %s\n", progname,
1493 				    strerror(errno));
1494 				exit(EXIT_FAILURE);
1495 			}
1496 		}
1497 	}
1498 
1499 	if (moptions & MULTICAST_TTL) {
1500 		char_op = hoplimit;
1501 
1502 		/* Applies to unicast and multicast. */
1503 		if (family == AF_INET) {
1504 			if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL,
1505 			    (char *)&char_op, sizeof (char)) == -1) {
1506 				Fprintf(stderr, "%s: setsockopt "
1507 				    "IP_MULTICAST_TTL %s\n", progname,
1508 				    strerror(errno));
1509 				exit(EXIT_FAILURE);
1510 			}
1511 			if (setsockopt(send_sock, IPPROTO_IP, IP_TTL,
1512 			    (char *)&hoplimit, sizeof (hoplimit)) == -1) {
1513 				Fprintf(stderr, "%s: setsockopt IP_TTL %s\n",
1514 				    progname, strerror(errno));
1515 				exit(EXIT_FAILURE);
1516 			}
1517 		}
1518 		/*
1519 		 * AF_INET6 case is handled in set_ancillary_data() function.
1520 		 * This is because when ancillary data is used (for routing
1521 		 * header and outgoing interface index), the hoplimit set using
1522 		 * setsockopt() is ignored.
1523 		 */
1524 	}
1525 
1526 	/*
1527 	 * did the user specify an interface?
1528 	 * Applies to unicast, broadcast and multicast.
1529 	 */
1530 	if (moptions & MULTICAST_IF) {
1531 		struct ifaddrlist *al = NULL;		/* interface list */
1532 		struct ifaddrlist *my_if;
1533 		char errbuf[ERRBUFSIZE];
1534 		int num_ifs;
1535 		int num_src_ifs;		/* exclude down and loopback */
1536 		int i;
1537 
1538 		/* pull out the interface list */
1539 		num_ifs = ifaddrlist(&al, family, LIFC_UNDER_IPMP, errbuf);
1540 		if (num_ifs == -1) {
1541 			Fprintf(stderr, "%s: %s\n", progname, errbuf);
1542 			exit(EXIT_FAILURE);
1543 		}
1544 
1545 		/* filter out down and loopback interfaces */
1546 		num_src_ifs = 0;
1547 		for (i = 0; i < num_ifs; i++) {
1548 			if (!(al[i].flags & IFF_LOOPBACK) &&
1549 			    (al[i].flags & IFF_UP))
1550 				num_src_ifs++;
1551 		}
1552 
1553 		if (num_src_ifs == 0) {
1554 			Fprintf(stderr, "%s: can't find any %s interface\n",
1555 			    progname, (family == AF_INET) ? "IPv4" : "IPv6");
1556 
1557 			return (_B_FALSE);	/* failure */
1558 		}
1559 
1560 		/* locate the specified interface */
1561 		my_if = find_if(al, num_ifs);
1562 		if (my_if == NULL) {
1563 			Fprintf(stderr, "%s: %s is an invalid %s interface\n",
1564 			    progname, out_if.str,
1565 			    (family == AF_INET) ? "IPv4" : "IPv6");
1566 
1567 			return (_B_FALSE);
1568 		}
1569 
1570 		if (family == AF_INET) {
1571 			struct in_pktinfo pktinfo;
1572 
1573 			if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_IF,
1574 			    (char *)&my_if->addr.addr,
1575 			    sizeof (struct in_addr)) == -1) {
1576 				Fprintf(stderr, "%s: setsockopt "
1577 				    "IP_MULTICAST_IF %s\n", progname,
1578 				    strerror(errno));
1579 				exit(EXIT_FAILURE);
1580 			}
1581 			bzero(&pktinfo, sizeof (pktinfo));
1582 			pktinfo.ipi_ifindex = my_if->index;
1583 			if (setsockopt(send_sock, IPPROTO_IP, IP_PKTINFO,
1584 			    (char *)&pktinfo, sizeof (pktinfo)) == -1) {
1585 				Fprintf(stderr, "%s: setsockopt "
1586 				    "IP_PKTINFO %s\n", progname,
1587 				    strerror(errno));
1588 				exit(EXIT_FAILURE);
1589 			}
1590 		} else {
1591 			/*
1592 			 * the outgoing interface is set in set_ancillary_data()
1593 			 * function
1594 			 */
1595 			*if_index = my_if->index;
1596 		}
1597 
1598 		free(al);
1599 	}
1600 
1601 	if (settos && family == AF_INET) {
1602 		int_op = tos;
1603 		if (setsockopt(send_sock, IPPROTO_IP, IP_TOS, (char *)&int_op,
1604 		    sizeof (int_op)) == -1) {
1605 			Fprintf(stderr, "%s: setsockopt IP_TOS %s\n",
1606 			    progname, strerror(errno));
1607 			exit(EXIT_FAILURE);
1608 		}
1609 	}
1610 
1611 	/* We enable or disable to not depend on the kernel default */
1612 	if (family == AF_INET) {
1613 		if (setsockopt(send_sock, IPPROTO_IP, IP_DONTFRAG,
1614 		    (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1615 			Fprintf(stderr, "%s: setsockopt IP_DONTFRAG %s\n",
1616 			    progname, strerror(errno));
1617 			exit(EXIT_FAILURE);
1618 		}
1619 	} else {
1620 		if (setsockopt(send_sock, IPPROTO_IPV6, IPV6_DONTFRAG,
1621 		    (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1622 			Fprintf(stderr, "%s: setsockopt IPV6_DONTFRAG %s\n",
1623 			    progname, strerror(errno));
1624 			exit(EXIT_FAILURE);
1625 		}
1626 	}
1627 
1628 	/* receiving IPv6 extension headers in verbose mode */
1629 	if (verbose && family == AF_INET6) {
1630 		if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVHOPOPTS,
1631 		    (char *)&on, sizeof (on)) == -1) {
1632 			Fprintf(stderr, "%s: setsockopt IPV6_RECVHOPOPTS %s\n",
1633 			    progname, strerror(errno));
1634 			exit(EXIT_FAILURE);
1635 		}
1636 
1637 		if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
1638 		    (char *)&on, sizeof (on)) == -1) {
1639 			Fprintf(stderr, "%s: setsockopt IPV6_RECVDSTOPTS %s\n",
1640 			    progname, strerror(errno));
1641 			exit(EXIT_FAILURE);
1642 		}
1643 
1644 		if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVRTHDR,
1645 		    (char *)&on, sizeof (on)) == -1) {
1646 			Fprintf(stderr, "%s: setsockopt IPV6_RECVRTHDR %s\n",
1647 			    progname, strerror(errno));
1648 			exit(EXIT_FAILURE);
1649 		}
1650 	}
1651 
1652 	/* Ensure that timestamping is requested on the receive socket */
1653 	if (setsockopt(recv_sock, SOL_SOCKET, SO_TIMESTAMP,
1654 	    &on, sizeof (on)) == -1) {
1655 		Fprintf(stderr, "%s: warning: timing accuracy diminished -- "
1656 		    "setsockopt SO_TIMESTAMP failed %s", progname,
1657 		    strerror(errno));
1658 	}
1659 
1660 	*send_sockp = send_sock;
1661 	*recv_sockp = recv_sock;
1662 
1663 	/* successful */
1664 	return (_B_TRUE);
1665 }
1666 
1667 /*
1668  * Pull out the record containing all the info about the interface specified by
1669  * `out_if'. Skips interfaces which are down or loopback.
1670  */
1671 static struct ifaddrlist *
1672 find_if(struct ifaddrlist *al, int num_ifs)
1673 {
1674 	static struct ifaddrlist tmp_if;
1675 	boolean_t found;
1676 	int i;
1677 
1678 	i = 0;
1679 	found = _B_FALSE;
1680 
1681 	while (i < num_ifs && !found) {
1682 		tmp_if = al[i];
1683 
1684 		/* skip down or loopback interfaces */
1685 		if ((tmp_if.flags & IFF_LOOPBACK) || !(tmp_if.flags & IFF_UP)) {
1686 			i++;
1687 			continue;
1688 		}
1689 
1690 		/* the type of interface id is variable */
1691 		switch (out_if.id_type) {
1692 		case IF_INDEX:
1693 			if (out_if.id.index == tmp_if.index)
1694 				found = _B_TRUE;
1695 			break;
1696 
1697 		case IF_NAME:
1698 			if (strcmp(out_if.id.name, tmp_if.device) == 0)
1699 				found = _B_TRUE;
1700 			break;
1701 
1702 		case IF_ADDR:
1703 			if (out_if.id.addr.addr.s_addr ==
1704 			    tmp_if.addr.addr.s_addr) {
1705 				found = _B_TRUE;
1706 			}
1707 			break;
1708 
1709 		case IF_ADDR6:
1710 			if (IN6_ARE_ADDR_EQUAL(&out_if.id.addr.addr6,
1711 			    &tmp_if.addr.addr6)) {
1712 				found = _B_TRUE;
1713 			}
1714 			break;
1715 
1716 		default:
1717 			break;
1718 		}
1719 
1720 		i++;
1721 	}
1722 
1723 	if (found)
1724 		return (&tmp_if);
1725 	else
1726 		return (NULL);
1727 }
1728 
1729 /*
1730  * Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
1731  * send_scheduled_probe() to send next probe.
1732  */
1733 void
1734 sigalrm_handler(void)
1735 {
1736 	/*
1737 	 * If we've been told that we're done, the timer should be cancelled
1738 	 * and not rescheduled, just return.
1739 	 */
1740 	if (timer_done == _B_TRUE)
1741 		return;
1742 
1743 	/*
1744 	 * Guard against denial-of-service attacks. Make sure ping doesn't send
1745 	 * probes for every SIGALRM it receives in the case of errant SIGALRMs.
1746 	 * ping will ignore those which are received too soon (the smaller of
1747 	 * 0.5 sec and the ping interval, if in effect) after it sent the last
1748 	 * probe.  We use gethrtime() instead of gettimeofday() because the
1749 	 * latter is not linear and is prone to resetting or drifting.
1750 	 */
1751 	if ((gethrtime() - t_last_probe_sent) < mintime) {
1752 		return;
1753 	}
1754 	send_scheduled_probe();
1755 	schedule_sigalrm();
1756 }
1757 
1758 /*
1759  * Schedule next SIGALRM.
1760  */
1761 void
1762 schedule_sigalrm(void)
1763 {
1764 	int waittime;
1765 	struct itimerspec it;
1766 
1767 	bzero(&it, sizeof (struct itimerspec));
1768 	if (npackets == 0 ||
1769 	    current_targetaddr->num_sent < current_targetaddr->num_probes) {
1770 		it = interval;
1771 	} else {
1772 		if (current_targetaddr->got_reply) {
1773 			waittime = 2 * tmax / MICROSEC;
1774 			if (waittime == 0)
1775 				waittime = 1;
1776 		} else {
1777 			waittime = MAX_WAIT;
1778 		}
1779 		it.it_value.tv_sec = waittime;
1780 	}
1781 
1782 	if (timer_settime(timer, TIMER_RELTIME, &it, NULL) != 0) {
1783 		Fprintf(stderr, "%s: unexpected error updating time: %s\n",
1784 		    progname, strerror(errno));
1785 		exit(EXIT_FAILURE);
1786 	}
1787 }
1788 
1789 /*
1790  * Called by sigalrm_handler(), check_reply() or check_reply6(),
1791  * send_scheduled_probe() looks at the current_targetaddr and determines what
1792  * should be sent next and calls pinger().
1793  */
1794 void
1795 send_scheduled_probe()
1796 {
1797 	static struct msghdr msg6;
1798 	static boolean_t first_probe = _B_TRUE;
1799 	char tmp_buf[INET6_ADDRSTRLEN];
1800 
1801 	/*
1802 	 * We are about to move to next targetaddr if it's either we sent
1803 	 * all the probes, or somebody set the probing_done flag to
1804 	 * _B_TRUE prompting us to move on.
1805 	 */
1806 	if (current_targetaddr->num_sent == current_targetaddr->num_probes ||
1807 	    current_targetaddr->probing_done) {
1808 		/*
1809 		 * is this a dead target?
1810 		 */
1811 		if (!stats && !current_targetaddr->got_reply) {
1812 			if (!probe_all) {
1813 				Printf("no answer from %s\n", targethost);
1814 			} else {
1815 				Printf("no answer from %s(%s)\n", targethost,
1816 				    inet_ntop(current_targetaddr->family,
1817 				    &current_targetaddr->dst_addr,
1818 				    tmp_buf, sizeof (tmp_buf)));
1819 			}
1820 		}
1821 		/*
1822 		 * Before we move onto next item, let's do some clean up.
1823 		 */
1824 		current_targetaddr->got_reply = _B_FALSE;
1825 		current_targetaddr->probing_done = _B_FALSE;
1826 		/*
1827 		 * If this is probe-all without stats mode, then we need to
1828 		 * preserve this count. This is needed when we try to map an
1829 		 * icmp_seq to IP address. Otherwise, clear it.
1830 		 */
1831 		if (stats || !probe_all)
1832 			current_targetaddr->num_sent = 0;
1833 		nreceived_last_target = 0;
1834 
1835 		current_targetaddr = current_targetaddr->next;
1836 
1837 		/*
1838 		 * Did we reach the end of road?
1839 		 */
1840 		if (current_targetaddr == NULL) {
1841 			timer_done = _B_TRUE;
1842 			if (stats)
1843 				finish();
1844 			if (is_alive)
1845 				exit(EXIT_SUCCESS);
1846 			else
1847 				exit(EXIT_FAILURE);
1848 		} else {
1849 			/*
1850 			 * We use starting_seq_num for authenticating replies.
1851 			 * Each time we move to a new targetaddr, which has
1852 			 * a different target IP address, we update this field.
1853 			 */
1854 			current_targetaddr->starting_seq_num = use_udp ?
1855 			    dest_port : (ntransmitted % (MAX_ICMP_SEQ + 1));
1856 		}
1857 	}
1858 
1859 	if (current_targetaddr->family == AF_INET6) {
1860 		if (send_reply) {
1861 			/* sending back to ourself */
1862 			to6.sin6_addr = current_targetaddr->src_addr.addr6;
1863 		} else {
1864 			to6.sin6_addr = current_targetaddr->dst_addr.addr6;
1865 		}
1866 		to6.sin6_scope_id = current_targetaddr->dst_scope;
1867 
1868 		/*
1869 		 * Setting the ancillary data once is enough, if we are
1870 		 * not using source routing through target (-l/-S). In
1871 		 * case -l/-S used, the middle gateway will be the
1872 		 * IP address of the source, which can be different
1873 		 * for each target IP.
1874 		 */
1875 		if (first_probe ||
1876 		    (send_reply && current_targetaddr->num_sent == 0)) {
1877 			int scope = if_index;
1878 			if (scope != 0 && to6.sin6_scope_id != 0)
1879 				/*
1880 				 * don't bother setting scope in ancillary data
1881 				 * as sin6_scope_id will override it.
1882 				 */
1883 				scope = 0;
1884 
1885 			if (send_reply) {
1886 				/* target is the middle gateway now */
1887 				gw_IP_list6[num_gw].addr6 =
1888 				    current_targetaddr->dst_addr.addr6;
1889 			}
1890 			set_ancillary_data(&msg6, hoplimit, gw_IP_list6,
1891 			    eff_num_gw, scope);
1892 			first_probe = _B_FALSE;
1893 		}
1894 		pinger(send_sock6, (struct sockaddr *)&to6, &msg6, AF_INET6);
1895 	} else {
1896 		to.sin_addr = current_targetaddr->dst_addr.addr;
1897 		/*
1898 		 * Set IPv4 options when sending the first probe to a target
1899 		 * IP address. Some options change when the target address
1900 		 * changes.
1901 		 */
1902 		if (current_targetaddr->num_sent == 0) {
1903 			if (eff_num_gw > 0) {
1904 				gw_IP_list[num_gw].addr =
1905 				    current_targetaddr->dst_addr.addr;
1906 				/*
1907 				 * If send_reply, the target becomes the
1908 				 * middle gateway, sender becomes the last
1909 				 * gateway.
1910 				 */
1911 				if (send_reply) {
1912 					gw_IP_list[eff_num_gw].addr =
1913 					    current_targetaddr->src_addr.addr;
1914 				}
1915 			}
1916 			/*
1917 			 * In IPv4, if source routing is used, the target
1918 			 * address shows up as the last gateway, hence +1.
1919 			 */
1920 			set_IPv4_options(send_sock, gw_IP_list,
1921 			    (eff_num_gw > 0) ? eff_num_gw + 1 : 0,
1922 			    &current_targetaddr->src_addr.addr, &to.sin_addr);
1923 		}
1924 		pinger(send_sock, (struct sockaddr *)&to, NULL, AF_INET);
1925 	}
1926 
1927 	current_targetaddr->num_sent++;
1928 }
1929 
1930 /*
1931  * recv_icmp_packet()'s job is to listen to icmp packets and filter out
1932  * those ping is interested in.
1933  */
1934 static void
1935 recv_icmp_packet(struct addrinfo *ai_dst, int recv_sock6, int recv_sock,
1936     ushort_t udp_src_port6, ushort_t udp_src_port)
1937 {
1938 	struct msghdr in_msg;
1939 	struct iovec iov;
1940 	struct sockaddr_in6 from6;
1941 	fd_set fds;
1942 	int result;
1943 	int cc;
1944 	boolean_t always_true = _B_TRUE; /* lint doesn't like while(_B_TRUE) */
1945 
1946 	while (always_true) {
1947 		(void) FD_ZERO(&fds);
1948 		if (recv_sock6 != -1)
1949 			FD_SET(recv_sock6, &fds);
1950 		if (recv_sock != -1)
1951 			FD_SET(recv_sock, &fds);
1952 
1953 		result = select(MAX(recv_sock6, recv_sock) + 1, &fds,
1954 		    (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL);
1955 		if (result == -1) {
1956 			if (errno == EINTR) {
1957 				continue;
1958 			} else {
1959 				Fprintf(stderr, "%s: select %s\n", progname,
1960 				    strerror(errno));
1961 				exit(EXIT_FAILURE);
1962 			}
1963 		} else if (result > 0) {
1964 			in_msg.msg_name = &from6;
1965 			in_msg.msg_namelen = sizeof (from6);
1966 			iov.iov_base = in_pkt;
1967 			iov.iov_len = sizeof (in_pkt);
1968 			in_msg.msg_iov = &iov;
1969 			in_msg.msg_iovlen = 1;
1970 			in_msg.msg_control = ancillary_data;
1971 			in_msg.msg_controllen = sizeof (ancillary_data);
1972 
1973 			/* Do we have an ICMP6 packet waiting? */
1974 			if ((recv_sock6 != -1) &&
1975 			    (FD_ISSET(recv_sock6, &fds))) {
1976 				cc = recvmsg(recv_sock6, &in_msg, 0);
1977 				if (cc < 0) {
1978 					if (errno != EINTR) {
1979 						Fprintf(stderr,
1980 						    "%s: recvmsg %s\n",
1981 						    progname, strerror(errno));
1982 					}
1983 					continue;
1984 				} else if (cc > 0) {
1985 					check_reply6(ai_dst, &in_msg, cc,
1986 					    udp_src_port6);
1987 				}
1988 			}
1989 			/* Do we have an ICMP packet waiting? */
1990 			if ((recv_sock != -1) && (FD_ISSET(recv_sock, &fds))) {
1991 				cc = recvmsg(recv_sock, &in_msg, 0);
1992 				if (cc < 0) {
1993 					if (errno != EINTR) {
1994 						Fprintf(stderr,
1995 						    "%s: recvmsg %s\n",
1996 						    progname, strerror(errno));
1997 					}
1998 					continue;
1999 				} else if (cc > 0) {
2000 					check_reply(ai_dst, &in_msg, cc,
2001 					    udp_src_port);
2002 				}
2003 			}
2004 		}
2005 		/*
2006 		 * If we were probing last IP address of the target host and
2007 		 * received a reply for each probe sent to this address,
2008 		 * then we are done!
2009 		 */
2010 		if ((npackets > 0) && (current_targetaddr->next == NULL) &&
2011 		    (nreceived_last_target == npackets)) {
2012 			timer_done = _B_TRUE;
2013 			finish();
2014 		}
2015 	} /* infinite loop */
2016 }
2017 
2018 /*
2019  * Given a host (with possibly multiple IP addresses) and an IP address, this
2020  * function determines if this IP address is one of the host's addresses to
2021  * which we're sending probes. Used to determine if we are interested in a
2022  * packet.
2023  */
2024 boolean_t
2025 is_a_target(struct addrinfo *ai, union any_in_addr *addr)
2026 {
2027 	int num_addrs;
2028 	int i;
2029 	struct addrinfo *aip;
2030 
2031 	aip = ai;
2032 	if (probe_all)
2033 		num_addrs = num_v4 + num_v6;
2034 	else
2035 		num_addrs = 1;
2036 	for (i = 0; i < num_addrs && aip != NULL; i++) {
2037 		if (aip->ai_family == AF_INET6) {
2038 			/* LINTED E_BAD_PTR_CAST_ALIGN */
2039 			if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)
2040 			    aip->ai_addr)->sin6_addr, &addr->addr6))
2041 				return (_B_TRUE);
2042 		} else {
2043 			/* LINTED E_BAD_PTR_CAST_ALIGN */
2044 			if (((struct sockaddr_in *)
2045 			    aip->ai_addr)->sin_addr.s_addr == addr->addr.s_addr)
2046 				return (_B_TRUE);
2047 		}
2048 	}
2049 
2050 	return (_B_FALSE);
2051 }
2052 
2053 /*
2054  * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
2055  * will be added on by the kernel.  The ID field is our UNIX process ID,
2056  * and the sequence number is an ascending integer.  The first 8 bytes
2057  * of the data portion are used to hold a UNIX "timeval" struct in network
2058  * byte-order, to compute the round-trip time.
2059  */
2060 static void
2061 pinger(int send_sock, struct sockaddr *whereto, struct msghdr *msg6,
2062     int family)
2063 {
2064 	static uint64_t out_pkt_buf[(IP_MAXPACKET + 1) / 8];
2065 	uchar_t *out_pkt = (uchar_t *)&out_pkt_buf;
2066 	/* LINTED E_BAD_PTR_CAST_ALIGN */
2067 	struct icmp *icp = (struct icmp *)out_pkt;
2068 	/* LINTED E_BAD_PTR_CAST_ALIGN */
2069 	struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)whereto;
2070 	/* LINTED E_BAD_PTR_CAST_ALIGN */
2071 	struct sockaddr_in *to = (struct sockaddr_in *)whereto;
2072 	struct timeval *tp;
2073 	struct timeval t_snd;
2074 	uchar_t *datap;
2075 	struct iovec iov;
2076 	int start = 0;
2077 	int cc;
2078 	int i;
2079 
2080 	/* using UDP? */
2081 	if (use_udp) {
2082 		cc = datalen;
2083 
2084 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2085 		tp = (struct timeval *)out_pkt;
2086 		datap = &out_pkt[sizeof (struct timeval)];
2087 
2088 		/*
2089 		 * This sets the port whether we are handling a v4 or v6
2090 		 * sockaddr structure.
2091 		 */
2092 		to->sin_port = htons(dest_port);
2093 
2094 		dest_port = (dest_port + 1) % (MAX_PORT + 1);
2095 		ntransmitted++;
2096 	} else {	/* using ICMP */
2097 		cc = datalen + ICMP_MINLEN;
2098 
2099 		if (family == AF_INET6) {
2100 			icp->icmp_type = send_reply ?
2101 			    ICMP6_ECHO_REPLY : ICMP6_ECHO_REQUEST;
2102 		} else if (use_icmp_ts) {	/* family is AF_INET */
2103 			icp->icmp_type = send_reply ?
2104 			    ICMP_TSTAMPREPLY : ICMP_TSTAMP;
2105 		} else {
2106 			icp->icmp_type = send_reply ?
2107 			    ICMP_ECHOREPLY : ICMP_ECHO;
2108 		}
2109 
2110 		icp->icmp_code = 0;
2111 		icp->icmp_cksum = 0;
2112 		icp->icmp_seq = htons(ntransmitted++ % (MAX_ICMP_SEQ + 1));
2113 		if (icp->icmp_seq == 0)
2114 			num_wraps++;
2115 		icp->icmp_id = htons(ident);		/* ID */
2116 
2117 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2118 		tp = (struct timeval *)&out_pkt[ICMP_MINLEN];
2119 		datap = &out_pkt[ICMP_MINLEN + sizeof (struct timeval)];
2120 	}
2121 
2122 	start = sizeof (struct timeval);	/* skip for time */
2123 
2124 	(void) gettimeofday(&t_snd, (struct timezone *)NULL);
2125 
2126 	/* if packet is big enough to store timeval OR ... */
2127 	if ((datalen >= sizeof (struct timeval)) ||
2128 	    (family == AF_INET && use_icmp_ts))
2129 		*tp = t_snd;
2130 
2131 	if (family == AF_INET && use_icmp_ts) {
2132 		start = sizeof (struct id_ts);	/* skip for ICMP timestamps */
2133 		/* Number of milliseconds since midnight */
2134 		icp->icmp_otime = htonl((tp->tv_sec % (24*60*60)) * 1000 +
2135 		    tp->tv_usec / 1000);
2136 	}
2137 
2138 	for (i = start; i < datalen; i++)
2139 		*datap++ = i;
2140 
2141 	if (family == AF_INET) {
2142 		if (!use_udp)
2143 			icp->icmp_cksum = in_cksum((ushort_t *)icp, cc);
2144 
2145 		i = sendto(send_sock, (char *)out_pkt, cc, 0, whereto,
2146 		    sizeof (struct sockaddr_in));
2147 	} else {
2148 		/*
2149 		 * Fill in the rest of the msghdr structure. msg_control is set
2150 		 * in set_ancillary_data().
2151 		 */
2152 		msg6->msg_name = to6;
2153 		msg6->msg_namelen = sizeof (struct sockaddr_in6);
2154 
2155 		iov.iov_base = out_pkt;
2156 		iov.iov_len = cc;
2157 
2158 		msg6->msg_iov = &iov;
2159 		msg6->msg_iovlen = 1;
2160 
2161 		i = sendmsg(send_sock, msg6, 0);
2162 	}
2163 
2164 	/* This is a more precise time (right after we send the packet) */
2165 	t_last_probe_sent = gethrtime();
2166 
2167 	if (i < 0 || i != cc)  {
2168 		if (i < 0) {
2169 			Fprintf(stderr, "%s: sendto %s\n", progname,
2170 			    strerror(errno));
2171 			if (!stats)
2172 				exit(EXIT_FAILURE);
2173 		}
2174 		Printf("ping: wrote %s %d chars, ret=%d\n",
2175 		    targethost, cc, i);
2176 		(void) fflush(stdout);
2177 	}
2178 }
2179 
2180 /*
2181  * Return a hostname for the given IP address.
2182  */
2183 char *
2184 pr_name(char *addr, int family)
2185 {
2186 	struct sockaddr_in sin;
2187 	struct sockaddr_in6 sin6;
2188 	struct sockaddr *sa;
2189 
2190 	switch (family) {
2191 	case AF_INET:
2192 		(void) memset(&sin, 0, sizeof (sin));
2193 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2194 		sin.sin_addr = *(struct in_addr *)addr;
2195 		sin.sin_port = 0;
2196 		sa = (struct sockaddr *)&sin;
2197 		break;
2198 	case AF_INET6:
2199 		(void) memset(&sin6, 0, sizeof (sin6));
2200 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2201 		sin6.sin6_addr = *(struct in6_addr *)addr;
2202 		sin6.sin6_port = 0;
2203 		sa = (struct sockaddr *)&sin6;
2204 		break;
2205 	default:
2206 		sa = (struct sockaddr *)&sin6;
2207 		break;
2208 	}
2209 	sa->sa_family = family;
2210 	return (pr_name_sa(sa));
2211 }
2212 
2213 char *
2214 pr_name_sa(const struct sockaddr *sa)
2215 {
2216 	const struct sockaddr_in *sin = (struct sockaddr_in *)sa;
2217 	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
2218 	int family = sa->sa_family;
2219 	static struct in6_addr prev_addr = IN6ADDR_ANY_INIT;
2220 	static int prev_scope = 0;
2221 	char *cp;
2222 	char abuf[INET6_ADDRSTRLEN];
2223 	static char buf[NI_MAXHOST + INET6_ADDRSTRLEN + 3];
2224 	uint_t slen, alen, hlen;
2225 	char *addr;
2226 	int scope;
2227 
2228 	switch (family) {
2229 	case AF_INET:
2230 		slen = sizeof (struct sockaddr_in);
2231 		alen = sizeof (struct in_addr);
2232 		addr = (char *)&sin->sin_addr;
2233 		scope = 0;
2234 		break;
2235 	case AF_INET6:
2236 		slen = sizeof (struct sockaddr_in6);
2237 		alen = sizeof (struct in6_addr);
2238 		addr = (char *)&sin6->sin6_addr;
2239 		scope = sin6->sin6_scope_id;
2240 		break;
2241 	default:
2242 		(void) snprintf(buf, sizeof (buf), "<invalid address family>");
2243 		return (buf);
2244 	}
2245 
2246 	/* compare with the buffered (previous) lookup */
2247 	if (scope != prev_scope || memcmp(addr, &prev_addr, alen) != 0) {
2248 		int flags = (nflag) ? NI_NUMERICHOST : NI_NAMEREQD;
2249 		mutex_enter(&ns_lock);
2250 		ns_active = _B_TRUE;
2251 		ns_starttime = gethrtime();
2252 		mutex_exit(&ns_lock);
2253 		if (getnameinfo(sa, slen, buf, sizeof (buf),
2254 		    NULL, 0, flags) != 0) {
2255 			/* getnameinfo() failed; return just the address */
2256 			if (getnameinfo(sa, slen, buf, sizeof (buf),
2257 			    NULL, 0, NI_NUMERICHOST) != 0) {
2258 				buf[0] = 0;
2259 			}
2260 		} else if (!nflag) {
2261 			/* append numeric address to hostname string */
2262 			hlen = strlen(buf);
2263 			cp = (char *)(buf + hlen);
2264 			(void) snprintf(cp, sizeof (buf) - hlen, " (%s)",
2265 			    inet_ntop(family, (const void *)addr, abuf,
2266 			    sizeof (abuf)));
2267 		}
2268 		mutex_enter(&ns_lock);
2269 		ns_active = _B_FALSE;
2270 		mutex_exit(&ns_lock);
2271 
2272 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2273 		prev_addr = *(struct in6_addr *)addr;
2274 		prev_scope = scope;
2275 	}
2276 	return (buf);
2277 }
2278 
2279 char *
2280 pr_name4(const struct sockaddr_in *sin)
2281 {
2282 	return (pr_name_sa((const struct sockaddr *)sin));
2283 }
2284 
2285 char *
2286 pr_name6(const struct sockaddr_in6 *sin6)
2287 {
2288 	return (pr_name_sa((const struct sockaddr *)sin6));
2289 }
2290 
2291 /*
2292  * Return the protocol string, given its protocol number.
2293  */
2294 char *
2295 pr_protocol(int prot)
2296 {
2297 	static char buf[20];
2298 
2299 	switch (prot) {
2300 	case IPPROTO_ICMPV6:
2301 		(void) strlcpy(buf, "icmp6", sizeof (buf));
2302 		break;
2303 
2304 	case IPPROTO_ICMP:
2305 		(void) strlcpy(buf, "icmp", sizeof (buf));
2306 		break;
2307 
2308 	case IPPROTO_TCP:
2309 		(void) strlcpy(buf, "tcp", sizeof (buf));
2310 		break;
2311 
2312 	case IPPROTO_UDP:
2313 		(void) strlcpy(buf, "udp", sizeof (buf));
2314 		break;
2315 
2316 	default:
2317 		(void) snprintf(buf, sizeof (buf), "prot %d", prot);
2318 		break;
2319 	}
2320 
2321 	return (buf);
2322 }
2323 
2324 char *
2325 pr_if(int ifindex)
2326 {
2327 	static struct ifaddrlist *al = NULL;
2328 	static int count = 0;
2329 	static char errbuf[ERRBUFSIZE];
2330 	int i;
2331 
2332 	if (al == NULL) {
2333 		count = ifaddrlist(&al, AF_INET6, 0, errbuf);
2334 		if (count < 0)
2335 			count = 0;
2336 	}
2337 	for (i = 0; i < count; i++) {
2338 		if (al[i].index == ifindex)
2339 			return (al[i].device);
2340 	}
2341 	(void) sprintf(errbuf, "%d", ifindex);
2342 	return (errbuf);
2343 }
2344 
2345 /*
2346  * Checks if value is between seq_begin and seq_begin+seq_len. Note that
2347  * sequence numbers wrap around after MAX_ICMP_SEQ (== MAX_PORT).
2348  */
2349 boolean_t
2350 seq_match(ushort_t seq_begin, int seq_len, ushort_t value)
2351 {
2352 	/*
2353 	 * If seq_len is too big, like some value greater than MAX_ICMP_SEQ/2,
2354 	 * truncate it down to MAX_ICMP_SEQ/2. We are not going to accept any
2355 	 * reply which come 83hr later!
2356 	 */
2357 	if (seq_len > MAX_ICMP_SEQ / 2) {
2358 		seq_begin = (seq_begin + seq_len - MAX_ICMP_SEQ / 2) %
2359 		    (MAX_ICMP_SEQ + 1);
2360 		seq_len = MAX_ICMP_SEQ / 2;
2361 	}
2362 
2363 	if (PINGSEQ_LEQ(seq_begin, value) &&
2364 	    PINGSEQ_LEQ(value, (seq_begin + seq_len - 1) % (MAX_ICMP_SEQ + 1)))
2365 		return (_B_TRUE);
2366 	else
2367 		return (_B_FALSE);
2368 }
2369 
2370 /*
2371  * For a given icmp_seq, find which destination address we must have sent this
2372  * to.
2373  */
2374 void
2375 find_dstaddr(ushort_t icmpseq, union any_in_addr *ipaddr)
2376 {
2377 	struct targetaddr *target = targetaddr_list;
2378 	int real_seq;
2379 	int targetaddr_index;
2380 	int real_npackets;
2381 	int i;
2382 
2383 	ipaddr->addr6 = in6addr_any;
2384 
2385 	/*
2386 	 * If this is probe_all and not stats, then the number of probes sent to
2387 	 * each IP address may be different (remember, we stop sending to one IP
2388 	 * address as soon as it replies). They are stored in target->num_sent
2389 	 * field. Since we don't wrap around the list (!stats), they are also
2390 	 * preserved.
2391 	 */
2392 	if (probe_all && !stats) {
2393 		do {
2394 			if (seq_match(target->starting_seq_num,
2395 			    target->num_sent, icmpseq)) {
2396 				ipaddr->addr6 = target->dst_addr.addr6;
2397 				/*
2398 				 * We are not immediately return()ing here.
2399 				 * Because of wrapping, we might find another
2400 				 * match later, which is more likely to be the
2401 				 * real one.
2402 				 */
2403 			}
2404 			target = target->next;
2405 		} while (target != NULL);
2406 	} else {
2407 		/*
2408 		 * Find the absolute (non-wrapped) seq number within the last
2409 		 * 64K
2410 		 */
2411 		if (icmpseq < (ntransmitted % (MAX_ICMP_SEQ + 1))) {
2412 			real_seq = num_wraps * (MAX_ICMP_SEQ + 1) + icmpseq;
2413 		} else {
2414 			real_seq = (num_wraps - 1) * (MAX_ICMP_SEQ + 1) +
2415 			    icmpseq;
2416 		}
2417 
2418 		/* Make sure it's non-negative */
2419 		if (real_seq < 0)
2420 			return;
2421 		real_npackets = (npackets == 0) ? 1 : npackets;
2422 
2423 		/*
2424 		 * We sent npackets many packets to each of those
2425 		 * num_targetaddrs many IP addresses.
2426 		 */
2427 		targetaddr_index =
2428 		    (real_seq % (num_targetaddrs * real_npackets)) /
2429 		    real_npackets;
2430 		for (i = 0; i < targetaddr_index; i++)
2431 			target = target->next;
2432 		ipaddr->addr6 = target->dst_addr.addr6;
2433 	}
2434 }
2435 
2436 /*
2437  * Checksum routine for Internet Protocol family headers (C Version)
2438  */
2439 static ushort_t
2440 in_cksum(ushort_t *addr, int len)
2441 {
2442 	int nleft = len;
2443 	ushort_t *w = addr;
2444 	ushort_t answer;
2445 	ushort_t odd_byte = 0;
2446 	int sum = 0;
2447 
2448 	/*
2449 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
2450 	 *  we add sequential 16 bit words to it, and at the end, fold
2451 	 *  back all the carry bits from the top 16 bits into the lower
2452 	 *  16 bits.
2453 	 */
2454 	while (nleft > 1) {
2455 		sum += *w++;
2456 		nleft -= 2;
2457 	}
2458 
2459 	/* mop up an odd byte, if necessary */
2460 	if (nleft == 1) {
2461 		*(uchar_t *)(&odd_byte) = *(uchar_t *)w;
2462 		sum += odd_byte;
2463 	}
2464 
2465 	/*
2466 	 * add back carry outs from top 16 bits to low 16 bits
2467 	 */
2468 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
2469 	sum += (sum >> 16);			/* add carry */
2470 	answer = ~sum;				/* truncate to 16 bits */
2471 	return (answer);
2472 }
2473 
2474 /*
2475  * Subtract 2 timeval structs:  out = out - in.
2476  * Out is assumed to be >= in.
2477  */
2478 void
2479 tvsub(struct timeval *out, struct timeval *in)
2480 {
2481 	if ((out->tv_usec -= in->tv_usec) < 0) {
2482 		out->tv_sec--;
2483 		out->tv_usec += 1000000;
2484 	}
2485 	out->tv_sec -= in->tv_sec;
2486 }
2487 
2488 /*
2489  * Print out statistics, and give up.
2490  * Heavily buffered STDIO is used here, so that all the statistics
2491  * will be written with 1 sys-write call.  This is nice when more
2492  * than one copy of the program is running on a terminal;  it prevents
2493  * the statistics output from becoming intermingled.
2494  */
2495 static void
2496 finish()
2497 {
2498 	Printf("\n----%s PING Statistics----\n", targethost);
2499 	Printf("%d packets transmitted, ", ntransmitted);
2500 	Printf("%d packets received, ", nreceived);
2501 	if (ntransmitted) {
2502 		if (nreceived <= ntransmitted) {
2503 			Printf("%d%% packet loss",
2504 			    (int)(((ntransmitted-nreceived)*100) /
2505 			    ntransmitted));
2506 		} else {
2507 			Printf("%.2f times amplification",
2508 			    (double)nreceived / (double)ntransmitted);
2509 		}
2510 	}
2511 	(void) putchar('\n');
2512 
2513 	/* if packet is big enough to store timeval AND ... */
2514 	if ((datalen >= sizeof (struct timeval)) && (nreceived > 0)) {
2515 		double mean = (double)tsum / nreceived;
2516 		double smean = (double)tsum2 / nreceived;
2517 		double sd =
2518 		    sqrt(((smean - mean*mean) * nreceived) / (nreceived-1));
2519 
2520 		Printf("round-trip (ms)  min/avg/max/stddev = "
2521 		    TIMEFORMAT "/" TIMEFORMAT "/"
2522 		    TIMEFORMAT "/" TIMEFORMAT "\n",
2523 		    (double)tmin / 1000, mean / 1000,
2524 		    (double)tmax / 1000, sd / 1000);
2525 	}
2526 	(void) fflush(stdout);
2527 
2528 	exit(is_alive ? EXIT_SUCCESS : EXIT_FAILURE);
2529 }
2530 
2531 /*
2532  * print the usage line
2533  */
2534 static void
2535 usage(char *cmdname)
2536 {
2537 	Fprintf(stderr, "usage: %s host [timeout]\n", cmdname);
2538 	Fprintf(stderr,
2539 /* CSTYLED */
2540 "usage: %s -s [-l | -U] [-abdDLnRrv] [-A addr_family] [-c traffic_class]\n\t"
2541 "[-g gateway [-g gateway ...]] [-N nexthop] [-F flow_label] [-I interval]\n\t"
2542 "[-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]\n",
2543 	    cmdname);
2544 }
2545 
2546 /*
2547  * Parse integer argument; exit with an error if it's not a number.
2548  * Now it also accepts hex. values.
2549  */
2550 static int
2551 int_arg(char *s, char *what)
2552 {
2553 	char *cp;
2554 	char *ep;
2555 	int num;
2556 
2557 	errno = 0;
2558 	if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
2559 		cp = s + 2;
2560 		num = (int)strtol(cp, &ep, 16);
2561 	} else {
2562 		num = (int)strtol(s, &ep, 10);
2563 	}
2564 
2565 	if (errno || *ep != '\0' || num < 0) {
2566 		Fprintf(stderr, "%s: bad %s: %s\n", progname, what, s);
2567 		exit(EXIT_FAILURE);
2568 	}
2569 
2570 	return (num);
2571 }
2572 
2573 /*
2574  * Parse the interval into a itimerspec. The interval used to originally be
2575  * parsed as an integer argument. That means that one used to be able to specify
2576  * an interval in hex. The strtod() family honors that at times, with strtod
2577  * sometimes doing so depending on the compilation environment and strtof() and
2578  * srtold() always doing that. To facilitiate that and not worry about a
2579  * careless Makefile change breaking us, we instead just use strtold here, even
2580  * though we really don't need the precision.
2581  */
2582 static void
2583 parse_interval(const char *s)
2584 {
2585 	long double val;
2586 	char *end;
2587 
2588 	errno = 0;
2589 	val = strtold(s, &end);
2590 	if (errno != 0 || *end != '\0') {
2591 		Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2592 		exit(EXIT_FAILURE);
2593 	}
2594 
2595 	/*
2596 	 * Check values that we know are going to be bad. Anything greater than
2597 	 * INT_MAX, anything less than 0, look for specific NaNs. Also, clamp
2598 	 * the value at 0.01 seconds.
2599 	 */
2600 	if (val == NAN || val <= 0.0 || val >= INT_MAX) {
2601 		Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2602 		exit(EXIT_FAILURE);
2603 	}
2604 
2605 	if (val < 0.01L) {
2606 		Fprintf(stderr, "%s: interval too small: %Lf\n", progname, val);
2607 		exit(EXIT_FAILURE);
2608 	}
2609 
2610 	interval.it_value.tv_sec = (long)val;
2611 	interval.it_value.tv_nsec = (long)((val - interval.it_value.tv_sec) *
2612 	    NANOSEC);
2613 
2614 	if (interval.it_value.tv_sec == 0 &&
2615 	    interval.it_value.tv_nsec < mintime) {
2616 		mintime = interval.it_value.tv_nsec;
2617 	}
2618 }
2619 
2620 /*
2621  * We should have an SO_TIMESTAMP message for this socket to indicate
2622  * the actual time that the message took. If we don't we'll fall back to
2623  * gettimeofday(); however, that can cause any delays due to DNS
2624  * resolution and the like to end up wreaking havoc on us.
2625  */
2626 void
2627 ping_gettime(struct msghdr *msg, struct timeval *tv)
2628 {
2629 	struct cmsghdr *cmsg;
2630 
2631 	for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
2632 	    cmsg = CMSG_NXTHDR(msg, cmsg)) {
2633 		if (cmsg->cmsg_level == SOL_SOCKET &&
2634 		    cmsg->cmsg_type == SO_TIMESTAMP &&
2635 		    cmsg->cmsg_len == CMSG_LEN(sizeof (*tv))) {
2636 			bcopy(CMSG_DATA(cmsg), tv, sizeof (*tv));
2637 			return;
2638 		}
2639 	}
2640 
2641 	(void) gettimeofday(tv, (struct timezone *)NULL);
2642 }
2643 
2644 /*
2645  * The purpose of this thread is to try and inform a user that we're blocked
2646  * doing name lookups. For various reasons, ping has to try and look up the IP
2647  * addresses it receives via name services unless the -n flag is specified. The
2648  * irony of this is that when trying to use ping to actually diagnose a broken
2649  * network, name services are unlikely to be available and that will result in a
2650  * lot of confusion as to why pings seem like they're not working. As such, we
2651  * basically wake up every 2 seconds and check whether or not we've hit such a
2652  * condition where we should inform the user via stderr.
2653  *
2654  * Once they've been informed, we do not inform them again until approximately a
2655  * minute of time has passed, in case that things are working intermittently.
2656  */
2657 /*ARGSUSED*/
2658 static void *
2659 ns_warning_thr(void *unused)
2660 {
2661 	for (;;) {
2662 		hrtime_t now;
2663 
2664 		(void) sleep(ns_sleeptime);
2665 		now = gethrtime();
2666 		mutex_enter(&ns_lock);
2667 		if (ns_active == _B_TRUE &&
2668 		    now - ns_starttime >= ns_warntime * NANOSEC) {
2669 			Fprintf(stderr, "%s: warning: ICMP responses "
2670 			    "received, but name service lookups are "
2671 			    "taking a while. Use ping -n to disable "
2672 			    "name service lookups.\n",
2673 			    progname);
2674 			mutex_exit(&ns_lock);
2675 			return (NULL);
2676 		}
2677 		mutex_exit(&ns_lock);
2678 	}
2679 
2680 	/* LINTED: E_STMT_NOT_REACHED */
2681 	return (NULL);
2682 }
2683