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