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