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