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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <string.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <net/if.h> 33 #include <sys/stropts.h> 34 #include <sys/sysmacros.h> 35 #include <netinet/in_systm.h> 36 #include <netinet/in.h> 37 #include <netinet/ip.h> 38 #include <netinet/ip_icmp.h> 39 #include <netinet/udp.h> 40 #include <netinet/tcp.h> 41 #include <netinet/icmp6.h> 42 #include <netinet/ip6.h> 43 #include <inet/ip.h> 44 #include <inet/ip6.h> 45 #include <arpa/inet.h> 46 #include <netdb.h> 47 #include "snoop.h" 48 #include "snoop_mip.h" 49 50 static void interpret_options(char *, int); 51 static void interpret_mldv2qry(icmp6_t *, int); 52 static void interpret_mldv2rpt(icmp6_t *, int); 53 54 55 /* Mobile-IP routines from snoop_mip.c */ 56 extern void interpret_icmp_mip_ext(uchar_t *, int); 57 extern const char *get_mip_adv_desc(uint8_t); 58 59 /* Router advertisement message structure. */ 60 struct icmp_ra_addr { 61 uint32_t addr; 62 uint32_t preference; 63 }; 64 65 /*ARGSUSED*/ 66 void 67 interpret_icmp(int flags, struct icmp *icmp, int iplen, int ilen) 68 { 69 char *pt, *pc, *px; 70 char *line; 71 char buff[67627]; /* Router adv. can have 256 routers .... */ 72 /* Each router has a name 256 char long .. */ 73 char extbuff[MAXHOSTNAMELEN + 1]; 74 struct udphdr *orig_uhdr; 75 int num_rtr_addrs = 0; 76 extern char *prot_nest_prefix; 77 78 if (ilen < ICMP_MINLEN) 79 return; /* incomplete header */ 80 81 pt = "Unknown"; 82 pc = ""; 83 px = ""; 84 85 switch (icmp->icmp_type) { 86 case ICMP_ECHOREPLY: 87 pt = "Echo reply"; 88 (void) sprintf(buff, "ID: %d Sequence number: %d", 89 ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 90 pc = buff; 91 break; 92 case ICMP_UNREACH: 93 pt = "Destination unreachable"; 94 switch (icmp->icmp_code) { 95 case ICMP_UNREACH_NET: 96 if (ilen >= ICMP_ADVLENMIN) { 97 (void) sprintf(buff, "Net %s unreachable", 98 addrtoname(AF_INET, 99 &icmp->icmp_ip.ip_dst)); 100 pc = buff; 101 } else { 102 pc = "Bad net"; 103 } 104 break; 105 case ICMP_UNREACH_HOST: 106 if (ilen >= ICMP_ADVLENMIN) { 107 (void) sprintf(buff, "Host %s unreachable", 108 addrtoname(AF_INET, 109 &icmp->icmp_ip.ip_dst)); 110 pc = buff; 111 } else { 112 pc = "Bad host"; 113 } 114 break; 115 case ICMP_UNREACH_PROTOCOL: 116 if (ilen >= ICMP_ADVLENMIN) { 117 (void) sprintf(buff, "Bad protocol %d", 118 icmp->icmp_ip.ip_p); 119 pc = buff; 120 } else { 121 pc = "Bad protocol"; 122 } 123 break; 124 case ICMP_UNREACH_PORT: 125 if (ilen >= ICMP_ADVLENMIN) { 126 orig_uhdr = (struct udphdr *)((uchar_t *)icmp + 127 ICMP_MINLEN + icmp->icmp_ip.ip_hl * 4); 128 switch (icmp->icmp_ip.ip_p) { 129 case IPPROTO_TCP: 130 (void) sprintf(buff, "TCP port %d" 131 " unreachable", 132 ntohs(orig_uhdr->uh_dport)); 133 pc = buff; 134 break; 135 case IPPROTO_UDP: 136 (void) sprintf(buff, "UDP port %d" 137 " unreachable", 138 ntohs(orig_uhdr->uh_dport)); 139 pc = buff; 140 break; 141 default: 142 pc = "Port unreachable"; 143 break; 144 } 145 } else { 146 pc = "Bad port"; 147 } 148 break; 149 case ICMP_UNREACH_NEEDFRAG: 150 if (ntohs(icmp->icmp_nextmtu) != 0) { 151 (void) sprintf(buff, "Needed to fragment:" 152 " next hop MTU = %d", 153 ntohs(icmp->icmp_nextmtu)); 154 pc = buff; 155 } else { 156 pc = "Needed to fragment"; 157 } 158 break; 159 case ICMP_UNREACH_SRCFAIL: 160 pc = "Source route failed"; 161 break; 162 case ICMP_UNREACH_NET_UNKNOWN: 163 pc = "Unknown network"; 164 break; 165 case ICMP_UNREACH_HOST_UNKNOWN: 166 pc = "Unknown host"; 167 break; 168 case ICMP_UNREACH_ISOLATED: 169 pc = "Source host isolated"; 170 break; 171 case ICMP_UNREACH_NET_PROHIB: 172 pc = "Net administratively prohibited"; 173 break; 174 case ICMP_UNREACH_HOST_PROHIB: 175 pc = "Host administratively prohibited"; 176 break; 177 case ICMP_UNREACH_TOSNET: 178 pc = "Net unreachable for this TOS"; 179 break; 180 case ICMP_UNREACH_TOSHOST: 181 pc = "Host unreachable for this TOS"; 182 break; 183 case ICMP_UNREACH_FILTER_PROHIB: 184 pc = "Communication administratively prohibited"; 185 break; 186 case ICMP_UNREACH_HOST_PRECEDENCE: 187 pc = "Host precedence violation"; 188 break; 189 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 190 pc = "Precedence cutoff in effect"; 191 break; 192 default: 193 break; 194 } 195 break; 196 case ICMP_SOURCEQUENCH: 197 pt = "Packet lost, slow down"; 198 break; 199 case ICMP_REDIRECT: 200 pt = "Redirect"; 201 switch (icmp->icmp_code) { 202 case ICMP_REDIRECT_NET: 203 pc = "for network"; 204 break; 205 case ICMP_REDIRECT_HOST: 206 pc = "for host"; 207 break; 208 case ICMP_REDIRECT_TOSNET: 209 pc = "for tos and net"; 210 break; 211 case ICMP_REDIRECT_TOSHOST: 212 pc = "for tos and host"; 213 break; 214 default: 215 break; 216 } 217 (void) sprintf(buff, "%s %s to %s", 218 pc, addrtoname(AF_INET, &icmp->icmp_ip.ip_dst), 219 addrtoname(AF_INET, &icmp->icmp_gwaddr)); 220 pc = buff; 221 break; 222 case ICMP_ECHO: 223 pt = "Echo request"; 224 (void) sprintf(buff, "ID: %d Sequence number: %d", 225 ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 226 pc = buff; 227 break; 228 case ICMP_ROUTERADVERT: 229 230 #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs 231 #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa 232 #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime 233 234 pt = "Router advertisement"; 235 (void) sprintf(buff, "Lifetime %ds [%d]:", 236 ntohs(icmp->icmp_lifetime), icmp->icmp_num_addrs); 237 if (icmp->icmp_wpa == 2) { 238 struct icmp_ra_addr *ra; 239 char ra_buf[MAXHOSTNAMELEN + 32]; 240 char ra_ext_buf[50]; 241 struct in_addr sin; 242 int icmp_ra_len; 243 int i; 244 245 /* Cannot trust anything from the network... */ 246 num_rtr_addrs = MIN((ilen - ICMP_MINLEN) / 8, 247 icmp->icmp_num_addrs); 248 249 ra = (struct icmp_ra_addr *)icmp->icmp_data; 250 for (i = 0; i < num_rtr_addrs; i++) { 251 sin.s_addr = ra->addr; 252 (void) snprintf(ra_buf, sizeof (ra_buf), 253 " {%s %u}", 254 addrtoname(AF_INET, &sin), 255 ntohl(ra->preference)); 256 if (strlcat(buff, ra_buf, sizeof (buff)) >= 257 sizeof (buff)) { 258 buff[sizeof (buff) - 259 strlen("<Too Long>)")] = '\0'; 260 (void) strlcat(buff, "<Too Long>", 261 sizeof (buff)); 262 break; 263 } 264 ra++; 265 } 266 267 icmp_ra_len = ICMP_MINLEN + num_rtr_addrs * 268 sizeof (struct icmp_ra_addr); 269 if (ilen > icmp_ra_len) { 270 int curr_len = ilen - icmp_ra_len; 271 int ocurr_len; 272 exthdr_t *exthdr = (exthdr_t *)ra; 273 274 extbuff[0] = '\0'; 275 276 while (curr_len > 0) { 277 /* Append Mobile-IP description */ 278 (void) snprintf(ra_ext_buf, 279 sizeof (ra_ext_buf), ", %s", 280 get_mip_adv_desc(exthdr->type)); 281 (void) strlcat(extbuff, ra_ext_buf, 282 sizeof (extbuff)); 283 284 /* Special case for padding */ 285 if (exthdr->type == 286 ICMP_ADV_MSG_PADDING_EXT) { 287 288 curr_len--; 289 exthdr = (exthdr_t *) 290 ((char *)exthdr + 1); 291 continue; 292 } 293 294 /* else normal extension */ 295 ocurr_len = curr_len; 296 curr_len -= sizeof (*exthdr) + 297 exthdr->length; 298 /* detect bad length */ 299 if (ocurr_len < curr_len) 300 break; 301 exthdr = (exthdr_t *) 302 ((char *)exthdr + 303 sizeof (*exthdr) + 304 exthdr->length); 305 } 306 px = extbuff; 307 } 308 pc = buff; 309 } 310 break; 311 case ICMP_ROUTERSOLICIT: 312 pt = "Router solicitation"; 313 break; 314 case ICMP_TIMXCEED: 315 pt = "Time exceeded"; 316 switch (icmp->icmp_code) { 317 case ICMP_TIMXCEED_INTRANS: 318 pc = "in transit"; 319 break; 320 case ICMP_TIMXCEED_REASS: 321 pc = "in reassembly"; 322 break; 323 default: 324 break; 325 } 326 break; 327 case ICMP_PARAMPROB: 328 pt = "IP parameter problem"; 329 switch (icmp->icmp_code) { 330 case ICMP_PARAMPROB_OPTABSENT: 331 pc = "Required option missing"; 332 break; 333 case ICMP_PARAMPROB_BADLENGTH: 334 pc = "Bad length"; 335 break; 336 case 0: /* Should this be the default? */ 337 (void) sprintf(buff, "Problem at octet %d\n", 338 icmp->icmp_pptr); 339 pc = buff; 340 default: 341 break; 342 } 343 break; 344 case ICMP_TSTAMP: 345 pt = "Timestamp request"; 346 break; 347 case ICMP_TSTAMPREPLY: 348 pt = "Timestamp reply"; 349 break; 350 case ICMP_IREQ: 351 pt = "Information request"; 352 break; 353 case ICMP_IREQREPLY: 354 pt = "Information reply"; 355 break; 356 case ICMP_MASKREQ: 357 pt = "Address mask request"; 358 break; 359 case ICMP_MASKREPLY: 360 pt = "Address mask reply"; 361 (void) sprintf(buff, "Mask = 0x%x", ntohl(icmp->icmp_mask)); 362 pc = buff; 363 break; 364 default: 365 break; 366 } 367 368 if (flags & F_SUM) { 369 line = get_sum_line(); 370 if (*pc) { 371 if (*px) { 372 (void) sprintf(line, "ICMP %s (%s)%s", 373 pt, pc, px); 374 } else { 375 (void) sprintf(line, "ICMP %s (%s)", pt, pc); 376 } 377 } else { 378 (void) sprintf(line, "ICMP %s", pt); 379 } 380 } 381 382 if (flags & F_DTAIL) { 383 show_header("ICMP: ", "ICMP Header", ilen); 384 show_space(); 385 (void) sprintf(get_line(0, 0), "Type = %d (%s)", 386 icmp->icmp_type, pt); 387 if (*pc) { 388 (void) sprintf(get_line(0, 0), "Code = %d (%s)", 389 icmp->icmp_code, pc); 390 } else { 391 (void) sprintf(get_line(0, 0), "Code = %d", 392 icmp->icmp_code); 393 } 394 (void) sprintf(get_line(0, 0), "Checksum = %x", 395 ntohs(icmp->icmp_cksum)); 396 397 if (icmp->icmp_type == ICMP_UNREACH || 398 icmp->icmp_type == ICMP_REDIRECT) { 399 if (ilen > 28) { 400 show_space(); 401 (void) sprintf(get_line(0, 0), 402 "[ subject header follows ]"); 403 show_space(); 404 prot_nest_prefix = "ICMP:"; 405 (void) interpret_ip(flags, 406 (struct ip *)icmp->icmp_data, 28); 407 prot_nest_prefix = ""; 408 } 409 } else if (icmp->icmp_type == ICMP_PARAMPROB) { 410 if (ilen > 28) { 411 show_space(); 412 (void) sprintf(get_line(0, 0), 413 "[ subject header follows ]"); 414 show_space(); 415 prot_nest_prefix = "ICMP:"; 416 (void) interpret_ip(flags, 417 (struct ip *)icmp->icmp_data, 28); 418 prot_nest_prefix = ""; 419 } 420 } else if (icmp->icmp_type == ICMP_ROUTERADVERT) { 421 if (icmp->icmp_wpa == 2) { 422 int icmp_ra_len; 423 424 show_space(); 425 icmp_ra_len = ICMP_MINLEN + 426 num_rtr_addrs * 427 sizeof (struct icmp_ra_addr); 428 prot_nest_prefix = ""; 429 if (ilen > icmp_ra_len) { 430 interpret_icmp_mip_ext( 431 (uchar_t *)icmp + icmp_ra_len, 432 ilen - icmp_ra_len); 433 } 434 } 435 } 436 show_space(); 437 } 438 } 439 440 /*ARGSUSED*/ 441 void 442 interpret_icmpv6(flags, icmp6, iplen, ilen) 443 int flags; 444 icmp6_t *icmp6; 445 int iplen, ilen; 446 { 447 char *pt, *pc; 448 char *line; 449 extern char *prot_nest_prefix; 450 char addrstr[INET6_ADDRSTRLEN]; 451 char buff[2048]; 452 453 if (ilen < ICMP6_MINLEN) 454 return; /* incomplete header */ 455 456 pt = "Unknown"; 457 pc = ""; 458 459 switch (icmp6->icmp6_type) { 460 case ICMP6_DST_UNREACH: 461 pt = "Destination unreachable"; 462 switch (icmp6->icmp6_code) { 463 case ICMP6_DST_UNREACH_NOROUTE: 464 pc = "No route to destination"; 465 break; 466 case ICMP6_DST_UNREACH_ADMIN: 467 pc = "Communication administratively prohibited"; 468 break; 469 case ICMP6_DST_UNREACH_ADDR: 470 pc = "Address unreachable"; 471 break; 472 case ICMP6_DST_UNREACH_NOPORT: 473 if (ilen >= ICMP6_MINLEN + IPV6_HDR_LEN + 474 sizeof (struct udphdr)) { 475 476 ip6_t *orig_ip6hdr = (ip6_t *)&icmp6[1]; 477 478 switch (orig_ip6hdr->ip6_nxt) { 479 case IPPROTO_TCP: { 480 struct tcphdr *orig_thdr = 481 (struct tcphdr *)&orig_ip6hdr[1]; 482 483 (void) sprintf(buff, "TCP port %hu" 484 " unreachable", 485 ntohs(orig_thdr->th_dport)); 486 pc = buff; 487 break; 488 } 489 case IPPROTO_UDP: { 490 struct udphdr *orig_uhdr = 491 (struct udphdr *)&orig_ip6hdr[1]; 492 493 (void) sprintf(buff, "UDP port %hu" 494 " unreachable", 495 ntohs(orig_uhdr->uh_dport)); 496 pc = buff; 497 break; 498 } 499 default: 500 pc = "Port unreachable"; 501 break; 502 } 503 } else { 504 pc = "Bad port"; 505 } 506 break; 507 default: 508 break; 509 } 510 break; 511 case ICMP6_PACKET_TOO_BIG: 512 pt = "Packet too big"; 513 break; 514 case ND_REDIRECT: 515 pt = "Redirect"; 516 break; 517 case ICMP6_TIME_EXCEEDED: 518 pt = "Time exceeded"; 519 switch (icmp6->icmp6_code) { 520 case ICMP6_TIME_EXCEED_TRANSIT: 521 pc = "Hop limit exceeded in transit"; 522 break; 523 case ICMP6_TIME_EXCEED_REASSEMBLY: 524 pc = "Fragment reassembly time exceeded"; 525 break; 526 default: 527 break; 528 } 529 break; 530 case ICMP6_PARAM_PROB: 531 pt = "Parameter problem"; 532 switch (icmp6->icmp6_code) { 533 case ICMP6_PARAMPROB_HEADER: 534 pc = "Erroneous header field"; 535 break; 536 case ICMP6_PARAMPROB_NEXTHEADER: 537 pc = "Unrecognized next header type"; 538 break; 539 case ICMP6_PARAMPROB_OPTION: 540 pc = "Unrecognized IPv6 option"; 541 break; 542 } 543 break; 544 case ICMP6_ECHO_REQUEST: 545 pt = "Echo request"; 546 (void) sprintf(buff, "ID: %d Sequence number: %d", 547 ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 548 pc = buff; 549 break; 550 case ICMP6_ECHO_REPLY: 551 pt = "Echo reply"; 552 (void) sprintf(buff, "ID: %d Sequence number: %d", 553 ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 554 pc = buff; 555 break; 556 case MLD_LISTENER_QUERY: 557 if (ilen == MLD_MINLEN) 558 pt = "Group membership query - MLDv1"; 559 else if (ilen >= MLD_V2_QUERY_MINLEN) 560 pt = "Group membership query - MLDv2"; 561 else 562 pt = "Unknown membership query"; 563 break; 564 case MLD_LISTENER_REPORT: 565 pt = "Group membership report - MLDv1"; 566 break; 567 case MLD_LISTENER_REDUCTION: 568 pt = "Group membership termination - MLDv1"; 569 break; 570 case MLD_V2_LISTENER_REPORT: 571 pt = "Group membership report - MLDv2"; 572 break; 573 case ND_ROUTER_SOLICIT: 574 pt = "Router solicitation"; 575 break; 576 case ND_ROUTER_ADVERT: 577 pt = "Router advertisement"; 578 break; 579 case ND_NEIGHBOR_SOLICIT: 580 pt = "Neighbor solicitation"; 581 break; 582 case ND_NEIGHBOR_ADVERT: 583 pt = "Neighbor advertisement"; 584 break; 585 default: 586 break; 587 } 588 589 if (flags & F_SUM) { 590 line = get_sum_line(); 591 if (*pc) 592 (void) sprintf(line, "ICMPv6 %s (%s)", pt, pc); 593 else 594 (void) sprintf(line, "ICMPv6 %s", pt); 595 } 596 597 if (flags & F_DTAIL) { 598 show_header("ICMPv6: ", "ICMPv6 Header", ilen); 599 show_space(); 600 (void) sprintf(get_line(0, 0), "Type = %d (%s)", 601 icmp6->icmp6_type, pt); 602 if (*pc) 603 (void) sprintf(get_line(0, 0), "Code = %d (%s)", 604 icmp6->icmp6_code, pc); 605 else 606 (void) sprintf(get_line(0, 0), "Code = %d", 607 icmp6->icmp6_code); 608 (void) sprintf(get_line(0, 0), "Checksum = %x", 609 ntohs(icmp6->icmp6_cksum)); 610 611 switch (icmp6->icmp6_type) { 612 case ICMP6_DST_UNREACH: 613 if (ilen > ICMP6_MINLEN + IPV6_HDR_LEN) { 614 show_space(); 615 (void) sprintf(get_line(0, 0), 616 "[ subject header follows ]"); 617 show_space(); 618 prot_nest_prefix = "ICMPv6:"; 619 (void) interpret_ipv6(flags, (ip6_t *)&icmp6[1], 620 ICMP6_MINLEN + IPV6_HDR_LEN); 621 prot_nest_prefix = ""; 622 } 623 break; 624 case ICMP6_PACKET_TOO_BIG: 625 show_space(); 626 (void) sprintf(get_line(0, 0), 627 " Packet too big MTU = %d", 628 ntohl(icmp6->icmp6_mtu)); 629 show_space(); 630 break; 631 case ND_REDIRECT: { 632 nd_redirect_t *rd = (nd_redirect_t *)icmp6; 633 634 (void) sprintf(get_line(0, 0), "Target address= %s", 635 inet_ntop(AF_INET6, (char *)&rd->nd_rd_target, 636 addrstr, INET6_ADDRSTRLEN)); 637 638 (void) sprintf(get_line(0, 0), 639 "Destination address= %s", 640 inet_ntop(AF_INET6, (char *)&rd->nd_rd_dst, 641 addrstr, INET6_ADDRSTRLEN)); 642 show_space(); 643 interpret_options((char *)icmp6 + sizeof (*rd), 644 ilen - sizeof (*rd)); 645 break; 646 } 647 case ND_NEIGHBOR_SOLICIT: { 648 struct nd_neighbor_solicit *ns; 649 if (ilen < sizeof (*ns)) 650 break; 651 ns = (struct nd_neighbor_solicit *)icmp6; 652 (void) sprintf(get_line(0, 0), "Target node = %s, %s", 653 inet_ntop(AF_INET6, (char *)&ns->nd_ns_target, 654 addrstr, INET6_ADDRSTRLEN), 655 addrtoname(AF_INET6, &ns->nd_ns_target)); 656 show_space(); 657 interpret_options((char *)icmp6 + sizeof (*ns), 658 ilen - sizeof (*ns)); 659 break; 660 } 661 662 case ND_NEIGHBOR_ADVERT: { 663 struct nd_neighbor_advert *na; 664 665 if (ilen < sizeof (*na)) 666 break; 667 na = (struct nd_neighbor_advert *)icmp6; 668 (void) sprintf(get_line(0, 0), "Target node = %s, %s", 669 inet_ntop(AF_INET6, (char *)&na->nd_na_target, 670 addrstr, INET6_ADDRSTRLEN), 671 addrtoname(AF_INET6, &na->nd_na_target)); 672 (void) sprintf(get_line(0, 0), 673 "Router flag: %s, Solicited flag: %s, " 674 "Override flag: %s", 675 na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER ? 676 "SET" : "NOT SET", 677 na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED ? 678 "SET" : "NOT SET", 679 na->nd_na_flags_reserved & ND_NA_FLAG_OVERRIDE ? 680 "SET" : "NOT SET"); 681 682 show_space(); 683 interpret_options((char *)icmp6 + sizeof (*na), 684 ilen - sizeof (*na)); 685 } 686 break; 687 688 case ND_ROUTER_SOLICIT: { 689 if (ilen < sizeof (struct nd_router_solicit)) 690 break; 691 interpret_options( 692 (char *)icmp6 + sizeof (struct nd_router_solicit), 693 ilen - sizeof (struct nd_router_solicit)); 694 break; 695 } 696 697 case ND_ROUTER_ADVERT: { 698 struct nd_router_advert *ra; 699 700 if (ilen < sizeof (*ra)) 701 break; 702 ra = (struct nd_router_advert *)icmp6; 703 (void) sprintf(get_line(0, 0), 704 "Max hops= %d, Router lifetime= %d", 705 ra->nd_ra_curhoplimit, 706 ntohs(ra->nd_ra_router_lifetime)); 707 708 (void) sprintf(get_line(0, 0), 709 "Managed addr conf flag: %s, Other conf flag: %s", 710 ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED ? 711 "SET" : "NOT SET", 712 ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER ? 713 "SET" : "NOT SET"); 714 715 (void) sprintf(get_line(0, 0), 716 "Reachable time: %u, Reachable retrans time %u", 717 ntohl(ra->nd_ra_reachable), 718 ntohl(ra->nd_ra_retransmit)); 719 show_space(); 720 721 interpret_options((char *)icmp6 + sizeof (*ra), 722 ilen - sizeof (*ra)); 723 break; 724 } 725 case ICMP6_PARAM_PROB: 726 if (ilen < sizeof (*icmp6)) 727 break; 728 (void) sprintf(get_line(0, 0), "Ptr = %u", 729 ntohl(icmp6->icmp6_pptr)); 730 show_space(); 731 break; 732 733 case MLD_LISTENER_QUERY: { 734 struct mld_hdr *mldg = (struct mld_hdr *)icmp6; 735 736 if (ilen < MLD_MINLEN) 737 break; 738 739 if (ilen >= MLD_V2_QUERY_MINLEN) { 740 interpret_mldv2qry(icmp6, ilen); 741 } else { 742 (void) snprintf(get_line(0, 0), 743 get_line_remain(), 744 "Multicast address= %s", 745 inet_ntop(AF_INET6, mldg->mld_addr.s6_addr, 746 addrstr, INET6_ADDRSTRLEN)); 747 } 748 show_space(); 749 break; 750 } 751 752 case MLD_LISTENER_REPORT: 753 case MLD_LISTENER_REDUCTION: { 754 struct mld_hdr *mldg; 755 756 if (ilen < sizeof (*mldg)) 757 break; 758 mldg = (struct mld_hdr *)icmp6; 759 (void) snprintf(get_line(0, 0), get_line_remain(), 760 "Multicast address= %s", inet_ntop(AF_INET6, 761 mldg->mld_addr.s6_addr, addrstr, INET6_ADDRSTRLEN)); 762 show_space(); 763 break; 764 } 765 766 case MLD_V2_LISTENER_REPORT: { 767 interpret_mldv2rpt(icmp6, ilen); 768 show_space(); 769 break; 770 } 771 772 default: 773 break; 774 } 775 } 776 } 777 778 static void 779 interpret_options(optc, ilen) 780 char *optc; 781 int ilen; 782 { 783 #define PREFIX_OPTION_LENGTH 4 784 #define MTU_OPTION_LENGTH 1 785 786 #define PREFIX_INFINITY 0xffffffffUL 787 788 struct nd_opt_hdr *opt; 789 790 for (; ilen >= sizeof (*opt); ) { 791 opt = (struct nd_opt_hdr *)optc; 792 if (opt->nd_opt_len == 0) 793 return; 794 switch (opt->nd_opt_type) { 795 case ND_OPT_SOURCE_LINKADDR: 796 case ND_OPT_TARGET_LINKADDR: 797 { 798 struct nd_opt_lla *lopt; 799 char *buf, chbuf[128]; 800 uint_t addr_len; 801 int i; 802 803 if (ilen < (int)opt->nd_opt_len * 8) 804 break; 805 806 buf = chbuf; 807 808 lopt = (struct nd_opt_lla *)opt; 809 if (lopt->nd_opt_lla_type == ND_OPT_SOURCE_LINKADDR) { 810 (void) sprintf(get_line(0, 0), 811 "+++ ICMPv6 Source LL Addr option +++"); 812 } else { 813 (void) sprintf(get_line(0, 0), 814 "+++ ICMPv6 Target LL Addr option +++"); 815 } 816 817 /* 818 * The option length is in 8 octet units, and 819 * includes the first two bytes (the type and 820 * lenght fields) of the option. 821 */ 822 addr_len = lopt->nd_opt_lla_len * 8 - 2; 823 for (i = 0; i < addr_len; i++) { 824 snprintf(buf, sizeof (chbuf) - (buf - chbuf), 825 "%x:", lopt->nd_opt_lla_hdw_addr[i]); 826 buf += strlen(buf); 827 if (buf >= &chbuf[sizeof (chbuf)]) { 828 buf = NULL; 829 chbuf[sizeof (chbuf) - 830 strlen("<Too Long>)")] = '\0'; 831 (void) strlcat(chbuf, "<Too Long>", 832 sizeof (chbuf)); 833 break; 834 } 835 } 836 if (buf) 837 *(buf - 1) = '\0'; /* Erase last colon */ 838 (void) sprintf(get_line(0, 0), 839 "Link Layer address: %s", chbuf); 840 show_space(); 841 break; 842 } 843 case ND_OPT_MTU: { 844 struct nd_opt_mtu *mopt; 845 if (opt->nd_opt_len != MTU_OPTION_LENGTH || 846 ilen < sizeof (struct nd_opt_mtu)) 847 break; 848 (void) sprintf(get_line(0, 0), 849 "+++ ICMPv6 MTU option +++"); 850 mopt = (struct nd_opt_mtu *)opt; 851 (void) sprintf(get_line(0, 0), 852 "MTU = %u ", mopt->nd_opt_mtu_mtu); 853 show_space(); 854 break; 855 } 856 case ND_OPT_PREFIX_INFORMATION: { 857 struct nd_opt_prefix_info *popt; 858 char validstr[30]; 859 char preferredstr[30]; 860 char prefixstr[INET6_ADDRSTRLEN]; 861 862 if (opt->nd_opt_len != PREFIX_OPTION_LENGTH || 863 ilen < sizeof (struct nd_opt_prefix_info)) 864 break; 865 popt = (struct nd_opt_prefix_info *)opt; 866 (void) sprintf(get_line(0, 0), 867 "+++ ICMPv6 Prefix option +++"); 868 (void) sprintf(get_line(0, 0), 869 "Prefix length = %d ", popt->nd_opt_pi_prefix_len); 870 (void) sprintf(get_line(0, 0), 871 "Onlink flag: %s, Autonomous addr conf flag: %s", 872 popt->nd_opt_pi_flags_reserved & 873 ND_OPT_PI_FLAG_ONLINK ? "SET" : "NOT SET", 874 popt->nd_opt_pi_flags_reserved & 875 ND_OPT_PI_FLAG_AUTO ? "SET" : "NOT SET"); 876 877 if (ntohl(popt->nd_opt_pi_valid_time) == 878 PREFIX_INFINITY) 879 sprintf(validstr, "INFINITY"); 880 else 881 sprintf(validstr, "%lu", 882 ntohl(popt->nd_opt_pi_valid_time)); 883 884 if (ntohl(popt->nd_opt_pi_preferred_time) == 885 PREFIX_INFINITY) 886 sprintf(preferredstr, "INFINITY"); 887 else 888 sprintf(preferredstr, "%lu", 889 ntohl(popt->nd_opt_pi_preferred_time)); 890 891 (void) sprintf(get_line(0, 0), 892 "Valid Lifetime %s, Preferred Lifetime %s", 893 validstr, preferredstr); 894 (void) sprintf(get_line(0, 0), "Prefix %s", 895 inet_ntop(AF_INET6, 896 (char *)&popt->nd_opt_pi_prefix, prefixstr, 897 INET6_ADDRSTRLEN)); 898 show_space(); 899 } 900 default: 901 break; 902 } 903 optc += opt->nd_opt_len * 8; 904 ilen -= opt->nd_opt_len * 8; 905 } 906 } 907 908 static void 909 interpret_mldv2qry(icmp6_t *icmp6, int ilen) 910 { 911 mld2q_t *qry; 912 in6_addr_t *src; 913 int rem = ilen; 914 int srccnt; 915 char addrstr[INET6_ADDRSTRLEN]; 916 917 if (ilen < sizeof (*qry)) { 918 (void) snprintf(get_line(0, 0), get_line_remain(), 919 "Malformed MLD Query"); 920 return; 921 } 922 qry = (mld2q_t *)icmp6; 923 rem -= sizeof (*qry); 924 srccnt = ntohs(qry->mld2q_numsrc); 925 (void) snprintf(get_line(0, 0), get_line_remain(), 926 "Multicast address= %s", inet_ntop(AF_INET6, 927 &qry->mld2q_addr.s6_addr, addrstr, INET6_ADDRSTRLEN)); 928 (void) snprintf(get_line(0, 0), get_line_remain(), 929 "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es"); 930 931 src = (in6_addr_t *)&qry[1]; 932 while (srccnt > 0 && rem >= sizeof (*src)) { 933 rem -= sizeof (*src); 934 935 (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 936 inet_ntop(AF_INET6, src, addrstr, INET6_ADDRSTRLEN)); 937 938 srccnt--; 939 src++; 940 } 941 } 942 943 #define MAX_MLDV2_REPORT_TYPE 6 944 945 const char *mldv2rpt_types[] = { 946 "<unknown>", 947 "MODE_IS_INCLUDE", 948 "MODE_IS_EXCLUDE", 949 "CHANGE_TO_INCLUDE", 950 "CHANGE_TO_EXCLUDE", 951 "ALLOW_NEW_SOURCES", 952 "BLOCK_OLD_SOURCES", 953 }; 954 955 static void 956 interpret_mldv2rpt(icmp6_t *icmp6, int ilen) 957 { 958 mld2r_t *rpt; 959 mld2mar_t *mar; 960 in6_addr_t *src; 961 int rem = ilen, auxlen; 962 uint16_t marcnt, srccnt; 963 char addrstr[INET6_ADDRSTRLEN]; 964 965 if (ilen < sizeof (*rpt)) { 966 (void) snprintf(get_line(0, 0), get_line_remain(), 967 "Malformed MLDv2 Report"); 968 return; 969 } 970 rpt = (mld2r_t *)icmp6; 971 mar = (mld2mar_t *)&rpt[1]; 972 marcnt = ntohs(rpt->mld2r_nummar); 973 (void) snprintf(get_line(0, 0), get_line_remain(), 974 "%d Multicast Address Record%s:", marcnt, (marcnt == 1) ? "" : "s"); 975 rem -= sizeof (*rpt); 976 while (marcnt > 0 && rem >= sizeof (*mar)) { 977 rem -= sizeof (*mar); 978 979 (void) snprintf(get_line(0, 0), get_line_remain(), 980 "Multicast address= %s type = %s", inet_ntop(AF_INET6, 981 &mar->mld2mar_group.s6_addr, addrstr, INET6_ADDRSTRLEN), 982 (mar->mld2mar_type > MAX_MLDV2_REPORT_TYPE) ? 983 "<unknown>" : mldv2rpt_types[mar->mld2mar_type]); 984 srccnt = ntohs(mar->mld2mar_numsrc); 985 (void) snprintf(get_line(0, 0), get_line_remain(), 986 "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es"); 987 988 src = (in6_addr_t *)&mar[1]; 989 while (srccnt > 0 && rem >= sizeof (*src)) { 990 rem -= sizeof (*src); 991 992 (void) snprintf(get_line(0, 0), get_line_remain(), 993 " %s", inet_ntop(AF_INET6, src, addrstr, 994 INET6_ADDRSTRLEN)); 995 996 srccnt--; 997 src++; 998 } 999 1000 marcnt--; 1001 auxlen = mar->mld2mar_auxlen * 4; 1002 rem -= auxlen; 1003 mar = (mld2mar_t *)((uint8_t *)src + auxlen); 1004 } 1005 } 1006