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 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Copyright 2015, Joyent, Inc. 32 * Copyright 2024 Bill Sommerfeld <sommerfeld@hamachi.org> 33 */ 34 35 /* 36 * Portions of this source code were derived from Berkeley 4.3 BSD 37 * under license from the Regents of the University of California. 38 */ 39 40 #include <stdio.h> 41 #include <string.h> 42 #include <strings.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <unistd.h> 46 #include <signal.h> 47 48 #include <sys/time.h> 49 #include <sys/param.h> 50 #include <sys/socket.h> 51 #include <sys/sockio.h> 52 #include <sys/stropts.h> 53 #include <sys/file.h> 54 #include <arpa/inet.h> 55 #include <net/if.h> 56 #include <netinet/in_systm.h> 57 #include <netinet/in.h> 58 #include <netinet/ip.h> 59 #include <netinet/ip_icmp.h> 60 #include <netinet/ip6.h> 61 #include <netinet/icmp6.h> 62 #include <netinet/udp.h> 63 #include <netdb.h> 64 #include <stdlib.h> 65 66 #include <libinetutil.h> 67 #include "ping.h" 68 69 static int IPv6_hdrlen(ip6_t *, int, uint8_t *); 70 static void pr_ext_headers(struct msghdr *); 71 static void pr_rthdr(unsigned char *); 72 static char *pr_type6(uchar_t); 73 74 /* 75 * Initialize the msghdr for specifying the hoplimit, outgoing interface and 76 * routing header. 77 */ 78 void 79 set_ancillary_data(struct msghdr *msgp, int hoplimit, 80 union any_in_addr *gwIPlist, int gw_cnt, uint_t if_index) 81 { 82 size_t hoplimit_space; 83 size_t rthdr_space; 84 size_t pktinfo_space; 85 size_t bufspace; 86 struct cmsghdr *cmsgp; 87 uchar_t *cmsg_datap; 88 static boolean_t first = _B_TRUE; 89 int i; 90 91 if (hoplimit == -1 && gw_cnt == 0 && if_index == 0) 92 return; 93 94 /* 95 * Need to figure out size of buffer needed for ancillary data 96 * containing routing header and packet info options. 97 * 98 * Portable heuristic to compute upper bound on space needed for 99 * N ancillary data options. It assumes up to _MAX_ALIGNMENT padding 100 * after both header and data as the worst possible upper bound on space 101 * consumed by padding. 102 * It also adds one extra "sizeof (struct cmsghdr)" for the last option. 103 * This is needed because we would like to use CMSG_NXTHDR() while 104 * composing the buffer. The CMSG_NXTHDR() macro is designed better for 105 * parsing than composing the buffer. It requires the pointer it returns 106 * to leave space in buffer for addressing a cmsghdr and we want to make 107 * sure it works for us while we skip beyond the last ancillary data 108 * option. 109 * 110 * bufspace[i] = sizeof(struct cmsghdr) + <pad after header> + 111 * <option[i] content length> + <pad after data>; 112 * 113 * total_bufspace = bufspace[0] + bufspace[1] + ... 114 * ... + bufspace[N-1] + sizeof (struct cmsghdr); 115 */ 116 117 rthdr_space = 0; 118 pktinfo_space = 0; 119 hoplimit_space = 0; 120 bufspace = 0; 121 122 if (hoplimit != -1) { 123 hoplimit_space = sizeof (int); 124 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 125 hoplimit_space + _MAX_ALIGNMENT; 126 } 127 128 if (gw_cnt > 0) { 129 rthdr_space = inet6_rth_space(IPV6_RTHDR_TYPE_0, gw_cnt); 130 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 131 rthdr_space + _MAX_ALIGNMENT; 132 } 133 134 if (if_index != 0) { 135 pktinfo_space = sizeof (struct in6_pktinfo); 136 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 137 pktinfo_space + _MAX_ALIGNMENT; 138 } 139 140 /* 141 * We need to temporarily set the msgp->msg_controllen to bufspace 142 * (we will later trim it to actual length used). This is needed because 143 * CMSG_NXTHDR() uses it to check we have not exceeded the bounds. 144 */ 145 bufspace += sizeof (struct cmsghdr); 146 msgp->msg_controllen = bufspace; 147 148 /* 149 * This function is called more than once only if -l/-S used, 150 * since we need to modify the middle gateway. So, don't alloc 151 * new memory, just reuse what msg6 points to. 152 */ 153 if (first) { 154 first = _B_FALSE; 155 msgp->msg_control = (struct cmsghdr *)malloc(bufspace); 156 if (msgp->msg_control == NULL) { 157 Fprintf(stderr, "%s: malloc %s\n", 158 progname, strerror(errno)); 159 exit(EXIT_FAILURE); 160 } 161 }; 162 cmsgp = CMSG_FIRSTHDR(msgp); 163 164 /* 165 * Fill ancillary data. First hoplimit, then rthdr and pktinfo. 166 */ 167 168 /* set hoplimit ancillary data if needed */ 169 if (hoplimit != -1) { 170 cmsgp->cmsg_level = IPPROTO_IPV6; 171 cmsgp->cmsg_type = IPV6_HOPLIMIT; 172 cmsg_datap = CMSG_DATA(cmsgp); 173 /* LINTED */ 174 *(int *)cmsg_datap = hoplimit; 175 cmsgp->cmsg_len = cmsg_datap + hoplimit_space - 176 (uchar_t *)cmsgp; 177 cmsgp = CMSG_NXTHDR(msgp, cmsgp); 178 } 179 180 /* set rthdr ancillary data if needed */ 181 if (gw_cnt > 0) { 182 struct ip6_rthdr0 *rthdr0p; 183 184 cmsgp->cmsg_level = IPPROTO_IPV6; 185 cmsgp->cmsg_type = IPV6_RTHDR; 186 cmsg_datap = CMSG_DATA(cmsgp); 187 188 /* 189 * Initialize rthdr structure 190 */ 191 /* LINTED */ 192 rthdr0p = (struct ip6_rthdr0 *)cmsg_datap; 193 if (inet6_rth_init(rthdr0p, rthdr_space, 194 IPV6_RTHDR_TYPE_0, gw_cnt) == NULL) { 195 Fprintf(stderr, "%s: inet6_rth_init failed\n", 196 progname); 197 exit(EXIT_FAILURE); 198 } 199 200 /* 201 * Stuff in gateway addresses 202 */ 203 for (i = 0; i < gw_cnt; i++) { 204 if (inet6_rth_add(rthdr0p, &gwIPlist[i].addr6) == -1) { 205 Fprintf(stderr, 206 "%s: inet6_rth_add\n", progname); 207 exit(EXIT_FAILURE); 208 } 209 } 210 211 cmsgp->cmsg_len = cmsg_datap + rthdr_space - (uchar_t *)cmsgp; 212 cmsgp = CMSG_NXTHDR(msgp, cmsgp); 213 } 214 215 /* set pktinfo ancillary data if needed */ 216 if (if_index != 0) { 217 struct in6_pktinfo *pktinfop; 218 219 cmsgp->cmsg_level = IPPROTO_IPV6; 220 cmsgp->cmsg_type = IPV6_PKTINFO; 221 cmsg_datap = CMSG_DATA(cmsgp); 222 223 /* LINTED */ 224 pktinfop = (struct in6_pktinfo *)cmsg_datap; 225 /* 226 * We don't know if pktinfop->ipi6_addr is aligned properly, 227 * therefore let's use bcopy, instead of assignment. 228 */ 229 (void) bcopy(&in6addr_any, &pktinfop->ipi6_addr, 230 sizeof (struct in6_addr)); 231 232 /* 233 * We can assume pktinfop->ipi6_ifindex is 32 bit aligned. 234 */ 235 pktinfop->ipi6_ifindex = if_index; 236 cmsgp->cmsg_len = cmsg_datap + pktinfo_space - (uchar_t *)cmsgp; 237 cmsgp = CMSG_NXTHDR(msgp, cmsgp); 238 } 239 240 msgp->msg_controllen = (char *)cmsgp - (char *)msgp->msg_control; 241 } 242 243 /* 244 * Check out the packet to see if it came from us. This logic is necessary 245 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 246 * which arrive ('tis only fair). This permits multiple copies of this 247 * program to be run without having intermingled output (or statistics!). 248 */ 249 void 250 check_reply6(struct addrinfo *ai_dst, struct msghdr *msg, int cc, 251 ushort_t udp_src_port) 252 { 253 struct icmp6_hdr *icmp6; 254 ip6_t *ip6h; 255 nd_redirect_t *nd_rdrct; 256 struct udphdr *up; 257 union any_in_addr dst_addr; 258 uchar_t *buf; 259 int32_t *intp; 260 struct sockaddr_in6 *from6; 261 struct timeval tv; 262 struct timeval *tp; 263 int64_t triptime; 264 boolean_t valid_reply = _B_FALSE; 265 boolean_t reply_matched_current_target = _B_FALSE; /* Is the source */ 266 /* address of this reply same */ 267 /* as where we're sending */ 268 /* currently? */ 269 boolean_t last_reply_from_targetaddr = _B_FALSE; /* Is this stats, */ 270 /* probe all with npackets>0 */ 271 /* and we received reply for */ 272 /* the last probe sent to */ 273 /* targetaddr */ 274 uint32_t ip6hdr_len; 275 uint8_t last_hdr; 276 int cc_left; 277 int i; 278 char tmp_buf[INET6_ADDRSTRLEN]; 279 static char *unreach6[] = { 280 "No Route to Destination", 281 "Communication Administratively Prohibited", 282 "Not a Neighbor (obsoleted ICMPv6 code)", 283 "Address Unreachable", 284 "Port Unreachable" 285 }; 286 static char *timexceed6[] = { 287 "Hop limit exceeded in transit", 288 "Fragment reassembly time exceeded" 289 }; 290 static char *param_prob6[] = { 291 "Erroneous header field encountered", 292 "Unrecognized next header type encountered", 293 "Unrecognized IPv6 option encountered" 294 }; 295 boolean_t print_newline = _B_FALSE; 296 297 /* decompose msghdr into useful pieces */ 298 buf = (uchar_t *)msg->msg_iov->iov_base; 299 from6 = (struct sockaddr_in6 *)msg->msg_name; 300 301 /* LINTED */ 302 intp = (int32_t *)buf; 303 304 ping_gettime(msg, &tv); 305 306 /* Ignore packets > 64k or control buffers that don't fit */ 307 if (msg->msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 308 if (verbose) { 309 Printf("Truncated message: msg_flags 0x%x from %s\n", 310 msg->msg_flags, pr_name6(from6)); 311 } 312 return; 313 } 314 if (cc < ICMP6_MINLEN) { 315 if (verbose) { 316 Printf("packet too short (%d bytes) from %s\n", cc, 317 pr_name6(from6)); 318 } 319 return; 320 } 321 /* LINTED */ 322 icmp6 = (struct icmp6_hdr *)buf; 323 cc_left = cc - ICMP6_MINLEN; 324 325 switch (icmp6->icmp6_type) { 326 case ICMP6_DST_UNREACH: 327 /* LINTED */ 328 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN); 329 if (cc_left < sizeof (ip6_t)) { 330 if (verbose) { 331 Printf("packet too short (%d bytes) from %s\n", 332 cc, pr_name6(from6)); 333 } 334 return; 335 } 336 337 /* 338 * Determine the total length of IPv6 header and extension 339 * headers, also the upper layer header (UDP, TCP, ICMP, etc.) 340 * following. 341 */ 342 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr); 343 344 cc_left -= ip6hdr_len; 345 346 /* LINTED */ 347 up = (struct udphdr *)((char *)ip6h + ip6hdr_len); 348 if (cc_left < sizeof (struct udphdr)) { 349 if (verbose) { 350 Printf("packet too short (%d bytes) from %s\n", 351 cc, pr_name6(from6)); 352 } 353 return; 354 } 355 cc_left -= sizeof (struct udphdr); 356 357 /* determine if this is *the* reply */ 358 if (icmp6->icmp6_code == ICMP6_DST_UNREACH_NOPORT && 359 last_hdr == IPPROTO_UDP && 360 udp_src_port == up->uh_sport && 361 use_udp) { 362 valid_reply = _B_TRUE; 363 } else { 364 valid_reply = _B_FALSE; 365 } 366 367 if (valid_reply) { 368 /* 369 * For this valid reply, if we are still sending to 370 * this target IP address, we'd like to do some 371 * updates to targetaddr, so hold SIGALRMs. 372 */ 373 (void) sighold(SIGALRM); 374 is_alive = _B_TRUE; 375 nreceived++; 376 reply_matched_current_target = 377 seq_match(current_targetaddr->starting_seq_num, 378 current_targetaddr->num_sent, 379 ntohs(up->uh_dport)); 380 if (reply_matched_current_target) { 381 current_targetaddr->got_reply = _B_TRUE; 382 nreceived_last_target++; 383 /* 384 * Determine if stats, probe-all, and 385 * npackets != 0, and this is the reply for 386 * the last probe we sent to current target 387 * address. 388 */ 389 if (stats && probe_all && npackets > 0 && 390 ((current_targetaddr->starting_seq_num + 391 current_targetaddr->num_probes - 1) % 392 (MAX_PORT + 1) == ntohs(up->uh_dport)) && 393 (current_targetaddr->num_probes == 394 current_targetaddr->num_sent)) 395 last_reply_from_targetaddr = _B_TRUE; 396 } else { 397 /* 398 * If it's just probe_all and we just received 399 * a reply from a target address we were 400 * probing and had timed out (now we are probing 401 * some other target address), we ignore 402 * this reply. 403 */ 404 if (probe_all && !stats) { 405 valid_reply = _B_FALSE; 406 /* 407 * Only if it's verbose, we get a 408 * message regarding this reply, 409 * otherwise we are done here. 410 */ 411 if (!verbose) { 412 (void) sigrelse(SIGALRM); 413 return; 414 } 415 } 416 } 417 } 418 419 if (valid_reply && !stats) { 420 /* 421 * if we are still sending to the same target address, 422 * then stop it, because we know it's alive. 423 */ 424 if (reply_matched_current_target) { 425 (void) alarm(0); /* cancel alarm */ 426 (void) sigset(SIGALRM, SIG_IGN); 427 current_targetaddr->probing_done = _B_TRUE; 428 } 429 (void) sigrelse(SIGALRM); 430 431 if (!probe_all) { 432 Printf("%s is alive\n", targethost); 433 } else { 434 (void) inet_ntop(AF_INET6, 435 (void *)&ip6h->ip6_dst, 436 tmp_buf, sizeof (tmp_buf)); 437 if (nflag) { 438 Printf("%s is alive\n", tmp_buf); 439 } else { 440 Printf("%s (%s) is alive\n", 441 targethost, tmp_buf); 442 } 443 } 444 if (reply_matched_current_target) { 445 /* 446 * Let's get things going again, but now 447 * ping will start sending to next target IP 448 * address. 449 */ 450 send_scheduled_probe(); 451 (void) sigset(SIGALRM, sigalrm_handler); 452 schedule_sigalrm(); 453 } 454 return; 455 } else { 456 /* 457 * If we are not moving to next targetaddr, let's 458 * release the SIGALRM now. We don't want to stall in 459 * the middle of probing a targetaddr if the pr_name() 460 * call (see below) takes longer. 461 */ 462 if (!last_reply_from_targetaddr) 463 (void) sigrelse(SIGALRM); 464 /* else, we'll release it later */ 465 } 466 467 dst_addr.addr6 = ip6h->ip6_dst; 468 if (valid_reply) { 469 Printf("%d bytes from %s: ", cc, 470 pr_name6(from6)); 471 Printf("udp_port=%d. ", ntohs(up->uh_dport)); 472 print_newline = _B_TRUE; 473 } else if (is_a_target(ai_dst, &dst_addr)|| verbose) { 474 if (icmp6->icmp6_code >= A_CNT(unreach6)) { 475 Printf("ICMPv6 %d Unreachable from gateway " 476 "%s\n", icmp6->icmp6_code, 477 pr_name6(from6)); 478 } else { 479 Printf("ICMPv6 %s from gateway %s\n", 480 unreach6[icmp6->icmp6_code], 481 pr_name6(from6)); 482 } 483 Printf(" for %s from %s", pr_protocol(last_hdr), 484 pr_name((char *)&ip6h->ip6_src, AF_INET6)); 485 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst, 486 AF_INET6)); 487 if (last_hdr == IPPROTO_TCP || last_hdr == IPPROTO_UDP) 488 Printf(" port %d ", ntohs(up->uh_dport)); 489 print_newline = _B_TRUE; 490 } 491 492 /* 493 * Update and print the stats, if it's a valid reply and 494 * contains a timestamp. 495 */ 496 if (valid_reply && datalen >= sizeof (struct timeval) && 497 cc_left >= sizeof (struct timeval)) { 498 /* LINTED */ 499 tp = (struct timeval *)((char *)up + 500 sizeof (struct udphdr)); 501 (void) tvsub(&tv, tp); 502 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec; 503 Printf("time=" TIMEFORMAT " ms", triptime/1000.0); 504 tsum += triptime; 505 tsum2 += triptime*triptime; 506 if (triptime < tmin) 507 tmin = triptime; 508 if (triptime > tmax) 509 tmax = triptime; 510 print_newline = _B_TRUE; 511 } 512 if (print_newline) 513 (void) putchar('\n'); 514 /* 515 * If it's stats, probe-all, npackets > 0, and we received reply 516 * for the last probe sent to this target address, then we 517 * don't need to wait anymore, let's move on to next target 518 * address, now! 519 */ 520 if (last_reply_from_targetaddr) { 521 (void) alarm(0); /* cancel alarm */ 522 current_targetaddr->probing_done = _B_TRUE; 523 (void) sigrelse(SIGALRM); 524 send_scheduled_probe(); 525 schedule_sigalrm(); 526 } 527 break; 528 529 case ICMP6_PACKET_TOO_BIG: 530 /* LINTED */ 531 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN); 532 if (cc_left < sizeof (ip6_t)) { 533 if (verbose) { 534 Printf("packet too short (%d bytes) from %s\n", 535 cc, pr_name6(from6)); 536 } 537 return; 538 } 539 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr); 540 541 dst_addr.addr6 = ip6h->ip6_dst; 542 if (is_a_target(ai_dst, &dst_addr) || verbose) { 543 Printf("ICMPv6 packet too big from %s\n", 544 pr_name6(from6)); 545 546 Printf(" for %s from %s", pr_protocol(last_hdr), 547 pr_name((char *)&ip6h->ip6_src, AF_INET6)); 548 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst, 549 AF_INET6)); 550 if ((last_hdr == IPPROTO_TCP || 551 last_hdr == IPPROTO_UDP) && 552 (cc_left >= (ip6hdr_len + 4))) { 553 /* LINTED */ 554 up = (struct udphdr *) 555 ((char *)ip6h + ip6hdr_len); 556 Printf(" port %d ", ntohs(up->uh_dport)); 557 } 558 Printf(" MTU = %d\n", ntohl(icmp6->icmp6_mtu)); 559 } 560 break; 561 562 case ICMP6_TIME_EXCEEDED: 563 /* LINTED */ 564 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN); 565 if (cc_left < sizeof (ip6_t)) { 566 if (verbose) { 567 Printf("packet too short (%d bytes) from %s\n", 568 cc, pr_name6(from6)); 569 } 570 return; 571 } 572 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr); 573 574 dst_addr.addr6 = ip6h->ip6_dst; 575 if (is_a_target(ai_dst, &dst_addr) || verbose) { 576 if (icmp6->icmp6_code >= A_CNT(timexceed6)) { 577 Printf("ICMPv6 %d time exceeded from %s\n", 578 icmp6->icmp6_code, pr_name6(from6)); 579 } else { 580 Printf("ICMPv6 %s from %s\n", 581 timexceed6[icmp6->icmp6_code], 582 pr_name6(from6)); 583 } 584 Printf(" for %s from %s", pr_protocol(last_hdr), 585 pr_name((char *)&ip6h->ip6_src, AF_INET6)); 586 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst, 587 AF_INET6)); 588 if ((last_hdr == IPPROTO_TCP || 589 last_hdr == IPPROTO_UDP) && 590 (cc_left >= (ip6hdr_len + 4))) { 591 /* LINTED */ 592 up = (struct udphdr *) 593 ((char *)ip6h + ip6hdr_len); 594 Printf(" port %d", ntohs(up->uh_dport)); 595 } 596 (void) putchar('\n'); 597 } 598 break; 599 600 case ICMP6_PARAM_PROB: 601 /* LINTED */ 602 ip6h = (ip6_t *)((char *)icmp6 + ICMP6_MINLEN); 603 if (cc_left < sizeof (ip6_t)) { 604 if (verbose) { 605 Printf("packet too short (%d bytes) from %s\n", 606 cc, pr_name6(from6)); 607 } 608 return; 609 } 610 ip6hdr_len = IPv6_hdrlen(ip6h, cc_left, &last_hdr); 611 612 dst_addr.addr6 = ip6h->ip6_dst; 613 if (is_a_target(ai_dst, &dst_addr) || verbose) { 614 if (icmp6->icmp6_code >= A_CNT(param_prob6)) { 615 Printf("ICMPv6 %d parameter problem from %s\n", 616 icmp6->icmp6_code, pr_name6(from6)); 617 } else { 618 Printf("ICMPv6 %s from %s\n", 619 param_prob6[icmp6->icmp6_code], 620 pr_name6(from6)); 621 } 622 icmp6->icmp6_pptr = ntohl(icmp6->icmp6_pptr); 623 Printf(" in byte %d", icmp6->icmp6_pptr); 624 if (icmp6->icmp6_pptr <= ip6hdr_len) { 625 Printf(" (value 0x%x)", 626 *((uchar_t *)ip6h + icmp6->icmp6_pptr)); 627 } 628 Printf(" for %s from %s", pr_protocol(last_hdr), 629 pr_name((char *)&ip6h->ip6_src, AF_INET6)); 630 Printf(" to %s", pr_name((char *)&ip6h->ip6_dst, 631 AF_INET6)); 632 if ((last_hdr == IPPROTO_TCP || 633 last_hdr == IPPROTO_UDP) && 634 (cc_left >= (ip6hdr_len + 4))) { 635 /* LINTED */ 636 up = (struct udphdr *) 637 ((char *)ip6h + ip6hdr_len); 638 Printf(" port %d", ntohs(up->uh_dport)); 639 } 640 (void) putchar('\n'); 641 } 642 break; 643 644 case ICMP6_ECHO_REQUEST: 645 return; 646 647 case ICMP6_ECHO_REPLY: 648 if (ntohs(icmp6->icmp6_id) == ident) { 649 if (!use_udp) 650 valid_reply = _B_TRUE; 651 else 652 valid_reply = _B_FALSE; 653 } else { 654 return; 655 } 656 657 if (valid_reply) { 658 /* 659 * For this valid reply, if we are still sending to 660 * this target IP address, we'd like to do some 661 * updates to targetaddr, so hold SIGALRMs. 662 */ 663 (void) sighold(SIGALRM); 664 is_alive = _B_TRUE; 665 nreceived++; 666 reply_matched_current_target = 667 seq_match(current_targetaddr->starting_seq_num, 668 current_targetaddr->num_sent, 669 ntohs(icmp6->icmp6_seq)); 670 if (reply_matched_current_target) { 671 current_targetaddr->got_reply = _B_TRUE; 672 nreceived_last_target++; 673 /* 674 * Determine if stats, probe-all, and 675 * npackets != 0, and this is the reply for 676 * the last probe we sent to current target 677 * address. 678 */ 679 if (stats && probe_all && npackets > 0 && 680 ((current_targetaddr->starting_seq_num + 681 current_targetaddr->num_probes - 1) % 682 (MAX_ICMP_SEQ + 1) == 683 ntohs(icmp6->icmp6_seq)) && 684 (current_targetaddr->num_probes == 685 current_targetaddr->num_sent)) 686 last_reply_from_targetaddr = _B_TRUE; 687 } else { 688 /* 689 * If it's just probe_all and we just received 690 * a reply from a target address we were 691 * probing and had timed out (now we are probing 692 * some other target address), we ignore 693 * this reply. 694 */ 695 if (probe_all && !stats) { 696 valid_reply = _B_FALSE; 697 /* 698 * Only if it's verbose, we get a 699 * message regarding this reply, 700 * otherwise we are done here. 701 */ 702 if (!verbose) { 703 (void) sigrelse(SIGALRM); 704 return; 705 } 706 } 707 } 708 } 709 710 if (!stats && valid_reply) { 711 /* 712 * if we are still sending to the same target address, 713 * then stop it, because we know it's alive. 714 */ 715 if (reply_matched_current_target) { 716 (void) alarm(0); /* cancel alarm */ 717 (void) sigset(SIGALRM, SIG_IGN); 718 current_targetaddr->probing_done = _B_TRUE; 719 } 720 (void) sigrelse(SIGALRM); 721 722 if (!probe_all) { 723 Printf("%s is alive\n", targethost); 724 } else { 725 /* 726 * If we are using send_reply, the real 727 * target address is not the src address of the 728 * replies. Use icmp_seq to find out where this 729 * probe was sent to. 730 */ 731 if (send_reply) { 732 (void) find_dstaddr( 733 ntohs(icmp6->icmp6_seq), &dst_addr); 734 (void) inet_ntop(AF_INET6, 735 (void *)&dst_addr.addr6, 736 tmp_buf, sizeof (tmp_buf)); 737 } else { 738 (void) inet_ntop(AF_INET6, 739 (void *)&from6->sin6_addr, 740 tmp_buf, sizeof (tmp_buf)); 741 } 742 743 if (nflag) { 744 Printf("%s is alive\n", tmp_buf); 745 } else { 746 Printf("%s (%s) is alive\n", 747 targethost, tmp_buf); 748 } 749 } 750 if (reply_matched_current_target) { 751 /* 752 * Let's get things going again, but now 753 * ping will start sending to next target IP 754 * address. 755 */ 756 send_scheduled_probe(); 757 (void) sigset(SIGALRM, sigalrm_handler); 758 schedule_sigalrm(); 759 } 760 return; 761 } else { 762 /* 763 * If we are not moving to next targetaddr, let's 764 * release the SIGALRM now. We don't want to stall in 765 * the middle of probing a targetaddr if the pr_name() 766 * call (see below) takes longer. 767 */ 768 if (!last_reply_from_targetaddr) 769 (void) sigrelse(SIGALRM); 770 /* else, we'll release it later */ 771 } 772 773 /* 774 * If we are using send_reply, the real target address is 775 * not the src address of the replies. Use icmp_seq to find out 776 * where this probe was sent to. 777 */ 778 if (send_reply) { 779 (void) find_dstaddr(ntohs(icmp6->icmp6_seq), &dst_addr); 780 Printf("%d bytes from %s: ", cc, 781 pr_name((char *)&dst_addr.addr6, AF_INET6)); 782 } else { 783 Printf("%d bytes from %s: ", cc, pr_name6(from6)); 784 } 785 Printf("icmp_seq=%d. ", ntohs(icmp6->icmp6_seq)); 786 787 if (valid_reply && datalen >= sizeof (struct timeval) && 788 cc_left >= sizeof (struct timeval)) { 789 /* LINTED */ 790 tp = (struct timeval *)&icmp6->icmp6_data16[2]; 791 (void) tvsub(&tv, tp); 792 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec; 793 Printf("time=" TIMEFORMAT " ms", triptime/1000.0); 794 tsum += triptime; 795 tsum2 += triptime*triptime; 796 if (triptime < tmin) 797 tmin = triptime; 798 if (triptime > tmax) 799 tmax = triptime; 800 } 801 (void) putchar('\n'); 802 /* 803 * If it's stats, probe-all, npackets > 0, and we received reply 804 * for the last probe sent to this target address, then we 805 * don't need to wait anymore, let's move on to next target 806 * address, now! 807 */ 808 if (last_reply_from_targetaddr) { 809 (void) alarm(0); /* cancel alarm */ 810 current_targetaddr->probing_done = _B_TRUE; 811 (void) sigrelse(SIGALRM); 812 send_scheduled_probe(); 813 schedule_sigalrm(); 814 } 815 break; 816 817 case MLD_LISTENER_QUERY: 818 case MLD_LISTENER_REPORT: 819 case MLD_LISTENER_REDUCTION: 820 case ND_ROUTER_SOLICIT: 821 case ND_ROUTER_ADVERT: 822 case ND_NEIGHBOR_SOLICIT: 823 case ND_NEIGHBOR_ADVERT: 824 return; 825 826 case ND_REDIRECT: 827 nd_rdrct = (nd_redirect_t *)icmp6; 828 829 if (cc_left < sizeof (nd_redirect_t) - ICMP6_MINLEN) { 830 if (verbose) { 831 Printf("packet too short (%d bytes) from %s\n", 832 cc, pr_name6(from6)); 833 } 834 return; 835 } 836 dst_addr.addr6 = nd_rdrct->nd_rd_dst; 837 if (is_a_target(ai_dst, &dst_addr) || verbose) { 838 Printf("ICMPv6 redirect from gateway %s\n", 839 pr_name6(from6)); 840 841 Printf(" to %s", 842 pr_name((char *)&nd_rdrct->nd_rd_target, AF_INET6)); 843 Printf(" for %s\n", 844 pr_name((char *)&nd_rdrct->nd_rd_dst, AF_INET6)); 845 } 846 break; 847 848 default: 849 if (verbose) { 850 Printf("%d bytes from %s:\n", cc, pr_name6(from6)); 851 Printf("icmp6_type=%d (%s) ", icmp6->icmp6_type, 852 pr_type6(icmp6->icmp6_type)); 853 Printf("icmp6_code=%d\n", icmp6->icmp6_code); 854 for (i = 0; i < 12; i++) { 855 Printf("x%2.2x: x%8.8x\n", 856 i * sizeof (int32_t), *intp++); 857 } 858 } 859 break; 860 } 861 862 /* 863 * If it's verbose mode and we recv'd ancillary data, print extension 864 * headers. 865 */ 866 if (verbose && msg->msg_controllen > 0) 867 pr_ext_headers(msg); 868 } 869 870 /* 871 * Convert an ICMP6 "type" field to a printable string. 872 */ 873 static char * 874 pr_type6(uchar_t icmp6_type) 875 { 876 static struct icmptype_table ttab6[] = { 877 {ICMP6_DST_UNREACH, "Dest Unreachable"}, 878 {ICMP6_PACKET_TOO_BIG, "Packet Too Big"}, 879 {ICMP6_TIME_EXCEEDED, "Time Exceeded"}, 880 {ICMP6_PARAM_PROB, "Parameter Problem"}, 881 {ICMP6_ECHO_REQUEST, "Echo Request"}, 882 {ICMP6_ECHO_REPLY, "Echo Reply"}, 883 {MLD_LISTENER_QUERY, "Multicast Listener Query"}, 884 {MLD_LISTENER_REPORT, "Multicast Listener Report"}, 885 {MLD_LISTENER_REDUCTION, "Multicast Listener Done"}, 886 {ND_ROUTER_SOLICIT, "Router Solicitation"}, 887 {ND_ROUTER_ADVERT, "Router Advertisement"}, 888 {ND_NEIGHBOR_SOLICIT, "Neighbor Solicitation"}, 889 {ND_NEIGHBOR_ADVERT, "Neighbor Advertisement"}, 890 {ND_REDIRECT, "Redirect Message"}, 891 }; 892 int i; 893 894 for (i = 0; i < A_CNT(ttab6); i++) { 895 if (ttab6[i].type == icmp6_type) 896 return (ttab6[i].message); 897 898 } 899 900 return ("OUT-OF-RANGE"); 901 } 902 903 /* 904 * Return the length of the IPv6 related headers (including extension headers). 905 * It also sets the *last_hdr_rtrn to the first upper layer protocol header 906 * following IPv6 header and extension headers. If print_flag is _B_TRUE, it 907 * prints extension headers. 908 */ 909 static int 910 IPv6_hdrlen(ip6_t *ip6h, int pkt_len, uint8_t *last_hdr_rtrn) 911 { 912 int length; 913 int exthdrlength; 914 uint8_t nexthdr; 915 uint8_t *whereptr; 916 ip6_hbh_t *hbhhdr; 917 ip6_dest_t *desthdr; 918 ip6_rthdr_t *rthdr; 919 ip6_frag_t *fraghdr; 920 uint8_t *endptr; 921 922 length = sizeof (ip6_t); 923 924 whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */ 925 endptr = ((uint8_t *)ip6h) + pkt_len; 926 927 nexthdr = ip6h->ip6_nxt; 928 *last_hdr_rtrn = IPPROTO_NONE; 929 930 if (whereptr >= endptr) 931 return (length); 932 933 while (whereptr < endptr) { 934 *last_hdr_rtrn = nexthdr; 935 switch (nexthdr) { 936 case IPPROTO_HOPOPTS: 937 hbhhdr = (ip6_hbh_t *)whereptr; 938 exthdrlength = 8 * (hbhhdr->ip6h_len + 1); 939 if ((uchar_t *)hbhhdr + exthdrlength > endptr) 940 return (length); 941 nexthdr = hbhhdr->ip6h_nxt; 942 length += exthdrlength; 943 break; 944 945 case IPPROTO_DSTOPTS: 946 desthdr = (ip6_dest_t *)whereptr; 947 exthdrlength = 8 * (desthdr->ip6d_len + 1); 948 if ((uchar_t *)desthdr + exthdrlength > endptr) 949 return (length); 950 nexthdr = desthdr->ip6d_nxt; 951 length += exthdrlength; 952 break; 953 954 case IPPROTO_ROUTING: 955 rthdr = (ip6_rthdr_t *)whereptr; 956 exthdrlength = 8 * (rthdr->ip6r_len + 1); 957 if ((uchar_t *)rthdr + exthdrlength > endptr) 958 return (length); 959 nexthdr = rthdr->ip6r_nxt; 960 length += exthdrlength; 961 break; 962 963 case IPPROTO_FRAGMENT: 964 /* LINTED */ 965 fraghdr = (ip6_frag_t *)whereptr; 966 if ((uchar_t *)&fraghdr[1] > endptr) 967 return (length); 968 nexthdr = fraghdr->ip6f_nxt; 969 length += sizeof (struct ip6_frag); 970 break; 971 972 case IPPROTO_NONE: 973 default: 974 return (length); 975 } 976 whereptr = (uint8_t *)ip6h + length; 977 } 978 *last_hdr_rtrn = nexthdr; 979 980 return (length); 981 } 982 983 /* 984 * Print extension headers 985 */ 986 static void 987 pr_ext_headers(struct msghdr *msg) 988 { 989 struct cmsghdr *cmsg; 990 991 Printf(" IPv6 extension headers: "); 992 993 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 994 cmsg = CMSG_NXTHDR(msg, cmsg)) { 995 if (cmsg->cmsg_level == IPPROTO_IPV6) { 996 switch (cmsg->cmsg_type) { 997 case IPV6_HOPOPTS: 998 Printf(" <hop-by-hop options>"); 999 break; 1000 1001 case IPV6_DSTOPTS: 1002 Printf(" <destination options (after routing" 1003 "header)>"); 1004 break; 1005 1006 case IPV6_RTHDRDSTOPTS: 1007 Printf(" <destination options (before routing" 1008 "header)>"); 1009 break; 1010 1011 case IPV6_RTHDR: 1012 pr_rthdr((uchar_t *)CMSG_DATA(cmsg)); 1013 break; 1014 1015 default: 1016 Printf(" <option type %d>", cmsg->cmsg_type); 1017 break; 1018 } 1019 } 1020 } 1021 (void) putchar('\n'); 1022 } 1023 1024 /* 1025 * Print the routing header 0 information 1026 */ 1027 static void 1028 pr_rthdr(uchar_t *buf) 1029 { 1030 ip6_rthdr_t *rthdr; 1031 ip6_rthdr0_t *rthdr0; 1032 struct in6_addr *gw_addr; 1033 int i, num_addr; 1034 1035 rthdr = (ip6_rthdr_t *)buf; 1036 Printf(" <type %d routing header, segleft %u> ", 1037 rthdr->ip6r_type, rthdr->ip6r_segleft); 1038 1039 if (rthdr->ip6r_type == 0) { 1040 /* LINTED */ 1041 rthdr0 = (ip6_rthdr0_t *)buf; 1042 gw_addr = (struct in6_addr *)(rthdr0 + 1); 1043 num_addr = rthdr0->ip6r0_len / 2; 1044 1045 for (i = 0; i < num_addr; i++) { 1046 Printf("%s", pr_name((char *)gw_addr, AF_INET6)); 1047 if (i == (num_addr - rthdr0->ip6r0_segleft)) 1048 Printf("(Current)"); 1049 gw_addr++; 1050 if (i != num_addr - 1) 1051 Printf(", "); 1052 } 1053 } 1054 } 1055