1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997 9 * The Regents of the University of California. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that: (1) source code distributions 13 * retain the above copyright notice and this paragraph in its entirety, (2) 14 * distributions including binary code include the above copyright notice and 15 * this paragraph in its entirety in the documentation or other materials 16 * provided with the distribution, and (3) all advertising materials mentioning 17 * features or use of this software display the following acknowledgement: 18 * ``This product includes software developed by the University of California, 19 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 20 * the University nor the names of its contributors may be used to endorse 21 * or promote products derived from this software without specific prior 22 * written permission. 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 24 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 26 * 27 * 28 * @(#)$Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp $ (LBL) 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <sys/socket.h> 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <ctype.h> 38 #include <strings.h> 39 #include <libintl.h> 40 #include <errno.h> 41 #include <netdb.h> 42 43 #include <netinet/in_systm.h> 44 #include <netinet/in.h> 45 #include <netinet/ip.h> 46 #include <netinet/ip_var.h> 47 #include <netinet/ip_icmp.h> 48 #include <netinet/udp.h> 49 #include <netinet/udp_var.h> 50 #include <netinet/ip6.h> 51 #include <netinet/icmp6.h> 52 53 #include <arpa/inet.h> 54 55 #include <libinetutil.h> 56 #include "traceroute.h" 57 58 int check_reply6(struct msghdr *, int, int, uchar_t *, uchar_t *); 59 void *find_ancillary_data(struct msghdr *, int, int); 60 extern char *inet_name(union any_in_addr *, int); 61 static int IPv6_hdrlen(ip6_t *, int, uint8_t *); 62 static char *pr_type6(uchar_t); 63 void print_addr6(uchar_t *, int, struct sockaddr *); 64 boolean_t print_icmp_other6(uchar_t, uchar_t); 65 void send_probe6(int, struct msghdr *, struct ip *, int, int, 66 struct timeval *, int); 67 void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int, uint_t); 68 struct ip *set_buffers6(int); 69 static boolean_t update_hoplimit_ancillary_data(struct msghdr *, int); 70 71 /* 72 * prepares the buffer to be sent as an IP datagram 73 */ 74 struct ip * 75 set_buffers6(int plen) 76 { 77 struct ip *outip; 78 uchar_t *outp; 79 struct udphdr *outudp; 80 struct icmp *outicmp; 81 int optlen = 0; 82 83 outip = (struct ip *)malloc((size_t)plen); 84 if (outip == NULL) { 85 Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); 86 exit(EXIT_FAILURE); 87 } 88 89 if (gw_count > 0) { 90 /* ip6_rthdr0 structure includes one gateway address */ 91 optlen = sizeof (struct ip6_rthdr0) + 92 gw_count * sizeof (struct in6_addr); 93 } 94 95 (void) memset((char *)outip, 0, (size_t)plen); 96 outp = (uchar_t *)(outip + 1); 97 98 if (useicmp) { 99 /* LINTED E_BAD_PTR_CAST_ALIGN */ 100 outicmp = (struct icmp *)outp; 101 outicmp->icmp_type = ICMP6_ECHO_REQUEST; 102 outicmp->icmp_id = htons(ident); 103 } else { 104 /* LINTED E_BAD_PTR_CAST_ALIGN */ 105 outudp = (struct udphdr *)outp; 106 /* 107 * "source port" is set at bind() call, so we don't do it 108 * again 109 */ 110 outudp->uh_ulen = htons((ushort_t)(plen - 111 (sizeof (struct ip6_hdr) + optlen))); 112 } 113 114 return (outip); 115 } 116 117 /* 118 * Initialize the msghdr for specifying hoplimit, outgoing interface and routing 119 * header for the probe packets. 120 */ 121 void 122 set_ancillary_data(struct msghdr *msgp, int hoplimit, 123 union any_in_addr *gwIPlist, int gw_cnt, uint_t if_index) 124 { 125 size_t hoplimit_space; 126 size_t rthdr_space; 127 size_t pktinfo_space; 128 size_t bufspace; 129 struct cmsghdr *cmsgp; 130 uchar_t *cmsg_datap; 131 int i; 132 133 msgp->msg_control = NULL; 134 msgp->msg_controllen = 0; 135 136 /* 137 * Need to figure out size of buffer needed for ancillary data 138 * containing routing header and packet info options. 139 * 140 * Portable heuristic to compute upper bound on space needed for 141 * N ancillary data options. It assumes up to _MAX_ALIGNMENT padding 142 * after both header and data as the worst possible upper bound on space 143 * consumed by padding. 144 * It also adds one extra "sizeof (struct cmsghdr)" for the last option. 145 * This is needed because we would like to use CMSG_NXTHDR() while 146 * composing the buffer. The CMSG_NXTHDR() macro is designed better for 147 * parsing than composing the buffer. It requires the pointer it returns 148 * to leave space in buffer for addressing a cmsghdr and we want to make 149 * sure it works for us while we skip beyond the last ancillary data 150 * option. 151 * 152 * bufspace[i] = sizeof(struct cmsghdr) + <pad after header> + 153 * <option[i] content length> + <pad after data>; 154 * 155 * total_bufspace = bufspace[0] + bufspace[1] + ... 156 * ... + bufspace[N-1] + sizeof (struct cmsghdr); 157 */ 158 159 rthdr_space = 0; 160 pktinfo_space = 0; 161 /* We'll always set the hoplimit of the outgoing packets */ 162 hoplimit_space = sizeof (int); 163 bufspace = sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 164 hoplimit_space + _MAX_ALIGNMENT; 165 166 if (gw_cnt > 0) { 167 rthdr_space = inet6_rth_space(IPV6_RTHDR_TYPE_0, gw_cnt); 168 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 169 rthdr_space + _MAX_ALIGNMENT; 170 } 171 172 if (if_index != 0) { 173 pktinfo_space = sizeof (struct in6_pktinfo); 174 bufspace += sizeof (struct cmsghdr) + _MAX_ALIGNMENT + 175 pktinfo_space + _MAX_ALIGNMENT; 176 } 177 178 /* 179 * We need to temporarily set the msgp->msg_controllen to bufspace 180 * (we will later trim it to actual length used). This is needed because 181 * CMSG_NXTHDR() uses it to check we have not exceeded the bounds. 182 */ 183 bufspace += sizeof (struct cmsghdr); 184 msgp->msg_controllen = bufspace; 185 186 msgp->msg_control = (struct cmsghdr *)malloc(bufspace); 187 if (msgp->msg_control == NULL) { 188 Fprintf(stderr, "%s: malloc %s\n", prog, strerror(errno)); 189 exit(EXIT_FAILURE); 190 } 191 cmsgp = CMSG_FIRSTHDR(msgp); 192 193 /* 194 * Fill ancillary data. First hoplimit, then rthdr and pktinfo if 195 * needed. 196 */ 197 198 /* set hoplimit ancillary data */ 199 cmsgp->cmsg_level = IPPROTO_IPV6; 200 cmsgp->cmsg_type = IPV6_HOPLIMIT; 201 cmsg_datap = CMSG_DATA(cmsgp); 202 /* LINTED E_BAD_PTR_CAST_ALIGN */ 203 *(int *)cmsg_datap = hoplimit; 204 cmsgp->cmsg_len = cmsg_datap + hoplimit_space - (uchar_t *)cmsgp; 205 cmsgp = CMSG_NXTHDR(msgp, cmsgp); 206 207 /* set rthdr ancillary data if needed */ 208 if (gw_cnt > 0) { 209 struct ip6_rthdr0 *rthdr0p; 210 211 cmsgp->cmsg_level = IPPROTO_IPV6; 212 cmsgp->cmsg_type = IPV6_RTHDR; 213 cmsg_datap = CMSG_DATA(cmsgp); 214 215 /* 216 * Initialize rthdr structure 217 */ 218 /* LINTED E_BAD_PTR_CAST_ALIGN */ 219 rthdr0p = (struct ip6_rthdr0 *)cmsg_datap; 220 if (inet6_rth_init(rthdr0p, rthdr_space, 221 IPV6_RTHDR_TYPE_0, gw_cnt) == NULL) { 222 Fprintf(stderr, "%s: inet6_rth_init failed\n", 223 prog); 224 exit(EXIT_FAILURE); 225 } 226 227 /* 228 * Stuff in gateway addresses 229 */ 230 for (i = 0; i < gw_cnt; i++) { 231 if (inet6_rth_add(rthdr0p, 232 &gwIPlist[i].addr6) == -1) { 233 Fprintf(stderr, 234 "%s: inet6_rth_add\n", prog); 235 exit(EXIT_FAILURE); 236 } 237 } 238 239 cmsgp->cmsg_len = cmsg_datap + rthdr_space - (uchar_t *)cmsgp; 240 cmsgp = CMSG_NXTHDR(msgp, cmsgp); 241 } 242 243 /* set pktinfo ancillary data if needed */ 244 if (if_index != 0) { 245 struct in6_pktinfo *pktinfop; 246 247 cmsgp->cmsg_level = IPPROTO_IPV6; 248 cmsgp->cmsg_type = IPV6_PKTINFO; 249 cmsg_datap = CMSG_DATA(cmsgp); 250 251 /* LINTED E_BAD_PTR_CAST_ALIGN */ 252 pktinfop = (struct in6_pktinfo *)cmsg_datap; 253 /* 254 * We don't know if pktinfop->ipi6_addr is aligned properly, 255 * therefore let's use bcopy, instead of assignment. 256 */ 257 (void) bcopy(&in6addr_any, &pktinfop->ipi6_addr, 258 sizeof (struct in6_addr)); 259 260 /* 261 * We can assume pktinfop->ipi6_ifindex is 32 bit aligned. 262 */ 263 pktinfop->ipi6_ifindex = if_index; 264 cmsgp->cmsg_len = cmsg_datap + pktinfo_space - (uchar_t *)cmsgp; 265 cmsgp = CMSG_NXTHDR(msgp, cmsgp); 266 } 267 268 msgp->msg_controllen = (char *)cmsgp - (char *)msgp->msg_control; 269 } 270 271 /* 272 * Parses the given msg->msg_control to find the IPV6_HOPLIMIT ancillary data 273 * and update the hoplimit. 274 * Returns _B_FALSE if it can't find IPV6_HOPLIMIT ancillary data, _B_TRUE 275 * otherwise. 276 */ 277 static boolean_t 278 update_hoplimit_ancillary_data(struct msghdr *msg, int hoplimit) 279 { 280 struct cmsghdr *cmsg; 281 int *intp; 282 283 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 284 cmsg = CMSG_NXTHDR(msg, cmsg)) { 285 if (cmsg->cmsg_level == IPPROTO_IPV6 && 286 cmsg->cmsg_type == IPV6_HOPLIMIT) { 287 /* LINTED E_BAD_PTR_CAST_ALIGN */ 288 intp = (int *)(CMSG_DATA(cmsg)); 289 *intp = hoplimit; 290 return (_B_TRUE); 291 } 292 } 293 294 return (_B_FALSE); 295 } 296 297 /* 298 * send a probe packet to the destination 299 */ 300 void 301 send_probe6(int sndsock, struct msghdr *msg6, struct ip *outip, int seq, 302 int ttl, struct timeval *tp, int packlen) 303 { 304 uchar_t *outp; 305 struct icmp *outicmp; 306 struct outdata *outdata; 307 struct iovec iov; 308 int cc; 309 int optlen = 0; 310 int send_size; 311 struct sockaddr_in6 *to6; 312 313 if (gw_count > 0) { 314 /* ip6_rthdr0 structure includes one gateway address */ 315 optlen = sizeof (struct ip6_rthdr0) + 316 gw_count * sizeof (struct in6_addr); 317 } 318 319 send_size = packlen - sizeof (struct ip6_hdr) - optlen; 320 321 /* if using UDP, further discount UDP header size */ 322 if (!useicmp) 323 send_size -= sizeof (struct udphdr); 324 325 /* initialize buffer pointers */ 326 outp = (uchar_t *)(outip + 1); 327 /* LINTED E_BAD_PTR_CAST_ALIGN */ 328 outicmp = (struct icmp *)outp; 329 /* LINTED E_BAD_PTR_CAST_ALIGN */ 330 outdata = (struct outdata *)(outp + ICMP6_MINLEN); 331 332 if (!update_hoplimit_ancillary_data(msg6, ttl)) { 333 Fprintf(stderr, 334 "%s: can't find IPV6_HOPLIMIT ancillary data\n", prog); 335 exit(EXIT_FAILURE); 336 } 337 338 /* Payload */ 339 outdata->seq = seq; 340 outdata->ttl = ttl; 341 outdata->tv = *tp; 342 343 if (useicmp) { 344 outicmp->icmp_seq = htons(seq); 345 } else { 346 to6 = (struct sockaddr_in6 *)msg6->msg_name; 347 to6->sin6_port = htons((port + seq) % (MAX_PORT + 1)); 348 } 349 350 iov.iov_base = outp; 351 iov.iov_len = send_size; 352 353 msg6->msg_iov = &iov; 354 msg6->msg_iovlen = 1; 355 356 cc = sendmsg(sndsock, msg6, 0); 357 358 if (cc < 0 || cc != send_size) { 359 if (cc < 0) { 360 Fprintf(stderr, "%s: sendmsg: %s\n", prog, 361 strerror(errno)); 362 } 363 Printf("%s: wrote %s %d chars, ret=%d\n", 364 prog, hostname, send_size, cc); 365 (void) fflush(stdout); 366 } 367 } 368 369 /* 370 * Return a pointer to the ancillary data for the given cmsg_level and 371 * cmsg_type. 372 * If not found return NULL. 373 */ 374 void * 375 find_ancillary_data(struct msghdr *msg, int cmsg_level, int cmsg_type) 376 { 377 struct cmsghdr *cmsg; 378 379 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 380 cmsg = CMSG_NXTHDR(msg, cmsg)) { 381 if (cmsg->cmsg_level == cmsg_level && 382 cmsg->cmsg_type == cmsg_type) { 383 return (CMSG_DATA(cmsg)); 384 } 385 } 386 return (NULL); 387 } 388 389 /* 390 * Check out the reply packet to see if it's what we were expecting. 391 * Returns REPLY_GOT_TARGET if the reply comes from the target 392 * REPLY_GOT_GATEWAY if an intermediate gateway sends TIME_EXCEEDED 393 * REPLY_GOT_OTHER for other kinds of unreachables indicating none of 394 * the above two cases 395 * 396 * It also sets the icmp type and icmp code values 397 */ 398 int 399 check_reply6(struct msghdr *msg, int cc, int seq, uchar_t *type, uchar_t *code) 400 { 401 uchar_t *buf = msg->msg_iov->iov_base; 402 struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)msg->msg_name; 403 icmp6_t *icp6; 404 ulong_t ip6hdr_len; 405 uint8_t last_hdr; 406 int save_cc = cc; 407 char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */ 408 409 /* Ignore packets > 64k or control buffers that don't fit */ 410 if (msg->msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 411 if (verbose) { 412 Printf("Truncated message: msg_flags 0x%x from %s\n", 413 msg->msg_flags, 414 inet_ntop(AF_INET6, 415 (void *)&(from_in6->sin6_addr), 416 temp_buf, sizeof (temp_buf))); 417 } 418 return (REPLY_SHORT_PKT); 419 } 420 if (cc < ICMP6_MINLEN) { 421 if (verbose) { 422 Printf("packet too short (%d bytes) from %s\n", 423 cc, 424 inet_ntop(AF_INET6, 425 (void *)&(from_in6->sin6_addr), 426 temp_buf, sizeof (temp_buf))); 427 } 428 return (REPLY_SHORT_PKT); 429 } 430 /* LINTED E_BAD_PTR_CAST_ALIGN */ 431 icp6 = (icmp6_t *)buf; 432 *type = icp6->icmp6_type; 433 *code = icp6->icmp6_code; 434 435 /* 436 * traceroute interprets only ICMP6_TIME_EXCEED_TRANSIT, 437 * ICMP6_DST_UNREACH, ICMP6_ECHO_REPLY, ICMP6_PACKET_TOO_BIG and 438 * ICMP6_PARAMPROB_NEXTHEADER, ignores others 439 */ 440 if ((*type == ICMP6_TIME_EXCEEDED && 441 *code == ICMP6_TIME_EXCEED_TRANSIT) || 442 *type == ICMP6_DST_UNREACH || *type == ICMP6_ECHO_REPLY || 443 *type == ICMP6_PACKET_TOO_BIG || 444 (*type == ICMP6_PARAM_PROB && 445 *code == ICMP6_PARAMPROB_NEXTHEADER)) { 446 ip6_t *hip6; 447 struct udphdr *up; 448 icmp6_t *hicmp6; 449 450 cc -= ICMP6_MINLEN; 451 hip6 = (ip6_t *)&(icp6->icmp6_data32[1]); 452 last_hdr = hip6->ip6_nxt; 453 ip6hdr_len = IPv6_hdrlen(hip6, cc, &last_hdr); 454 455 cc -= ip6hdr_len; 456 if (useicmp) { 457 if (*type == ICMP6_ECHO_REPLY && 458 icp6->icmp6_id == htons(ident) && 459 icp6->icmp6_seq == htons(seq)) { 460 return (REPLY_GOT_TARGET); 461 } 462 463 /* LINTED E_BAD_PTR_CAST_ALIGN */ 464 hicmp6 = (icmp6_t *)((uchar_t *)hip6 + ip6hdr_len); 465 466 if (ICMP6_MINLEN <= cc && 467 last_hdr == IPPROTO_ICMPV6 && 468 hicmp6->icmp6_id == htons(ident) && 469 hicmp6->icmp6_seq == htons(seq)) { 470 if (*type == ICMP6_TIME_EXCEEDED) { 471 return (REPLY_GOT_GATEWAY); 472 } else { 473 return (REPLY_GOT_OTHER); 474 } 475 } 476 } else { 477 /* LINTED E_BAD_PTR_CAST_ALIGN */ 478 up = (struct udphdr *)((uchar_t *)hip6 + ip6hdr_len); 479 /* 480 * at least 4 bytes of UDP header is required for this 481 * check 482 */ 483 if (4 <= cc && 484 last_hdr == IPPROTO_UDP && 485 up->uh_sport == htons(ident) && 486 up->uh_dport == htons((port + seq) % 487 (MAX_PORT + 1))) { 488 if (*type == ICMP6_DST_UNREACH && 489 *code == ICMP6_DST_UNREACH_NOPORT) { 490 return (REPLY_GOT_TARGET); 491 } else if (*type == ICMP6_TIME_EXCEEDED) { 492 return (REPLY_GOT_GATEWAY); 493 } else { 494 return (REPLY_GOT_OTHER); 495 } 496 } 497 } 498 } 499 500 if (verbose) { 501 int i, j; 502 uchar_t *lp = (uchar_t *)icp6; 503 struct in6_addr *dst; 504 struct in6_pktinfo *pkti; 505 506 pkti = (struct in6_pktinfo *)find_ancillary_data(msg, 507 IPPROTO_IPV6, IPV6_PKTINFO); 508 if (pkti == NULL) { 509 Fprintf(stderr, 510 "%s: can't find IPV6_PKTINFO ancillary data\n", 511 prog); 512 exit(EXIT_FAILURE); 513 } 514 dst = &pkti->ipi6_addr; 515 cc = save_cc; 516 Printf("\n%d bytes from %s to ", cc, 517 inet_ntop(AF_INET6, (const void *)&(from_in6->sin6_addr), 518 temp_buf, sizeof (temp_buf))); 519 Printf("%s: icmp type %d (%s) code %d\n", 520 inet_ntop(AF_INET6, (const void *)dst, 521 temp_buf, sizeof (temp_buf)), 522 *type, pr_type6(*type), *code); 523 for (i = 0; i < cc; i += 4) { 524 Printf("%2d: x", i); 525 for (j = 0; ((j < 4) && ((i + j) < cc)); j++) 526 Printf("%2.2x", *lp++); 527 (void) putchar('\n'); 528 } 529 } 530 531 return (REPLY_SHORT_PKT); 532 } 533 534 /* 535 * Return the length of the IPv6 related headers (including extension headers) 536 */ 537 static int 538 IPv6_hdrlen(ip6_t *ip6h, int pkt_len, uint8_t *last_hdr_rtrn) 539 { 540 int length; 541 int exthdrlength; 542 uint8_t nexthdr; 543 uint8_t *whereptr; 544 ip6_hbh_t *hbhhdr; 545 ip6_dest_t *desthdr; 546 ip6_rthdr_t *rthdr; 547 ip6_frag_t *fraghdr; 548 uint8_t *endptr; 549 550 length = sizeof (ip6_t); 551 552 whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */ 553 endptr = ((uint8_t *)ip6h) + pkt_len; 554 555 nexthdr = ip6h->ip6_nxt; 556 *last_hdr_rtrn = IPPROTO_NONE; 557 558 if (whereptr >= endptr) 559 return (length); 560 561 while (whereptr < endptr) { 562 *last_hdr_rtrn = nexthdr; 563 switch (nexthdr) { 564 case IPPROTO_HOPOPTS: 565 hbhhdr = (ip6_hbh_t *)whereptr; 566 exthdrlength = 8 * (hbhhdr->ip6h_len + 1); 567 if ((uchar_t *)hbhhdr + exthdrlength > endptr) 568 return (length); 569 nexthdr = hbhhdr->ip6h_nxt; 570 length += exthdrlength; 571 break; 572 573 case IPPROTO_DSTOPTS: 574 desthdr = (ip6_dest_t *)whereptr; 575 exthdrlength = 8 * (desthdr->ip6d_len + 1); 576 if ((uchar_t *)desthdr + exthdrlength > endptr) 577 return (length); 578 nexthdr = desthdr->ip6d_nxt; 579 length += exthdrlength; 580 break; 581 582 case IPPROTO_ROUTING: 583 rthdr = (ip6_rthdr_t *)whereptr; 584 exthdrlength = 8 * (rthdr->ip6r_len + 1); 585 if ((uchar_t *)rthdr + exthdrlength > endptr) 586 return (length); 587 nexthdr = rthdr->ip6r_nxt; 588 length += exthdrlength; 589 break; 590 591 case IPPROTO_FRAGMENT: 592 /* LINTED E_BAD_PTR_CAST_ALIGN */ 593 fraghdr = (ip6_frag_t *)whereptr; 594 if ((uchar_t *)&fraghdr[1] > endptr) 595 return (length); 596 nexthdr = fraghdr->ip6f_nxt; 597 length += sizeof (struct ip6_frag); 598 break; 599 600 case IPPROTO_NONE: 601 default: 602 return (length); 603 } 604 whereptr = (uint8_t *)ip6h + length; 605 } 606 *last_hdr_rtrn = nexthdr; 607 608 return (length); 609 } 610 611 /* 612 * convert an ICMP6 "type" field to a printable string. 613 */ 614 static char * 615 pr_type6(uchar_t type) 616 { 617 static struct icmptype_table ttab6[] = { 618 {ICMP6_DST_UNREACH, "Dest Unreachable"}, 619 {ICMP6_PACKET_TOO_BIG, "Packet Too Big"}, 620 {ICMP6_TIME_EXCEEDED, "Time Exceeded"}, 621 {ICMP6_PARAM_PROB, "Param Problem"}, 622 {ICMP6_ECHO_REQUEST, "Echo Request"}, 623 {ICMP6_ECHO_REPLY, "Echo Reply"}, 624 {MLD_LISTENER_QUERY, "Multicast Listener Query"}, 625 {MLD_LISTENER_REPORT, "Multicast Listener Report"}, 626 {MLD_LISTENER_REDUCTION, "Multicast Listener Done"}, 627 {ND_ROUTER_SOLICIT, "Router Solicitation"}, 628 {ND_ROUTER_ADVERT, "Router Advertisement"}, 629 {ND_NEIGHBOR_SOLICIT, "Neighbor Solicitation"}, 630 {ND_NEIGHBOR_ADVERT, "Neighbor Advertisement"}, 631 {ND_REDIRECT, "Redirect Message"} 632 }; 633 int i = 0; 634 635 for (i = 0; i < A_CNT(ttab6); i++) { 636 if (ttab6[i].type == type) 637 return (ttab6[i].message); 638 } 639 640 return ("OUT-OF-RANGE"); 641 } 642 643 644 /* 645 * print the IPv6 src address of the reply packet 646 */ 647 void 648 print_addr6(uchar_t *buf, int cc, struct sockaddr *from) 649 { 650 /* LINTED E_BAD_PTR_CAST_ALIGN */ 651 struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)from; 652 ip6_t *ip; 653 union any_in_addr ip_addr; 654 char *resolved_name; 655 char temp_buf[INET6_ADDRSTRLEN]; /* use for inet_ntop() */ 656 657 ip_addr.addr6 = from_in6->sin6_addr; 658 659 /* LINTED E_BAD_PTR_CAST_ALIGN */ 660 ip = (ip6_t *)buf; 661 662 (void) inet_ntop(AF_INET6, &(from_in6->sin6_addr), temp_buf, 663 sizeof (temp_buf)); 664 if (!nflag) 665 resolved_name = inet_name(&ip_addr, AF_INET6); 666 /* 667 * If the IPv6 address cannot be resolved to hostname, inet_name() 668 * returns the IPv6 address as a string. In that case, we choose not 669 * to print it twice. This saves us space on display. 670 */ 671 if (nflag || (strcmp(temp_buf, resolved_name) == 0)) 672 Printf(" %s", temp_buf); 673 else 674 Printf(" %s (%s)", resolved_name, temp_buf); 675 676 if (verbose) { 677 Printf(" %d bytes to %s", cc, inet_ntop(AF_INET6, 678 (const void *) &(ip->ip6_dst), temp_buf, 679 sizeof (temp_buf))); 680 } 681 } 682 683 /* 684 * ICMP6 messages which doesn't mean we got the target, or we got a gateway, are 685 * processed here. It returns _B_TRUE if it's some sort of 'unreachable'. 686 */ 687 boolean_t 688 print_icmp_other6(uchar_t type, uchar_t code) 689 { 690 boolean_t unreach = _B_FALSE; 691 692 switch (type) { 693 694 /* this corresponds to "ICMP_UNREACH_NEEDFRAG" in ICMP */ 695 case ICMP6_PACKET_TOO_BIG: 696 unreach = _B_TRUE; 697 Printf(" !B"); 698 break; 699 700 case ICMP6_PARAM_PROB: 701 /* this corresponds to "ICMP_UNREACH_PROTOCOL" in ICMP */ 702 if (code == ICMP6_PARAMPROB_NEXTHEADER) { 703 unreach = _B_TRUE; 704 Printf(" !R"); 705 } 706 break; 707 708 case ICMP6_DST_UNREACH: 709 switch (code) { 710 case ICMP6_DST_UNREACH_NOPORT: 711 break; 712 713 case ICMP6_DST_UNREACH_NOROUTE: 714 unreach = _B_TRUE; 715 Printf(" !H"); 716 break; 717 718 case ICMP6_DST_UNREACH_ADMIN: 719 unreach = _B_TRUE; 720 Printf(" !X"); 721 break; 722 723 case ICMP6_DST_UNREACH_ADDR: 724 unreach = _B_TRUE; 725 Printf(" !A"); 726 break; 727 728 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 729 unreach = _B_TRUE; 730 Printf(" !E"); 731 break; 732 733 default: 734 unreach = _B_TRUE; 735 Printf(" !<%d>", code); 736 break; 737 } 738 break; 739 default: 740 break; 741 } 742 743 return (unreach); 744 } 745