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