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