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