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