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