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