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