xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
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  */
43 
44 #include <assert.h>
45 #include <stdio.h>
46 #include <strings.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <signal.h>
51 #include <limits.h>
52 #include <math.h>
53 #include <locale.h>
54 #include <thread.h>
55 #include <synch.h>
56 
57 #include <sys/time.h>
58 #include <sys/param.h>
59 #include <sys/socket.h>
60 #include <sys/sockio.h>
61 #include <sys/stropts.h>
62 #include <sys/file.h>
63 #include <sys/sysmacros.h>
64 #include <sys/debug.h>
65 
66 #include <arpa/inet.h>
67 #include <net/if.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>
76 #include <netdb.h>
77 #include <stdlib.h>
78 #include <priv_utils.h>
79 
80 #include <libinetutil.h>
81 #include "ping.h"
82 
83 /*
84  * This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
85  * TCP's SEQ_LEQ macro.
86  */
87 #define	PINGSEQ_LEQ(a, b)	((int16_t)((a)-(b)) <= 0)
88 
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 */
93 
94 #define	TIMEOUT			20	/* default timeout value */
95 #define	DEFAULT_DATALEN		56
96 
97 #define	MULTICAST_NOLOOP	1	/* multicast options */
98 #define	MULTICAST_TTL		2
99 #define	MULTICAST_IF		4
100 
101 #define	IF_INDEX		0	/* types of -i argument */
102 #define	IF_NAME			1
103 #define	IF_ADDR			2
104 #define	IF_ADDR6		3
105 
106 #ifdef BSD
107 #define	setbuf(s, b)	setlinebuf((s))
108 #endif /* BSD */
109 
110 
111 /* interface identification */
112 union if_id {
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) */
116 };
117 
118 /* stores the interface supplied by the user */
119 struct if_entry {
120 	char *str;		/* unresolved, string input */
121 	int id_type;		/* type of ID (index, name, addr, addr6) */
122 	union if_id id;		/* ID */
123 };
124 
125 char *progname;
126 char *targethost;
127 char *nexthop;
128 
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 */
180 
181 /*
182  * Globals for our name services warning. See ns_warning_thr() for more on why
183  * this exists.
184  */
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 
191 /*
192  * This buffer stores the received packets. Currently it needs to be 32 bit
193  * aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
194  * alignment now.
195  */
196 static uint64_t in_pkt[(IP_MAXPACKET + 1)/8];
197 
198 /* Used to store the ancillary data that comes with the received packets */
199 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
200 
201 static int ntransmitted;	/* number of packet sent to single IP address */
202 int nreceived;			/* # of packets we got back from target host */
203 int nreceived_last_target;	/* received from last target IP */
204 /*
205  * These are used for statistics. tmin is initialized to maximum longint value.
206  * The max value is also used for timeouts.   All times are in microseconds.
207  */
208 long long tmin = LLONG_MAX;
209 long long tmax;
210 int64_t tsum;			/* sum of all times, for doing average */
211 int64_t tsum2;			/* sum of squared times, for std. dev. */
212 
213 static struct targetaddr *build_targetaddr_list(struct addrinfo *,
214     union any_in_addr *);
215 extern void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t);
216 extern void check_reply6(struct addrinfo *, struct msghdr *, int, ushort_t);
217 static struct targetaddr *create_targetaddr_item(int, union any_in_addr *,
218     union any_in_addr *);
219 void find_dstaddr(ushort_t, union any_in_addr *);
220 static struct ifaddrlist *find_if(struct ifaddrlist *, int);
221 static void finish();
222 static void get_gwaddrs(char *[], int, union any_in_addr *,
223     union any_in_addr *, int *, int *);
224 static void get_hostinfo(char *, int, struct addrinfo **);
225 static ushort_t in_cksum(ushort_t *, int);
226 static int int_arg(char *s, char *what);
227 boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
228 static void mirror_gws(union any_in_addr *, int);
229 static void *ns_warning_thr(void *);
230 static void parse_interval(char *s);
231 static void pinger(int, struct sockaddr *, struct msghdr *, int);
232 char *pr_name(char *, int);
233 char *pr_protocol(int);
234 static void print_unknown_host_msg(const char *, const char *);
235 static void recv_icmp_packet(struct addrinfo *, int, int, ushort_t, ushort_t);
236 static void resolve_nodes(struct addrinfo **, struct addrinfo **,
237     union any_in_addr **);
238 void schedule_sigalrm();
239 static void select_all_src_addrs(union any_in_addr **, struct addrinfo *,
240     union any_in_addr *, union any_in_addr *);
241 static void select_src_addr(union any_in_addr *, int, union any_in_addr *);
242 void send_scheduled_probe();
243 boolean_t seq_match(ushort_t, int, ushort_t);
244 extern void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int,
245     uint_t);
246 extern void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *,
247     struct in_addr *);
248 static void set_nexthop(int, struct addrinfo *, int);
249 static boolean_t setup_socket(int, int *, int *, int *, ushort_t *,
250     struct addrinfo *);
251 void sigalrm_handler();
252 void tvsub(struct timeval *, struct timeval *);
253 static void usage(char *);
254 
255 /*
256  * main()
257  */
258 int
259 main(int argc, char *argv[])
260 {
261 	struct addrinfo	*ai_dst = NULL;		/* addrinfo host list */
262 	struct addrinfo	*ai_nexthop = NULL;		/* addrinfo nexthop */
263 	union any_in_addr *src_addr_list = NULL;	/* src addrs to use */
264 	int recv_sock = -1;				/* receive sockets */
265 	int recv_sock6 = -1;
266 	ushort_t udp_src_port;			/* src ports for UDP probes */
267 	ushort_t udp_src_port6;			/* used to identify replies */
268 	uint_t flowinfo = 0;
269 	uint_t class = 0;
270 	char abuf[INET6_ADDRSTRLEN];
271 	int c;
272 	int i;
273 	boolean_t has_sys_ip_config;
274 
275 	progname = argv[0];
276 
277 	(void) setlocale(LC_ALL, "");
278 
279 	/*
280 	 * This program needs the net_icmpaccess privilege for creating
281 	 * raw ICMP sockets.  It needs sys_ip_config for using the
282 	 * IP_NEXTHOP socket option (IPv4 only).  We'll fail
283 	 * on the socket call and report the error there when we have
284 	 * insufficient privileges.
285 	 *
286 	 * Shared-IP zones don't have the sys_ip_config privilege, so
287 	 * we need to check for it in our limit set before trying
288 	 * to set it.
289 	 */
290 	has_sys_ip_config = priv_ineffect(PRIV_SYS_IP_CONFIG);
291 
292 	(void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
293 	    has_sys_ip_config ? PRIV_SYS_IP_CONFIG : (char *)NULL,
294 	    (char *)NULL);
295 
296 	setbuf(stdout, (char *)0);
297 
298 	while ((c = getopt(argc, argv,
299 	    "abA:c:dDF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
300 		switch ((char)c) {
301 		case 'A':
302 			if (strcmp(optarg, "inet") == 0) {
303 				family_input = AF_INET;
304 			} else if (strcmp(optarg, "inet6") == 0) {
305 				family_input = AF_INET6;
306 			} else {
307 				Fprintf(stderr,
308 				    "%s: unknown address family %s\n",
309 				    progname, optarg);
310 				exit(EXIT_FAILURE);
311 			}
312 			break;
313 
314 		case 'a':
315 			probe_all = _B_TRUE;
316 			break;
317 
318 		case 'c':
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);
323 				exit(EXIT_FAILURE);
324 			}
325 			class = (uint_t)i;
326 			break;
327 
328 		case 'd':
329 			options |= SO_DEBUG;
330 			break;
331 
332 		case 'D':
333 			dontfrag = 1;
334 			break;
335 
336 		case 'b':
337 			bypass = _B_TRUE;
338 			break;
339 
340 		case 'F':
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);
345 				exit(EXIT_FAILURE);
346 			}
347 			flowinfo = (uint_t)i;
348 			break;
349 
350 		case 'I':
351 			stats = _B_TRUE;
352 			parse_interval(optarg);
353 			break;
354 
355 		case 'i':
356 			/*
357 			 * this can accept interface index, interface name, and
358 			 * address configured on the interface
359 			 */
360 			moptions |= MULTICAST_IF;
361 			out_if.str = optarg;
362 
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;
370 				out_if.id.index = 0;
371 			} else if ((out_if.id.index = atoi(optarg)) != 0) {
372 				out_if.id_type = IF_INDEX;
373 			} else {
374 				out_if.id.name = optarg;
375 				out_if.id_type = IF_NAME;
376 			}
377 			break;
378 
379 		case 'L':
380 			moptions |= MULTICAST_NOLOOP;
381 			break;
382 
383 		case 'l':
384 			send_reply = _B_TRUE;
385 			strict = _B_FALSE;
386 			break;
387 
388 		case 'n':
389 			nflag = _B_TRUE;
390 			break;
391 
392 		case 'P':
393 			settos = _B_TRUE;
394 			i = int_arg(optarg, "type-of-service");
395 			if (i > MAX_TOS) {
396 				Fprintf(stderr, "%s: tos value %d out of "
397 				    "range\n", progname, i);
398 				exit(EXIT_FAILURE);
399 			}
400 			tos = (ushort_t)i;
401 			break;
402 
403 		case 'p':
404 			i = int_arg(optarg, "port number");
405 			if (i > MAX_PORT) {
406 				Fprintf(stderr, "%s: port number %d out of "
407 				    "range\n", progname, i);
408 				exit(EXIT_FAILURE);
409 			}
410 			dest_port = (ushort_t)i;
411 			break;
412 
413 		case 'r':
414 			options |= SO_DONTROUTE;
415 			break;
416 
417 		case 'R':
418 			rr_option = _B_TRUE;
419 			break;
420 
421 		case 'S':
422 			send_reply = _B_TRUE;
423 			strict = _B_TRUE;
424 			break;
425 
426 		case 's':
427 			stats = _B_TRUE;
428 			break;
429 
430 		case 'T':
431 			ts_option = _B_TRUE;
432 			break;
433 
434 		case 't':
435 			moptions |= MULTICAST_TTL;
436 			hoplimit = int_arg(optarg, "ttl");
437 			if (hoplimit > MAXTTL) {
438 				Fprintf(stderr, "%s: ttl %d out of range\n",
439 				    progname, hoplimit);
440 				exit(EXIT_FAILURE);
441 			}
442 			break;
443 
444 		case 'U':
445 			use_udp = _B_TRUE;
446 			use_icmp_ts = _B_FALSE;
447 			break;
448 
449 		case 'v':
450 			verbose = _B_TRUE;
451 			break;
452 		/*
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
457 		 * also undocumented.
458 		 */
459 		case 'x':
460 		case 'g':
461 			strict = _B_FALSE;
462 			if (num_gw > MAXMAX_GWS) {
463 				Fprintf(stderr, "%s: too many gateways\n",
464 				    progname);
465 				exit(EXIT_FAILURE);
466 			}
467 			gw_list[num_gw++] = optarg;
468 			break;
469 
470 		case 'X':
471 		case 'G':
472 			strict = _B_TRUE;
473 			if (num_gw > MAXMAX_GWS) {
474 				Fprintf(stderr, "%s: too many gateways\n",
475 				    progname);
476 				exit(EXIT_FAILURE);
477 			}
478 			gw_list[num_gw++] = optarg;
479 			break;
480 
481 		case 'N':
482 			if (nexthop != NULL) {
483 				Fprintf(stderr, "%s: only one next hop gateway"
484 				    " allowed\n", progname);
485 				exit(EXIT_FAILURE);
486 			}
487 			nexthop = optarg;
488 			break;
489 
490 		case 'Y':
491 			use_icmp_ts = _B_TRUE;
492 			use_udp = _B_FALSE;
493 			break;
494 
495 		case '0':
496 		case '1':
497 		case '2':
498 		case '3':
499 			ts_flag = (char)c - '0';
500 			break;
501 
502 		case '?':
503 			usage(progname);
504 			exit(EXIT_FAILURE);
505 			break;
506 
507 		default:
508 			usage(progname);
509 			exit(EXIT_FAILURE);
510 			break;
511 		}
512 	}
513 
514 	if (optind >= argc) {
515 		usage(progname);
516 		exit(EXIT_FAILURE);
517 	}
518 
519 	/*
520 	 * send_reply, which sends the probe packet back to itself
521 	 * doesn't work with UDP
522 	 */
523 	if (use_udp)
524 		send_reply = _B_FALSE;
525 
526 	if (getenv("MACHINE_THAT_GOES_PING") != NULL)
527 		stats = _B_TRUE;
528 
529 	targethost = argv[optind];
530 	optind++;
531 	if (optind < argc) {
532 		if (stats) {
533 			datalen = int_arg(argv[optind], "data size");
534 			optind++;
535 			if (optind < argc) {
536 				npackets = int_arg(argv[optind],
537 				    "packet count");
538 				if (npackets < 1) {
539 					Fprintf(stderr, "%s: packet count %d "
540 					    "out of range\n", progname,
541 					    npackets);
542 					exit(EXIT_FAILURE);
543 				}
544 			}
545 		} else {
546 			timeout = int_arg(argv[optind], "timeout");
547 		}
548 	}
549 
550 	/*
551 	 * Let's prepare sockaddr_in* structures, cause we might need both of
552 	 * them.
553 	 */
554 	bzero((char *)&to, sizeof (struct sockaddr_in));
555 	to.sin_family = AF_INET;
556 
557 	bzero((char *)&to6, sizeof (struct sockaddr_in6));
558 	to6.sin6_family = AF_INET6;
559 	to6.sin6_flowinfo = htonl((class << 20) | flowinfo);
560 
561 	if (stats)
562 		(void) sigset(SIGINT, finish);
563 
564 	ident = (int)getpid() & 0xFFFF;
565 
566 	/* resolve the hostnames */
567 	resolve_nodes(&ai_dst, &ai_nexthop, &src_addr_list);
568 
569 	/*
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 +
574 	 *			datalen
575 	 */
576 
577 	if (family_input == AF_INET6 ||
578 	    (family_input == AF_UNSPEC && num_v6 != 0)) {
579 		size_t exthdr_len = 0;
580 
581 		if (send_reply) {
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);
587 		}
588 
589 		/*
590 		 * Size of ICMP6 header and UDP header are the same. Let's
591 		 * use ICMP6_MINLEN.
592 		 */
593 		if (datalen > (IP_MAXPACKET - (sizeof (struct ip6_hdr) +
594 		    exthdr_len + ICMP6_MINLEN))) {
595 			Fprintf(stderr,
596 			    "%s: data size too large for IPv6 packet\n",
597 			    progname);
598 			num_v6 = 0;
599 		}
600 	}
601 
602 	if (family_input == AF_INET ||
603 	    (family_input == AF_UNSPEC && num_v4 != 0)) {
604 		size_t opt_len = 0;
605 
606 		if (send_reply) {
607 			/*
608 			 * Includes 3 bytes code+ptr+len, the intermediate
609 			 * gateways, the actual and the effective target.
610 			 */
611 			opt_len = 3 +
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);
615 		}
616 
617 		if (rr_option) {
618 			opt_len = MAX_IPOPTLEN;
619 		} else if (ts_option) {
620 			if ((ts_flag & 0x0f) <= IPOPT_TS_TSANDADDR) {
621 				opt_len = MAX_IPOPTLEN;
622 			} else {
623 				opt_len += IPOPT_MINOFF +
624 				    2 * sizeof (struct ipt_ta);
625 				/*
626 				 * Note: BSD/4.X is broken in their check so we
627 				 * have to  bump up this number by at least one.
628 				 */
629 				opt_len++;
630 			}
631 		}
632 
633 		/* Round up to 4 byte boundary */
634 		if (opt_len & 0x3)
635 			opt_len = (opt_len & ~0x3) + 4;
636 
637 		if (datalen > (IP_MAXPACKET - (sizeof (struct ip) + opt_len +
638 		    ICMP_MINLEN))) {
639 			Fprintf(stderr,
640 			    "%s: data size too large for IPv4 packet\n",
641 			    progname);
642 			num_v4 = 0;
643 		}
644 	}
645 
646 	if (num_v4 == 0 && num_v6 == 0) {
647 		exit(EXIT_FAILURE);
648 	}
649 
650 	/* setup the sockets */
651 	if (num_v6 != 0) {
652 		if (!setup_socket(AF_INET6, &send_sock6, &recv_sock6,
653 		    &if_index, &udp_src_port6, ai_nexthop))
654 			exit(EXIT_FAILURE);
655 	}
656 
657 	if (num_v4 != 0) {
658 		if (!setup_socket(AF_INET, &send_sock, &recv_sock, &if_index,
659 		    &udp_src_port, ai_nexthop))
660 			exit(EXIT_FAILURE);
661 	}
662 
663 	__priv_relinquish();
664 
665 	/*
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.
669 	 */
670 	if (send_reply) {
671 		if (num_v6 != 0)
672 			mirror_gws(gw_IP_list6, AF_INET6);
673 		if (num_v4 != 0)
674 			mirror_gws(gw_IP_list, AF_INET);
675 
676 		/* We add 1 because we put the target as the middle gateway */
677 		eff_num_gw = 2 * num_gw + 1;
678 
679 	} else {
680 		eff_num_gw = num_gw;
681 	}
682 
683 	targetaddr_list = build_targetaddr_list(ai_dst, src_addr_list);
684 	current_targetaddr = targetaddr_list;
685 
686 	/*
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
695 	 * targetaddr.
696 	 */
697 	current_targetaddr->starting_seq_num = use_udp ? dest_port : 0;
698 
699 	if (stats) {
700 		if (probe_all || !nflag) {
701 			Printf("PING %s: %d data bytes\n", targethost, datalen);
702 		} else {
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));
708 			} else {
709 				(void) inet_ntop(AF_INET6,
710 				    &((struct sockaddr_in6 *)(void *)
711 				    ai_dst->ai_addr)->sin6_addr,
712 				    abuf, sizeof (abuf));
713 			}
714 			Printf("PING %s (%s): %d data bytes\n",
715 			    targethost, abuf, datalen);
716 		}
717 	}
718 
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));
723 		exit(EXIT_FAILURE);
724 	}
725 
726 	/*
727 	 * Finally start up the name services warning thread.
728 	 */
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));
733 		exit(EXIT_FAILURE);
734 	}
735 
736 	/* Let's get things going */
737 	send_scheduled_probe();
738 
739 	/* SIGALRM is used to send the next scheduled probe */
740 	(void) sigset(SIGALRM, sigalrm_handler);
741 	schedule_sigalrm();
742 
743 	/*
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
746 	 * probe.
747 	 */
748 	recv_icmp_packet(ai_dst, recv_sock6, recv_sock, udp_src_port6,
749 	    udp_src_port);
750 
751 	return (EXIT_SUCCESS);	/* should never come here */
752 }
753 
754 /*
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.
758  */
759 static struct targetaddr *
760 build_targetaddr_list(struct addrinfo *ai_dst, union any_in_addr *src_addr_list)
761 {
762 	struct targetaddr *head = NULL;
763 	struct targetaddr *targetaddr;
764 	struct targetaddr **nextp;
765 	int num_dst;
766 	int i;
767 	struct addrinfo *aip;
768 
769 	aip = ai_dst;
770 	if (probe_all)
771 		num_dst = num_v4 + num_v6;
772 	else
773 		num_dst = 1;
774 	num_targetaddrs = num_dst;
775 	nextp = &head;
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,
783 			    &src_addr_list[i]);
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,
790 			    &src_addr_list[i]);
791 		} else {
792 			continue;
793 		}
794 		*nextp = targetaddr;
795 		nextp = &targetaddr->next;
796 		if (num_targetaddrs == 1)
797 			break;
798 	}
799 	if (npackets == 0 && stats)
800 		*nextp = head;	/* keep going indefinitely */
801 
802 	return (head);
803 }
804 
805 /*
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.
810  */
811 static struct targetaddr *
812 create_targetaddr_item(int family, union any_in_addr *dst_addr,
813     union any_in_addr *src_addr)
814 {
815 	struct targetaddr *targetaddr;
816 
817 	targetaddr = (struct targetaddr *)malloc(sizeof (struct targetaddr));
818 	if (targetaddr == NULL) {
819 		Fprintf(stderr, "%s: malloc %s\n", progname, strerror(errno));
820 		exit(EXIT_FAILURE);
821 	}
822 	targetaddr->family = family;
823 	targetaddr->dst_addr = *dst_addr;
824 	targetaddr->src_addr = *src_addr;
825 	if (stats) {
826 		/*
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
830 		 * next target IP.
831 		 */
832 		if (npackets > 0)
833 			targetaddr->num_probes = npackets;
834 		else
835 			targetaddr->num_probes = 1;
836 	} else {
837 		targetaddr->num_probes = timeout;
838 	}
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 */
844 
845 	return (targetaddr);
846 }
847 
848 /*
849  * print "unknown host" message
850  */
851 static void
852 print_unknown_host_msg(const char *protocol, const char *hostname)
853 {
854 	Fprintf(stderr, "%s: unknown%s host %s\n", progname, protocol,
855 	    hostname);
856 }
857 
858 /*
859  * Resolve hostnames for the target host and gateways. Also, determine source
860  * addresses to use for each target address.
861  */
862 static void
863 resolve_nodes(struct addrinfo **ai_dstp, struct addrinfo **ai_nexthopp,
864     union any_in_addr **src_addr_listp)
865 {
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;
872 
873 	get_hostinfo(targethost, family_input, &ai_dst);
874 	if (ai_dst == NULL) {
875 		print_unknown_host_msg("", targethost);
876 		exit(EXIT_FAILURE);
877 	}
878 	if (nexthop != NULL) {
879 		get_hostinfo(nexthop, family_input, &ai_nexthop);
880 		if (ai_nexthop == NULL) {
881 			print_unknown_host_msg("", nexthop);
882 			exit(EXIT_FAILURE);
883 		}
884 	}
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) {
888 		case AF_INET:
889 			num_v4++;
890 			break;
891 		case AF_INET6:
892 			num_v6++;
893 			break;
894 		}
895 	}
896 
897 	if (family_input == AF_UNSPEC && !probe_all) {
898 		family_input = ai_dst->ai_family;
899 	}
900 
901 	/* resolve gateways */
902 	if (num_gw > 0) {
903 		get_gwaddrs(gw_list, family_input, gw_IP_list, gw_IP_list6,
904 		    &num_resolved_gw, &num_resolved_gw6);
905 
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]);
911 			num_v6 = 0;
912 		}
913 
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]);
919 			num_v4 = 0;
920 		}
921 	}
922 
923 	if (num_v4 == 0 && num_v6 == 0)
924 		exit(EXIT_FAILURE);
925 
926 	select_all_src_addrs(&src_addr_list, ai_dst, gw_IP_list, gw_IP_list6);
927 	*ai_dstp = ai_dst;
928 	*ai_nexthopp = ai_nexthop;
929 	*src_addr_listp = src_addr_list;
930 }
931 
932 /*
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.
939  */
940 static void
941 get_gwaddrs(char **gw_list, int family, union any_in_addr *gwIPlist,
942     union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
943 {
944 	int i;
945 	boolean_t check_v4 = _B_TRUE, check_v6 = _B_TRUE;
946 	struct addrinfo	*ai = NULL;
947 	struct addrinfo	*aip = NULL;
948 
949 	*resolved = *resolved6 = 0;
950 	switch (family) {
951 	case AF_UNSPEC:
952 		break;
953 	case AF_INET:
954 		check_v6 = _B_FALSE;
955 		break;
956 	case AF_INET6:
957 		check_v4 = _B_FALSE;
958 		break;
959 	default:
960 		return;
961 	}
962 
963 	if (check_v4 && num_gw >= MAX_GWS) {
964 		check_v4 = _B_FALSE;
965 		Fprintf(stderr, "%s: too many IPv4 gateways\n", progname);
966 	}
967 	if (check_v6 && num_gw > MAX_GWS6) {
968 		check_v6 = _B_FALSE;
969 		Fprintf(stderr, "%s: too many IPv6 gateways\n", progname);
970 	}
971 
972 	for (i = 0; i < num_gw; i++) {
973 		if (!check_v4 && !check_v6)
974 			return;
975 		get_hostinfo(gw_list[i], family, &ai);
976 		if (ai == NULL)
977 			return;
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,
984 					    &gwIPlist[i].addr,
985 					    aip->ai_addrlen);
986 					(*resolved)++;
987 					break;
988 				}
989 			}
990 		} else if (check_v4) {
991 			check_v4 = _B_FALSE;
992 		}
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,
999 					    &gwIPlist6[i].addr6,
1000 					    aip->ai_addrlen);
1001 					(*resolved6)++;
1002 					break;
1003 				}
1004 			}
1005 		} else if (check_v6) {
1006 			check_v6 = _B_FALSE;
1007 		}
1008 	}
1009 	freeaddrinfo(ai);
1010 }
1011 
1012 /*
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.
1016  */
1017 static void
1018 mirror_gws(union any_in_addr *gwIPlist, int family)
1019 {
1020 	int effective_num_gw;
1021 	int i;
1022 
1023 	/* We add 1 because we put the target as the middle gateway */
1024 	effective_num_gw = 2 * num_gw + 1;
1025 
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");
1030 		exit(EXIT_FAILURE);
1031 	}
1032 
1033 	for (i = 0; i < num_gw; i++)
1034 		gwIPlist[num_gw + i + 1].addr6 = gwIPlist[num_gw - i - 1].addr6;
1035 }
1036 
1037 /*
1038  * Given IP address or hostname, return addrinfo list.
1039  * Assumes that addrinfo ** ptr is non-null.
1040  */
1041 static void
1042 get_hostinfo(char *host, int family, struct addrinfo **aipp)
1043 {
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];
1049 	int rc;
1050 
1051 	/* check if broadcast */
1052 	if (strcmp(host, "255.255.255.255") == 0)
1053 		broadcast = _B_TRUE;
1054 	else
1055 		broadcast = _B_FALSE;
1056 
1057 	/* check if IPv4-mapped address or broadcast */
1058 	if (((inet_pton(AF_INET6, host, &addr6) > 0) &&
1059 	    IN6_IS_ADDR_V4MAPPED(&addr6)) || broadcast) {
1060 		if (!broadcast) {
1061 			/*
1062 			 * Peel off the "mapping" stuff, leaving 32 bit IPv4
1063 			 * address.
1064 			 */
1065 			IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
1066 
1067 			/* convert it back to a string */
1068 			(void) inet_ntop(AF_INET, (void *)&addr, tmp_buf,
1069 			    sizeof (tmp_buf));
1070 			/*
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
1076 			 * here.
1077 			 */
1078 			(void) strcpy(host, tmp_buf);
1079 		}
1080 		/*
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.
1087 		 */
1088 		if (family == AF_INET6) {
1089 			return;
1090 		}
1091 	}
1092 
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);
1097 	if (rc != 0) {
1098 		if (rc != EAI_NONAME)
1099 			Fprintf(stderr, "%s: getaddrinfo: %s\n", progname,
1100 			    gai_strerror(rc));
1101 		return;
1102 	}
1103 	*aipp = ai;
1104 }
1105 
1106 /*
1107  * For each IP address of the target host, determine a source address to use.
1108  */
1109 static void
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)
1112 {
1113 	union any_in_addr *list;
1114 	struct addrinfo *aip;
1115 	int num_dst = 1;
1116 	int i;
1117 
1118 	if (probe_all) {
1119 		for (aip = ai; aip->ai_next != NULL; aip = aip->ai_next)
1120 			num_dst++;
1121 	}
1122 
1123 	list = calloc((size_t)num_dst, sizeof (union any_in_addr));
1124 	if (list == NULL) {
1125 		Fprintf(stderr, "%s: calloc: %s\n", progname, strerror(errno));
1126 		exit(EXIT_FAILURE);
1127 	}
1128 
1129 	/*
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.
1133 	 */
1134 	if (num_gw > 0) {
1135 		if (ai->ai_family == AF_INET)
1136 			select_src_addr(gwv4, ai->ai_family, &list[0]);
1137 		else
1138 			select_src_addr(gwv6, ai->ai_family, &list[0]);
1139 		/*
1140 		 * Since the first gateway address is fixed, we'll use the same
1141 		 * src address for every different final destination address
1142 		 * we send to.
1143 		 */
1144 		for (i = 1; i < num_dst; i++)
1145 			list[i] = list[0];
1146 	} else {
1147 		/*
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.
1152 		 */
1153 		for (i = 0, aip = ai; i < num_dst && aip != NULL;
1154 		    i++, aip = aip->ai_next) {
1155 			if (aip->ai_family == AF_INET) {
1156 				if (num_v4 != 0) {
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,
1161 					    aip->ai_family,
1162 					    &list[i]);
1163 				}
1164 			} else {
1165 				if (num_v6 != 0) {
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,
1170 					    aip->ai_family,
1171 					    &list[i]);
1172 				}
1173 			}
1174 		}
1175 	}
1176 
1177 	*src_addr_list = list;
1178 }
1179 
1180 /*
1181  * For a given destination address, determine a source address to use.
1182  * Returns wildcard address if it cannot determine the source address.
1183  */
1184 static void
1185 select_src_addr(union any_in_addr *dst_addr, int family,
1186     union any_in_addr *src_addr)
1187 {
1188 	struct sockaddr *sock;
1189 	struct sockaddr_in *sin = NULL;
1190 	struct sockaddr_in6 *sin6 = NULL;
1191 	int tmp_fd;
1192 	size_t sock_len;
1193 
1194 	sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
1195 	if (sock == NULL) {
1196 		Fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
1197 		exit(EXIT_FAILURE);
1198 	}
1199 	(void) bzero(sock, sizeof (struct sockaddr_in6));
1200 
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);
1208 	} else {
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);
1215 	}
1216 
1217 	/* open a UDP socket */
1218 	if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
1219 		Fprintf(stderr, "%s: udp socket: %s\n", progname,
1220 		    strerror(errno));
1221 		exit(EXIT_FAILURE);
1222 	}
1223 
1224 	/* connect it */
1225 	if (connect(tmp_fd, sock, sock_len) < 0) {
1226 		/*
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.
1232 		 */
1233 		if (family == AF_INET)
1234 			src_addr->addr.s_addr = INADDR_ANY;
1235 		else
1236 			src_addr->addr6 = in6addr_any;
1237 		free(sock);
1238 		return;
1239 	}
1240 
1241 	/* get the local sock info */
1242 	if (getsockname(tmp_fd, sock, &sock_len) < 0) {
1243 		Fprintf(stderr, "%s: getsockname: %s\n", progname,
1244 		    strerror(errno));
1245 		exit(EXIT_FAILURE);
1246 	}
1247 
1248 	if (family == AF_INET) {
1249 		assert(sin != NULL);
1250 		src_addr->addr = sin->sin_addr;
1251 	} else {
1252 		assert(sin6 != NULL);
1253 		src_addr->addr6 = sin6->sin6_addr;
1254 	}
1255 
1256 	(void) close(tmp_fd);
1257 	free(sock);
1258 }
1259 
1260 /*
1261  * Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
1262  * exits on failure
1263  */
1264 static void
1265 set_nexthop(int family, struct addrinfo	*ai_nexthop, int sock)
1266 {
1267 	if (family == AF_INET) {
1268 		ipaddr_t nh;
1269 
1270 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1271 		nh = ((struct sockaddr_in *)ai_nexthop->
1272 		    ai_addr)->sin_addr.s_addr;
1273 
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) {
1278 			if (errno == EPERM)
1279 				Fprintf(stderr, "%s: Insufficient privilege "
1280 				    "to specify IPv4 nexthop router.\n",
1281 				    progname);
1282 			else
1283 				Fprintf(stderr, "%s: setsockopt %s\n",
1284 				    progname, strerror(errno));
1285 			exit(EXIT_FAILURE);
1286 		}
1287 		(void) __priv_bracket(PRIV_OFF);
1288 		/* revert to non-privileged user */
1289 	} else {
1290 		struct sockaddr_in6 *nh;
1291 
1292 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1293 		nh = (struct sockaddr_in6 *)ai_nexthop->
1294 		    ai_addr;
1295 
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));
1300 			exit(EXIT_FAILURE);
1301 		}
1302 	}
1303 }
1304 
1305 /*
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.
1310  */
1311 static boolean_t
1312 setup_socket(int family, int *send_sockp, int *recv_sockp, int *if_index,
1313     ushort_t *udp_src_port, struct addrinfo *ai_nexthop)
1314 {
1315 	int send_sock;
1316 	int recv_sock;
1317 	struct sockaddr_in6 sin6;
1318 	struct sockaddr_in sin;
1319 	struct sockaddr *sp;
1320 	struct ipsec_req req;
1321 	size_t slen;
1322 	int on = 1;
1323 	uchar_t char_op;
1324 	int int_op;
1325 
1326 	/* now we need the net_icmpaccess privilege */
1327 	(void) __priv_bracket(PRIV_ON);
1328 
1329 	recv_sock = socket(family, SOCK_RAW,
1330 	    (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
1331 
1332 	if (recv_sock < 0) {
1333 		Fprintf(stderr, "%s: socket %s\n", progname, strerror(errno));
1334 		exit(EXIT_FAILURE);
1335 	}
1336 
1337 	/* revert to non-privileged user after opening sockets */
1338 	(void) __priv_bracket(PRIV_OFF);
1339 
1340 	if (bypass) {
1341 		(void) memset(&req, 0, sizeof (req));
1342 		req.ipsr_ah_req = IPSEC_PREF_NEVER;
1343 		req.ipsr_esp_req = IPSEC_PREF_NEVER;
1344 
1345 		if (setsockopt(recv_sock, (family == AF_INET) ? IPPROTO_IP :
1346 		    IPPROTO_IPV6, IP_SEC_OPT, &req, sizeof (req)) < 0) {
1347 			switch (errno) {
1348 			case EPROTONOSUPPORT:
1349 				/*
1350 				 * No IPsec subsystem or policy loaded.
1351 				 * Bypass implicitly allowed.
1352 				 */
1353 				break;
1354 			case EPERM:
1355 				Fprintf(stderr, "%s: Insufficient privilege "
1356 				    "to bypass IPsec policy.\n", progname);
1357 				exit(EXIT_FAILURE);
1358 				break;
1359 			default:
1360 				Fprintf(stderr, "%s: setsockopt %s\n", progname,
1361 				    strerror(errno));
1362 				exit(EXIT_FAILURE);
1363 				break;
1364 			}
1365 		}
1366 	}
1367 
1368 	/*
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.
1371 	 */
1372 	if (use_udp) {
1373 		send_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP);
1374 		if (send_sock < 0) {
1375 			Fprintf(stderr, "%s: socket %s\n", progname,
1376 			    strerror(errno));
1377 			exit(EXIT_FAILURE);
1378 		}
1379 
1380 		if (bypass) {
1381 			if (setsockopt(send_sock, (family == AF_INET) ?
1382 			    IPPROTO_IP : IPPROTO_IPV6, IP_SEC_OPT, &req,
1383 			    sizeof (req)) < 0) {
1384 				switch (errno) {
1385 				case EPROTONOSUPPORT:
1386 					/*
1387 					 * No IPsec subsystem or policy loaded.
1388 					 * Bypass implicitly allowed.
1389 					 */
1390 					break;
1391 				case EPERM:
1392 					Fprintf(stderr, "%s: Insufficient "
1393 					    "privilege to bypass IPsec "
1394 					    "policy.\n", progname);
1395 					exit(EXIT_FAILURE);
1396 					break;
1397 				default:
1398 					Fprintf(stderr, "%s: setsockopt %s\n",
1399 					    progname, strerror(errno));
1400 					exit(EXIT_FAILURE);
1401 					break;
1402 				}
1403 			}
1404 		}
1405 
1406 		/*
1407 		 * In order to distinguish replies to our UDP probes from
1408 		 * other pings', we need to know our source port number.
1409 		 */
1410 		if (family == AF_INET) {
1411 			sp = (struct sockaddr *)&sin;
1412 			slen = sizeof (sin);
1413 		} else {
1414 			sp = (struct sockaddr *)&sin6;
1415 			slen = sizeof (sin6);
1416 		}
1417 		bzero(sp, slen);
1418 		sp->sa_family = family;
1419 
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,
1423 			    strerror(errno));
1424 			exit(EXIT_FAILURE);
1425 		}
1426 
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,
1430 			    strerror(errno));
1431 			exit(EXIT_FAILURE);
1432 		}
1433 		*udp_src_port = (family == AF_INET) ? sin.sin_port :
1434 		    sin6.sin6_port;
1435 	} else {
1436 		send_sock = recv_sock;
1437 	}
1438 
1439 	if (nexthop != NULL)
1440 		set_nexthop(family, ai_nexthop, send_sock);
1441 
1442 	int_op = 48 * 1024;
1443 	if (int_op < datalen)
1444 		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,
1448 		    strerror(errno));
1449 		exit(EXIT_FAILURE);
1450 	}
1451 
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,
1455 		    strerror(errno));
1456 		exit(EXIT_FAILURE);
1457 	}
1458 
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));
1464 			exit(EXIT_FAILURE);
1465 		}
1466 	}
1467 
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));
1473 			exit(EXIT_FAILURE);
1474 		}
1475 	}
1476 
1477 	if (moptions & MULTICAST_NOLOOP) {
1478 		if (family == AF_INET) {
1479 			char_op = 0;	/* used to turn off option */
1480 
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,
1485 				    strerror(errno));
1486 				exit(EXIT_FAILURE);
1487 			}
1488 		} else {
1489 			int_op = 0;	/* used to turn off option */
1490 
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,
1496 				    strerror(errno));
1497 				exit(EXIT_FAILURE);
1498 			}
1499 		}
1500 	}
1501 
1502 	if (moptions & MULTICAST_TTL) {
1503 		char_op = hoplimit;
1504 
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,
1511 				    strerror(errno));
1512 				exit(EXIT_FAILURE);
1513 			}
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));
1518 				exit(EXIT_FAILURE);
1519 			}
1520 		}
1521 		/*
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.
1526 		 */
1527 	}
1528 
1529 	/*
1530 	 * did the user specify an interface?
1531 	 * Applies to unicast, broadcast and multicast.
1532 	 */
1533 	if (moptions & MULTICAST_IF) {
1534 		struct ifaddrlist *al = NULL;		/* interface list */
1535 		struct ifaddrlist *my_if;
1536 		char errbuf[ERRBUFSIZE];
1537 		int num_ifs;
1538 		int num_src_ifs;		/* exclude down and loopback */
1539 		int i;
1540 
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);
1545 			exit(EXIT_FAILURE);
1546 		}
1547 
1548 		/* filter out down and loopback interfaces */
1549 		num_src_ifs = 0;
1550 		for (i = 0; i < num_ifs; i++) {
1551 			if (!(al[i].flags & IFF_LOOPBACK) &&
1552 			    (al[i].flags & IFF_UP))
1553 				num_src_ifs++;
1554 		}
1555 
1556 		if (num_src_ifs == 0) {
1557 			Fprintf(stderr, "%s: can't find any %s interface\n",
1558 			    progname, (family == AF_INET) ? "IPv4" : "IPv6");
1559 
1560 			return (_B_FALSE);	/* failure */
1561 		}
1562 
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");
1569 
1570 			return (_B_FALSE);
1571 		}
1572 
1573 		if (family == AF_INET) {
1574 			struct in_pktinfo pktinfo;
1575 
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,
1581 				    strerror(errno));
1582 				exit(EXIT_FAILURE);
1583 			}
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,
1590 				    strerror(errno));
1591 				exit(EXIT_FAILURE);
1592 			}
1593 		} else {
1594 			/*
1595 			 * the outgoing interface is set in set_ancillary_data()
1596 			 * function
1597 			 */
1598 			*if_index = my_if->index;
1599 		}
1600 
1601 		free(al);
1602 	}
1603 
1604 	if (settos && family == AF_INET) {
1605 		int_op = tos;
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));
1610 			exit(EXIT_FAILURE);
1611 		}
1612 	}
1613 
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));
1620 			exit(EXIT_FAILURE);
1621 		}
1622 	} else {
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));
1627 			exit(EXIT_FAILURE);
1628 		}
1629 	}
1630 
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));
1637 			exit(EXIT_FAILURE);
1638 		}
1639 
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));
1644 			exit(EXIT_FAILURE);
1645 		}
1646 
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));
1651 			exit(EXIT_FAILURE);
1652 		}
1653 	}
1654 
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,
1660 		    strerror(errno));
1661 	}
1662 
1663 	*send_sockp = send_sock;
1664 	*recv_sockp = recv_sock;
1665 
1666 	/* successful */
1667 	return (_B_TRUE);
1668 }
1669 
1670 /*
1671  * Pull out the record containing all the info about the interface specified by
1672  * `out_if'. Skips interfaces which are down or loopback.
1673  */
1674 static struct ifaddrlist *
1675 find_if(struct ifaddrlist *al, int num_ifs)
1676 {
1677 	static struct ifaddrlist tmp_if;
1678 	boolean_t found;
1679 	int i;
1680 
1681 	i = 0;
1682 	found = _B_FALSE;
1683 
1684 	while (i < num_ifs && !found) {
1685 		tmp_if = al[i];
1686 
1687 		/* skip down or loopback interfaces */
1688 		if ((tmp_if.flags & IFF_LOOPBACK) || !(tmp_if.flags & IFF_UP)) {
1689 			i++;
1690 			continue;
1691 		}
1692 
1693 		/* the type of interface id is variable */
1694 		switch (out_if.id_type) {
1695 		case IF_INDEX:
1696 			if (out_if.id.index == tmp_if.index)
1697 				found = _B_TRUE;
1698 			break;
1699 
1700 		case IF_NAME:
1701 			if (strcmp(out_if.id.name, tmp_if.device) == 0)
1702 				found = _B_TRUE;
1703 			break;
1704 
1705 		case IF_ADDR:
1706 			if (out_if.id.addr.addr.s_addr ==
1707 			    tmp_if.addr.addr.s_addr) {
1708 				found = _B_TRUE;
1709 			}
1710 			break;
1711 
1712 		case IF_ADDR6:
1713 			if (IN6_ARE_ADDR_EQUAL(&out_if.id.addr.addr6,
1714 			    &tmp_if.addr.addr6)) {
1715 				found = _B_TRUE;
1716 			}
1717 			break;
1718 
1719 		default:
1720 			break;
1721 		}
1722 
1723 		i++;
1724 	}
1725 
1726 	if (found)
1727 		return (&tmp_if);
1728 	else
1729 		return (NULL);
1730 }
1731 
1732 /*
1733  * Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
1734  * send_scheduled_probe() to send next probe.
1735  */
1736 void
1737 sigalrm_handler(void)
1738 {
1739 	/*
1740 	 * If we've been told that we're done, the timer should be cancelled
1741 	 * and not rescheduled, just return.
1742 	 */
1743 	if (timer_done == _B_TRUE)
1744 		return;
1745 
1746 	/*
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.
1753 	 */
1754 	if ((gethrtime() - t_last_probe_sent) < mintime) {
1755 		return;
1756 	}
1757 	send_scheduled_probe();
1758 	schedule_sigalrm();
1759 }
1760 
1761 /*
1762  * Schedule next SIGALRM.
1763  */
1764 void
1765 schedule_sigalrm(void)
1766 {
1767 	int waittime;
1768 	struct itimerspec it;
1769 
1770 	bzero(&it, sizeof (struct itimerspec));
1771 	if (npackets == 0 ||
1772 	    current_targetaddr->num_sent < current_targetaddr->num_probes) {
1773 		it = interval;
1774 	} else {
1775 		if (current_targetaddr->got_reply) {
1776 			waittime = 2 * tmax / MICROSEC;
1777 			if (waittime == 0)
1778 				waittime = 1;
1779 		} else {
1780 			waittime = MAX_WAIT;
1781 		}
1782 		it.it_value.tv_sec = waittime;
1783 	}
1784 
1785 	if (timer_settime(timer, TIMER_RELTIME, &it, NULL) != 0) {
1786 		Fprintf(stderr, "%s: unexpected error updating time: %s\n",
1787 		    progname, strerror(errno));
1788 		exit(EXIT_FAILURE);
1789 	}
1790 }
1791 
1792 /*
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().
1796  */
1797 void
1798 send_scheduled_probe()
1799 {
1800 	static struct msghdr msg6;
1801 	static boolean_t first_probe = _B_TRUE;
1802 	char tmp_buf[INET6_ADDRSTRLEN];
1803 
1804 	/*
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.
1808 	 */
1809 	if (current_targetaddr->num_sent == current_targetaddr->num_probes ||
1810 	    current_targetaddr->probing_done) {
1811 		/*
1812 		 * is this a dead target?
1813 		 */
1814 		if (!stats && !current_targetaddr->got_reply) {
1815 			if (!probe_all) {
1816 				Printf("no answer from %s\n", targethost);
1817 			} else {
1818 				Printf("no answer from %s(%s)\n", targethost,
1819 				    inet_ntop(current_targetaddr->family,
1820 				    &current_targetaddr->dst_addr,
1821 				    tmp_buf, sizeof (tmp_buf)));
1822 			}
1823 		}
1824 		/*
1825 		 * Before we move onto next item, let's do some clean up.
1826 		 */
1827 		current_targetaddr->got_reply = _B_FALSE;
1828 		current_targetaddr->probing_done = _B_FALSE;
1829 		/*
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.
1833 		 */
1834 		if (stats || !probe_all)
1835 			current_targetaddr->num_sent = 0;
1836 		nreceived_last_target = 0;
1837 
1838 		current_targetaddr = current_targetaddr->next;
1839 
1840 		/*
1841 		 * Did we reach the end of road?
1842 		 */
1843 		if (current_targetaddr == NULL) {
1844 			timer_done = _B_TRUE;
1845 			if (stats)
1846 				finish();
1847 			if (is_alive)
1848 				exit(EXIT_SUCCESS);
1849 			else
1850 				exit(EXIT_FAILURE);
1851 		} else {
1852 			/*
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.
1856 			 */
1857 			current_targetaddr->starting_seq_num = use_udp ?
1858 			    dest_port : (ntransmitted % (MAX_ICMP_SEQ + 1));
1859 		}
1860 	}
1861 
1862 	if (current_targetaddr->family == AF_INET6) {
1863 		if (send_reply) {
1864 			/* sending back to ourself */
1865 			to6.sin6_addr = current_targetaddr->src_addr.addr6;
1866 		} else {
1867 			to6.sin6_addr = current_targetaddr->dst_addr.addr6;
1868 		}
1869 		/*
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.
1875 		 */
1876 		if (first_probe ||
1877 		    (send_reply && current_targetaddr->num_sent == 0)) {
1878 			if (send_reply) {
1879 				/* target is the middle gateway now */
1880 				gw_IP_list6[num_gw].addr6 =
1881 				    current_targetaddr->dst_addr.addr6;
1882 			}
1883 			set_ancillary_data(&msg6, hoplimit, gw_IP_list6,
1884 			    eff_num_gw, if_index);
1885 			first_probe = _B_FALSE;
1886 		}
1887 		pinger(send_sock6, (struct sockaddr *)&to6, &msg6, AF_INET6);
1888 	} else {
1889 		to.sin_addr = current_targetaddr->dst_addr.addr;
1890 		/*
1891 		 * Set IPv4 options when sending the first probe to a target
1892 		 * IP address. Some options change when the target address
1893 		 * changes.
1894 		 */
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;
1899 				/*
1900 				 * If send_reply, the target becomes the
1901 				 * middle gateway, sender becomes the last
1902 				 * gateway.
1903 				 */
1904 				if (send_reply) {
1905 					gw_IP_list[eff_num_gw].addr =
1906 					    current_targetaddr->src_addr.addr;
1907 				}
1908 			}
1909 			/*
1910 			 * In IPv4, if source routing is used, the target
1911 			 * address shows up as the last gateway, hence +1.
1912 			 */
1913 			set_IPv4_options(send_sock, gw_IP_list,
1914 			    (eff_num_gw > 0) ? eff_num_gw + 1 : 0,
1915 			    &current_targetaddr->src_addr.addr, &to.sin_addr);
1916 		}
1917 		pinger(send_sock, (struct sockaddr *)&to, NULL, AF_INET);
1918 	}
1919 
1920 	current_targetaddr->num_sent++;
1921 }
1922 
1923 /*
1924  * recv_icmp_packet()'s job is to listen to icmp packets and filter out
1925  * those ping is interested in.
1926  */
1927 static void
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)
1930 {
1931 	struct msghdr in_msg;
1932 	struct iovec iov;
1933 	struct sockaddr_in6 from6;
1934 	fd_set fds;
1935 	int result;
1936 	int cc;
1937 	boolean_t always_true = _B_TRUE; /* lint doesn't like while(_B_TRUE) */
1938 
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);
1945 
1946 		result = select(MAX(recv_sock6, recv_sock) + 1, &fds,
1947 		    (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL);
1948 		if (result == -1) {
1949 			if (errno == EINTR) {
1950 				continue;
1951 			} else {
1952 				Fprintf(stderr, "%s: select %s\n", progname,
1953 				    strerror(errno));
1954 				exit(EXIT_FAILURE);
1955 			}
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);
1965 
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);
1970 				if (cc < 0) {
1971 					if (errno != EINTR) {
1972 						Fprintf(stderr,
1973 						    "%s: recvmsg %s\n",
1974 						    progname, strerror(errno));
1975 					}
1976 					continue;
1977 				} else if (cc > 0) {
1978 					check_reply6(ai_dst, &in_msg, cc,
1979 					    udp_src_port6);
1980 				}
1981 			}
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);
1985 				if (cc < 0) {
1986 					if (errno != EINTR) {
1987 						Fprintf(stderr,
1988 						    "%s: recvmsg %s\n",
1989 						    progname, strerror(errno));
1990 					}
1991 					continue;
1992 				} else if (cc > 0) {
1993 					check_reply(ai_dst, &in_msg, cc,
1994 					    udp_src_port);
1995 				}
1996 			}
1997 		}
1998 		/*
1999 		 * If we were probing last IP address of the target host and
2000 		 * received a reply for each probe sent to this address,
2001 		 * then we are done!
2002 		 */
2003 		if ((npackets > 0) && (current_targetaddr->next == NULL) &&
2004 		    (nreceived_last_target == npackets)) {
2005 			timer_done = _B_TRUE;
2006 			finish();
2007 		}
2008 	} /* infinite loop */
2009 }
2010 
2011 /*
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
2015  * packet.
2016  */
2017 boolean_t
2018 is_a_target(struct addrinfo *ai, union any_in_addr *addr)
2019 {
2020 	int num_addrs;
2021 	int i;
2022 	struct addrinfo *aip;
2023 
2024 	aip = ai;
2025 	if (probe_all)
2026 		num_addrs = num_v4 + num_v6;
2027 	else
2028 		num_addrs = 1;
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))
2034 				return (_B_TRUE);
2035 		} else {
2036 			/* LINTED E_BAD_PTR_CAST_ALIGN */
2037 			if (((struct sockaddr_in *)
2038 			    aip->ai_addr)->sin_addr.s_addr == addr->addr.s_addr)
2039 				return (_B_TRUE);
2040 		}
2041 	}
2042 
2043 	return (_B_FALSE);
2044 }
2045 
2046 /*
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.
2052  */
2053 static void
2054 pinger(int send_sock, struct sockaddr *whereto, struct msghdr *msg6,
2055     int family)
2056 {
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;
2065 	struct timeval *tp;
2066 	struct timeval t_snd;
2067 	uchar_t *datap;
2068 	struct iovec iov;
2069 	int start = 0;
2070 	int cc;
2071 	int i;
2072 
2073 	/* using UDP? */
2074 	if (use_udp) {
2075 		cc = datalen;
2076 
2077 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2078 		tp = (struct timeval *)out_pkt;
2079 		datap = &out_pkt[sizeof (struct timeval)];
2080 
2081 		/*
2082 		 * This sets the port whether we are handling a v4 or v6
2083 		 * sockaddr structure.
2084 		 */
2085 		to->sin_port = htons(dest_port);
2086 
2087 		dest_port = (dest_port + 1) % (MAX_PORT + 1);
2088 		ntransmitted++;
2089 	} else {	/* using ICMP */
2090 		cc = datalen + ICMP_MINLEN;
2091 
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;
2098 		} else {
2099 			icp->icmp_type = send_reply ?
2100 			    ICMP_ECHOREPLY : ICMP_ECHO;
2101 		}
2102 
2103 		icp->icmp_code = 0;
2104 		icp->icmp_cksum = 0;
2105 		icp->icmp_seq = htons(ntransmitted++ % (MAX_ICMP_SEQ + 1));
2106 		if (icp->icmp_seq == 0)
2107 			num_wraps++;
2108 		icp->icmp_id = htons(ident);		/* ID */
2109 
2110 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2111 		tp = (struct timeval *)&out_pkt[ICMP_MINLEN];
2112 		datap = &out_pkt[ICMP_MINLEN + sizeof (struct timeval)];
2113 	}
2114 
2115 	start = sizeof (struct timeval);	/* skip for time */
2116 
2117 	(void) gettimeofday(&t_snd, (struct timezone *)NULL);
2118 
2119 	/* if packet is big enough to store timeval OR ... */
2120 	if ((datalen >= sizeof (struct timeval)) ||
2121 	    (family == AF_INET && use_icmp_ts))
2122 		*tp = t_snd;
2123 
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);
2129 	}
2130 
2131 	for (i = start; i < datalen; i++)
2132 		*datap++ = i;
2133 
2134 	if (family == AF_INET) {
2135 		if (!use_udp)
2136 			icp->icmp_cksum = in_cksum((ushort_t *)icp, cc);
2137 
2138 		i = sendto(send_sock, (char *)out_pkt, cc, 0, whereto,
2139 		    sizeof (struct sockaddr_in));
2140 	} else {
2141 		/*
2142 		 * Fill in the rest of the msghdr structure. msg_control is set
2143 		 * in set_ancillary_data().
2144 		 */
2145 		msg6->msg_name = to6;
2146 		msg6->msg_namelen = sizeof (struct sockaddr_in6);
2147 
2148 		iov.iov_base = out_pkt;
2149 		iov.iov_len = cc;
2150 
2151 		msg6->msg_iov = &iov;
2152 		msg6->msg_iovlen = 1;
2153 
2154 		i = sendmsg(send_sock, msg6, 0);
2155 	}
2156 
2157 	/* This is a more precise time (right after we send the packet) */
2158 	t_last_probe_sent = gethrtime();
2159 
2160 	if (i < 0 || i != cc)  {
2161 		if (i < 0) {
2162 			Fprintf(stderr, "%s: sendto %s\n", progname,
2163 			    strerror(errno));
2164 			if (!stats)
2165 				exit(EXIT_FAILURE);
2166 		}
2167 		Printf("ping: wrote %s %d chars, ret=%d\n",
2168 		    targethost, cc, i);
2169 		(void) fflush(stdout);
2170 	}
2171 }
2172 
2173 /*
2174  * Return a hostname for the given IP address.
2175  */
2176 char *
2177 pr_name(char *addr, int family)
2178 {
2179 	struct sockaddr_in sin;
2180 	struct sockaddr_in6 sin6;
2181 	struct sockaddr *sa;
2182 	static struct in6_addr prev_addr = IN6ADDR_ANY_INIT;
2183 	char *cp;
2184 	char abuf[INET6_ADDRSTRLEN];
2185 	static char buf[NI_MAXHOST + INET6_ADDRSTRLEN + 3];
2186 	uint_t slen, alen, hlen;
2187 
2188 	switch (family) {
2189 	case AF_INET:
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;
2195 		sin.sin_port = 0;
2196 		sa = (struct sockaddr *)&sin;
2197 		break;
2198 	case AF_INET6:
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;
2204 		sin6.sin6_port = 0;
2205 		sa = (struct sockaddr *)&sin6;
2206 		break;
2207 	default:
2208 		(void) snprintf(buf, sizeof (buf), "<invalid address family>");
2209 		return (buf);
2210 	}
2211 	sa->sa_family = family;
2212 
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)
2225 				buf[0] = 0;
2226 		} else if (!nflag) {
2227 			/* append numeric address to hostname string */
2228 			hlen = strlen(buf);
2229 			cp = (char *)(buf + hlen);
2230 			(void) snprintf(cp, sizeof (buf) - hlen, " (%s)",
2231 			    inet_ntop(family, (const void *)addr, abuf,
2232 			    sizeof (abuf)));
2233 		}
2234 		mutex_enter(&ns_lock);
2235 		ns_active = _B_FALSE;
2236 		mutex_exit(&ns_lock);
2237 
2238 		/* LINTED E_BAD_PTR_CAST_ALIGN */
2239 		prev_addr = *(struct in6_addr *)addr;
2240 	}
2241 	return (buf);
2242 }
2243 
2244 /*
2245  * Return the protocol string, given its protocol number.
2246  */
2247 char *
2248 pr_protocol(int prot)
2249 {
2250 	static char buf[20];
2251 
2252 	switch (prot) {
2253 	case IPPROTO_ICMPV6:
2254 		(void) strlcpy(buf, "icmp6", sizeof (buf));
2255 		break;
2256 
2257 	case IPPROTO_ICMP:
2258 		(void) strlcpy(buf, "icmp", sizeof (buf));
2259 		break;
2260 
2261 	case IPPROTO_TCP:
2262 		(void) strlcpy(buf, "tcp", sizeof (buf));
2263 		break;
2264 
2265 	case IPPROTO_UDP:
2266 		(void) strlcpy(buf, "udp", sizeof (buf));
2267 		break;
2268 
2269 	default:
2270 		(void) snprintf(buf, sizeof (buf), "prot %d", prot);
2271 		break;
2272 	}
2273 
2274 	return (buf);
2275 }
2276 
2277 /*
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).
2280  */
2281 boolean_t
2282 seq_match(ushort_t seq_begin, int seq_len, ushort_t value)
2283 {
2284 	/*
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!
2288 	 */
2289 	if (seq_len > MAX_ICMP_SEQ / 2) {
2290 		seq_begin = (seq_begin + seq_len - MAX_ICMP_SEQ / 2) %
2291 		    (MAX_ICMP_SEQ + 1);
2292 		seq_len = MAX_ICMP_SEQ / 2;
2293 	}
2294 
2295 	if (PINGSEQ_LEQ(seq_begin, value) &&
2296 	    PINGSEQ_LEQ(value, (seq_begin + seq_len - 1) % (MAX_ICMP_SEQ + 1)))
2297 		return (_B_TRUE);
2298 	else
2299 		return (_B_FALSE);
2300 }
2301 
2302 /*
2303  * For a given icmp_seq, find which destination address we must have sent this
2304  * to.
2305  */
2306 void
2307 find_dstaddr(ushort_t icmpseq, union any_in_addr *ipaddr)
2308 {
2309 	struct targetaddr *target = targetaddr_list;
2310 	int real_seq;
2311 	int targetaddr_index;
2312 	int real_npackets;
2313 	int i;
2314 
2315 	ipaddr->addr6 = in6addr_any;
2316 
2317 	/*
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
2322 	 * preserved.
2323 	 */
2324 	if (probe_all && !stats) {
2325 		do {
2326 			if (seq_match(target->starting_seq_num,
2327 			    target->num_sent, icmpseq)) {
2328 				ipaddr->addr6 = target->dst_addr.addr6;
2329 				/*
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
2333 				 * real one.
2334 				 */
2335 			}
2336 			target = target->next;
2337 		} while (target != NULL);
2338 	} else {
2339 		/*
2340 		 * Find the absolute (non-wrapped) seq number within the last
2341 		 * 64K
2342 		 */
2343 		if (icmpseq < (ntransmitted % (MAX_ICMP_SEQ + 1))) {
2344 			real_seq = num_wraps * (MAX_ICMP_SEQ + 1) + icmpseq;
2345 		} else {
2346 			real_seq = (num_wraps - 1) * (MAX_ICMP_SEQ + 1) +
2347 			    icmpseq;
2348 		}
2349 
2350 		/* Make sure it's non-negative */
2351 		if (real_seq < 0)
2352 			return;
2353 		real_npackets = (npackets == 0) ? 1 : npackets;
2354 
2355 		/*
2356 		 * We sent npackets many packets to each of those
2357 		 * num_targetaddrs many IP addresses.
2358 		 */
2359 		targetaddr_index =
2360 		    (real_seq % (num_targetaddrs * real_npackets)) /
2361 		    real_npackets;
2362 		for (i = 0; i < targetaddr_index; i++)
2363 			target = target->next;
2364 		ipaddr->addr6 = target->dst_addr.addr6;
2365 	}
2366 }
2367 
2368 /*
2369  * Checksum routine for Internet Protocol family headers (C Version)
2370  */
2371 static ushort_t
2372 in_cksum(ushort_t *addr, int len)
2373 {
2374 	int nleft = len;
2375 	ushort_t *w = addr;
2376 	ushort_t answer;
2377 	ushort_t odd_byte = 0;
2378 	int sum = 0;
2379 
2380 	/*
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
2384 	 *  16 bits.
2385 	 */
2386 	while (nleft > 1) {
2387 		sum += *w++;
2388 		nleft -= 2;
2389 	}
2390 
2391 	/* mop up an odd byte, if necessary */
2392 	if (nleft == 1) {
2393 		*(uchar_t *)(&odd_byte) = *(uchar_t *)w;
2394 		sum += odd_byte;
2395 	}
2396 
2397 	/*
2398 	 * add back carry outs from top 16 bits to low 16 bits
2399 	 */
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 */
2403 	return (answer);
2404 }
2405 
2406 /*
2407  * Subtract 2 timeval structs:  out = out - in.
2408  * Out is assumed to be >= in.
2409  */
2410 void
2411 tvsub(struct timeval *out, struct timeval *in)
2412 {
2413 	if ((out->tv_usec -= in->tv_usec) < 0) {
2414 		out->tv_sec--;
2415 		out->tv_usec += 1000000;
2416 	}
2417 	out->tv_sec -= in->tv_sec;
2418 }
2419 
2420 /*
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.
2426  */
2427 static void
2428 finish()
2429 {
2430 	Printf("\n----%s PING Statistics----\n", targethost);
2431 	Printf("%d packets transmitted, ", ntransmitted);
2432 	Printf("%d packets received, ", nreceived);
2433 	if (ntransmitted) {
2434 		if (nreceived <= ntransmitted) {
2435 			Printf("%d%% packet loss",
2436 			    (int)(((ntransmitted-nreceived)*100) /
2437 			    ntransmitted));
2438 		} else {
2439 			Printf("%.2f times amplification",
2440 			    (double)nreceived / (double)ntransmitted);
2441 		}
2442 	}
2443 	(void) putchar('\n');
2444 
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;
2449 		double sd =
2450 		    sqrt(((smean - mean*mean) * nreceived) / (nreceived-1));
2451 
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);
2457 	}
2458 	(void) fflush(stdout);
2459 
2460 	exit(is_alive ? EXIT_SUCCESS : EXIT_FAILURE);
2461 }
2462 
2463 /*
2464  * print the usage line
2465  */
2466 static void
2467 usage(char *cmdname)
2468 {
2469 	Fprintf(stderr, "usage: %s host [timeout]\n", cmdname);
2470 	Fprintf(stderr,
2471 /* CSTYLED */
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",
2475 	    cmdname);
2476 }
2477 
2478 /*
2479  * Parse integer argument; exit with an error if it's not a number.
2480  * Now it also accepts hex. values.
2481  */
2482 static int
2483 int_arg(char *s, char *what)
2484 {
2485 	char *cp;
2486 	char *ep;
2487 	int num;
2488 
2489 	errno = 0;
2490 	if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
2491 		cp = s + 2;
2492 		num = (int)strtol(cp, &ep, 16);
2493 	} else {
2494 		num = (int)strtol(s, &ep, 10);
2495 	}
2496 
2497 	if (errno || *ep != '\0' || num < 0) {
2498 		Fprintf(stderr, "%s: bad %s: %s\n", progname, what, s);
2499 		exit(EXIT_FAILURE);
2500 	}
2501 
2502 	return (num);
2503 }
2504 
2505 /*
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.
2513  */
2514 static void
2515 parse_interval(char *s)
2516 {
2517 	long double val;
2518 	char *end;
2519 
2520 	errno = 0;
2521 	val = strtold(s, &end);
2522 	if (errno != 0 || *end != '\0') {
2523 		Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2524 		exit(EXIT_FAILURE);
2525 	}
2526 
2527 	/*
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.
2531 	 */
2532 	if (val == NAN || val <= 0.0 || val >= INT_MAX) {
2533 		Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2534 		exit(EXIT_FAILURE);
2535 	}
2536 
2537 	if (val < 0.01) {
2538 		Fprintf(stderr, "%s: interval too small: %Lf\n", progname, val);
2539 		exit(EXIT_FAILURE);
2540 	}
2541 
2542 	interval.it_value.tv_sec = (long)val;
2543 	interval.it_value.tv_nsec = (long)((val - interval.it_value.tv_sec) *
2544 	    NANOSEC);
2545 
2546 	if (interval.it_value.tv_sec == 0 &&
2547 	    interval.it_value.tv_nsec < mintime) {
2548 		mintime = interval.it_value.tv_nsec;
2549 	}
2550 }
2551 
2552 /*
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.
2557  */
2558 void
2559 ping_gettime(struct msghdr *msg, struct timeval *tv)
2560 {
2561 	struct cmsghdr *cmsg;
2562 
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));
2569 			return;
2570 		}
2571 	}
2572 
2573 	(void) gettimeofday(tv, (struct timezone *)NULL);
2574 }
2575 
2576 /*
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.
2585  *
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.
2588  */
2589 /*ARGSUSED*/
2590 static void *
2591 ns_warning_thr(void *unused)
2592 {
2593 	for (;;) {
2594 		hrtime_t now;
2595 
2596 		(void) sleep(ns_sleeptime);
2597 		now = gethrtime();
2598 		mutex_enter(&ns_lock);
2599 		if (ns_active == _B_TRUE &&
2600 		    now - ns_starttime >= ns_warntime * NANOSEC) {
2601 			Fprintf(stderr, "%s: warning: ICMP responses "
2602 			    "received, but name service lookups are "
2603 			    "taking a while. Use ping -n to disable "
2604 			    "name service lookups.\n",
2605 			    progname);
2606 			mutex_exit(&ns_lock);
2607 			return (NULL);
2608 		}
2609 		mutex_exit(&ns_lock);
2610 	}
2611 
2612 	/* LINTED: E_STMT_NOT_REACHED */
2613 	return (NULL);
2614 }
2615