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