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