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