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