1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <net/if.h> 34 #include <sys/stropts.h> 35 #include <sys/sysmacros.h> 36 #include <netinet/in_systm.h> 37 #include <netinet/in.h> 38 #include <netinet/ip.h> 39 #include <netinet/ip_icmp.h> 40 #include <netinet/udp.h> 41 #include <netinet/tcp.h> 42 #include <netinet/icmp6.h> 43 #include <netinet/ip6.h> 44 #include <inet/ip.h> 45 #include <inet/ip6.h> 46 #include <arpa/inet.h> 47 #include <netdb.h> 48 #include "snoop.h" 49 #include "snoop_mip.h" 50 51 static void interpret_options(char *, int); 52 static void interpret_mldv2qry(icmp6_t *, int); 53 static void interpret_mldv2rpt(icmp6_t *, int); 54 55 56 /* Mobile-IP routines from snoop_mip.c */ 57 extern void interpret_icmp_mip_ext(uchar_t *, int); 58 extern const char *get_mip_adv_desc(uint8_t); 59 60 /* Router advertisement message structure. */ 61 struct icmp_ra_addr { 62 uint32_t addr; 63 uint32_t preference; 64 }; 65 66 /*ARGSUSED*/ 67 void 68 interpret_icmp(int flags, struct icmp *icmp, int iplen, int ilen) 69 { 70 char *pt, *pc, *px; 71 char *line; 72 char buff[67627]; /* Router adv. can have 256 routers .... */ 73 /* Each router has a name 256 char long .. */ 74 char extbuff[MAXHOSTNAMELEN + 1]; 75 struct udphdr *orig_uhdr; 76 int num_rtr_addrs = 0; 77 extern char *prot_nest_prefix; 78 79 if (ilen < ICMP_MINLEN) 80 return; /* incomplete header */ 81 82 pt = "Unknown"; 83 pc = ""; 84 px = ""; 85 86 switch (icmp->icmp_type) { 87 case ICMP_ECHOREPLY: 88 pt = "Echo reply"; 89 (void) sprintf(buff, "ID: %d Sequence number: %d", 90 ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 91 pc = buff; 92 break; 93 case ICMP_UNREACH: 94 pt = "Destination unreachable"; 95 switch (icmp->icmp_code) { 96 case ICMP_UNREACH_NET: 97 if (ilen >= ICMP_ADVLENMIN) { 98 (void) sprintf(buff, "Net %s unreachable", 99 addrtoname(AF_INET, 100 &icmp->icmp_ip.ip_dst)); 101 pc = buff; 102 } else { 103 pc = "Bad net"; 104 } 105 break; 106 case ICMP_UNREACH_HOST: 107 if (ilen >= ICMP_ADVLENMIN) { 108 (void) sprintf(buff, "Host %s unreachable", 109 addrtoname(AF_INET, 110 &icmp->icmp_ip.ip_dst)); 111 pc = buff; 112 } else { 113 pc = "Bad host"; 114 } 115 break; 116 case ICMP_UNREACH_PROTOCOL: 117 if (ilen >= ICMP_ADVLENMIN) { 118 (void) sprintf(buff, "Bad protocol %d", 119 icmp->icmp_ip.ip_p); 120 pc = buff; 121 } else { 122 pc = "Bad protocol"; 123 } 124 break; 125 case ICMP_UNREACH_PORT: 126 if (ilen >= ICMP_ADVLENMIN) { 127 orig_uhdr = (struct udphdr *)((uchar_t *)icmp + 128 ICMP_MINLEN + icmp->icmp_ip.ip_hl * 4); 129 switch (icmp->icmp_ip.ip_p) { 130 case IPPROTO_TCP: 131 (void) sprintf(buff, "TCP port %d" 132 " unreachable", 133 ntohs(orig_uhdr->uh_dport)); 134 pc = buff; 135 break; 136 case IPPROTO_UDP: 137 (void) sprintf(buff, "UDP port %d" 138 " unreachable", 139 ntohs(orig_uhdr->uh_dport)); 140 pc = buff; 141 break; 142 default: 143 pc = "Port unreachable"; 144 break; 145 } 146 } else { 147 pc = "Bad port"; 148 } 149 break; 150 case ICMP_UNREACH_NEEDFRAG: 151 if (ntohs(icmp->icmp_nextmtu) != 0) { 152 (void) sprintf(buff, "Needed to fragment:" 153 " next hop MTU = %d", 154 ntohs(icmp->icmp_nextmtu)); 155 pc = buff; 156 } else { 157 pc = "Needed to fragment"; 158 } 159 break; 160 case ICMP_UNREACH_SRCFAIL: 161 pc = "Source route failed"; 162 break; 163 case ICMP_UNREACH_NET_UNKNOWN: 164 pc = "Unknown network"; 165 break; 166 case ICMP_UNREACH_HOST_UNKNOWN: 167 pc = "Unknown host"; 168 break; 169 case ICMP_UNREACH_ISOLATED: 170 pc = "Source host isolated"; 171 break; 172 case ICMP_UNREACH_NET_PROHIB: 173 pc = "Net administratively prohibited"; 174 break; 175 case ICMP_UNREACH_HOST_PROHIB: 176 pc = "Host administratively prohibited"; 177 break; 178 case ICMP_UNREACH_TOSNET: 179 pc = "Net unreachable for this TOS"; 180 break; 181 case ICMP_UNREACH_TOSHOST: 182 pc = "Host unreachable for this TOS"; 183 break; 184 case ICMP_UNREACH_FILTER_PROHIB: 185 pc = "Communication administratively prohibited"; 186 break; 187 case ICMP_UNREACH_HOST_PRECEDENCE: 188 pc = "Host precedence violation"; 189 break; 190 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 191 pc = "Precedence cutoff in effect"; 192 break; 193 default: 194 break; 195 } 196 break; 197 case ICMP_SOURCEQUENCH: 198 pt = "Packet lost, slow down"; 199 break; 200 case ICMP_REDIRECT: 201 pt = "Redirect"; 202 switch (icmp->icmp_code) { 203 case ICMP_REDIRECT_NET: 204 pc = "for network"; 205 break; 206 case ICMP_REDIRECT_HOST: 207 pc = "for host"; 208 break; 209 case ICMP_REDIRECT_TOSNET: 210 pc = "for tos and net"; 211 break; 212 case ICMP_REDIRECT_TOSHOST: 213 pc = "for tos and host"; 214 break; 215 default: 216 break; 217 } 218 (void) sprintf(buff, "%s %s to %s", 219 pc, addrtoname(AF_INET, &icmp->icmp_ip.ip_dst), 220 addrtoname(AF_INET, &icmp->icmp_gwaddr)); 221 pc = buff; 222 break; 223 case ICMP_ECHO: 224 pt = "Echo request"; 225 (void) sprintf(buff, "ID: %d Sequence number: %d", 226 ntohs(icmp->icmp_id), ntohs(icmp->icmp_seq)); 227 pc = buff; 228 break; 229 case ICMP_ROUTERADVERT: 230 231 #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs 232 #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa 233 #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime 234 235 pt = "Router advertisement"; 236 (void) sprintf(buff, "Lifetime %ds [%d]:", 237 ntohs(icmp->icmp_lifetime), icmp->icmp_num_addrs); 238 if (icmp->icmp_wpa == 2) { 239 struct icmp_ra_addr *ra; 240 char ra_buf[MAXHOSTNAMELEN + 32]; 241 char ra_ext_buf[50]; 242 struct in_addr sin; 243 int icmp_ra_len; 244 int i; 245 246 /* Cannot trust anything from the network... */ 247 num_rtr_addrs = MIN((ilen - ICMP_MINLEN) / 8, 248 icmp->icmp_num_addrs); 249 250 ra = (struct icmp_ra_addr *)icmp->icmp_data; 251 for (i = 0; i < num_rtr_addrs; i++) { 252 sin.s_addr = ra->addr; 253 (void) snprintf(ra_buf, sizeof (ra_buf), 254 " {%s %u}", 255 addrtoname(AF_INET, &sin), 256 ntohl(ra->preference)); 257 if (strlcat(buff, ra_buf, sizeof (buff)) >= 258 sizeof (buff)) { 259 buff[sizeof (buff) - 260 strlen("<Too Long>)")] = '\0'; 261 (void) strlcat(buff, "<Too Long>", 262 sizeof (buff)); 263 break; 264 } 265 ra++; 266 } 267 268 icmp_ra_len = ICMP_MINLEN + num_rtr_addrs * 269 sizeof (struct icmp_ra_addr); 270 if (ilen > icmp_ra_len) { 271 int curr_len = ilen - icmp_ra_len; 272 int ocurr_len; 273 exthdr_t *exthdr = (exthdr_t *)ra; 274 275 extbuff[0] = '\0'; 276 277 while (curr_len > 0) { 278 /* Append Mobile-IP description */ 279 (void) snprintf(ra_ext_buf, 280 sizeof (ra_ext_buf), ", %s", 281 get_mip_adv_desc(exthdr->type)); 282 (void) strlcat(extbuff, ra_ext_buf, 283 sizeof (extbuff)); 284 285 /* Special case for padding */ 286 if (exthdr->type == 287 ICMP_ADV_MSG_PADDING_EXT) { 288 289 curr_len--; 290 exthdr = (exthdr_t *) 291 ((char *)exthdr + 1); 292 continue; 293 } 294 295 /* else normal extension */ 296 ocurr_len = curr_len; 297 curr_len -= sizeof (*exthdr) + 298 exthdr->length; 299 /* detect bad length */ 300 if (ocurr_len < curr_len) 301 break; 302 exthdr = (exthdr_t *) 303 ((char *)exthdr + 304 sizeof (*exthdr) + 305 exthdr->length); 306 } 307 px = extbuff; 308 } 309 pc = buff; 310 } 311 break; 312 case ICMP_ROUTERSOLICIT: 313 pt = "Router solicitation"; 314 break; 315 case ICMP_TIMXCEED: 316 pt = "Time exceeded"; 317 switch (icmp->icmp_code) { 318 case ICMP_TIMXCEED_INTRANS: 319 pc = "in transit"; 320 break; 321 case ICMP_TIMXCEED_REASS: 322 pc = "in reassembly"; 323 break; 324 default: 325 break; 326 } 327 break; 328 case ICMP_PARAMPROB: 329 pt = "IP parameter problem"; 330 switch (icmp->icmp_code) { 331 case ICMP_PARAMPROB_OPTABSENT: 332 pc = "Required option missing"; 333 break; 334 case ICMP_PARAMPROB_BADLENGTH: 335 pc = "Bad length"; 336 break; 337 case 0: /* Should this be the default? */ 338 (void) sprintf(buff, "Problem at octet %d\n", 339 icmp->icmp_pptr); 340 pc = buff; 341 default: 342 break; 343 } 344 break; 345 case ICMP_TSTAMP: 346 pt = "Timestamp request"; 347 break; 348 case ICMP_TSTAMPREPLY: 349 pt = "Timestamp reply"; 350 break; 351 case ICMP_IREQ: 352 pt = "Information request"; 353 break; 354 case ICMP_IREQREPLY: 355 pt = "Information reply"; 356 break; 357 case ICMP_MASKREQ: 358 pt = "Address mask request"; 359 break; 360 case ICMP_MASKREPLY: 361 pt = "Address mask reply"; 362 (void) sprintf(buff, "Mask = 0x%x", ntohl(icmp->icmp_mask)); 363 pc = buff; 364 break; 365 default: 366 break; 367 } 368 369 if (flags & F_SUM) { 370 line = get_sum_line(); 371 if (*pc) { 372 if (*px) { 373 (void) sprintf(line, "ICMP %s (%s)%s", 374 pt, pc, px); 375 } else { 376 (void) sprintf(line, "ICMP %s (%s)", pt, pc); 377 } 378 } else { 379 (void) sprintf(line, "ICMP %s", pt); 380 } 381 } 382 383 if (flags & F_DTAIL) { 384 show_header("ICMP: ", "ICMP Header", ilen); 385 show_space(); 386 (void) sprintf(get_line(0, 0), "Type = %d (%s)", 387 icmp->icmp_type, pt); 388 if (*pc) { 389 (void) sprintf(get_line(0, 0), "Code = %d (%s)", 390 icmp->icmp_code, pc); 391 } else { 392 (void) sprintf(get_line(0, 0), "Code = %d", 393 icmp->icmp_code); 394 } 395 (void) sprintf(get_line(0, 0), "Checksum = %x", 396 ntohs(icmp->icmp_cksum)); 397 398 if (icmp->icmp_type == ICMP_UNREACH || 399 icmp->icmp_type == ICMP_REDIRECT) { 400 if (ilen > 28) { 401 show_space(); 402 (void) sprintf(get_line(0, 0), 403 "[ subject header follows ]"); 404 show_space(); 405 prot_nest_prefix = "ICMP:"; 406 (void) interpret_ip(flags, 407 (struct ip *)icmp->icmp_data, 28); 408 prot_nest_prefix = ""; 409 } 410 } else if (icmp->icmp_type == ICMP_PARAMPROB) { 411 if (ilen > 28) { 412 show_space(); 413 (void) sprintf(get_line(0, 0), 414 "[ subject header follows ]"); 415 show_space(); 416 prot_nest_prefix = "ICMP:"; 417 (void) interpret_ip(flags, 418 (struct ip *)icmp->icmp_data, 28); 419 prot_nest_prefix = ""; 420 } 421 } else if (icmp->icmp_type == ICMP_ROUTERADVERT) { 422 if (icmp->icmp_wpa == 2) { 423 int icmp_ra_len; 424 425 show_space(); 426 icmp_ra_len = ICMP_MINLEN + 427 num_rtr_addrs * 428 sizeof (struct icmp_ra_addr); 429 prot_nest_prefix = ""; 430 if (ilen > icmp_ra_len) { 431 interpret_icmp_mip_ext( 432 (uchar_t *)icmp + icmp_ra_len, 433 ilen - icmp_ra_len); 434 } 435 } 436 } 437 show_space(); 438 } 439 } 440 441 /*ARGSUSED*/ 442 void 443 interpret_icmpv6(flags, icmp6, iplen, ilen) 444 int flags; 445 icmp6_t *icmp6; 446 int iplen, ilen; 447 { 448 char *pt, *pc; 449 char *line; 450 extern char *prot_nest_prefix; 451 char addrstr[INET6_ADDRSTRLEN]; 452 char buff[2048]; 453 454 if (ilen < ICMP6_MINLEN) 455 return; /* incomplete header */ 456 457 pt = "Unknown"; 458 pc = ""; 459 460 switch (icmp6->icmp6_type) { 461 case ICMP6_DST_UNREACH: 462 pt = "Destination unreachable"; 463 switch (icmp6->icmp6_code) { 464 case ICMP6_DST_UNREACH_NOROUTE: 465 pc = "No route to destination"; 466 break; 467 case ICMP6_DST_UNREACH_ADMIN: 468 pc = "Communication administratively prohibited"; 469 break; 470 case ICMP6_DST_UNREACH_ADDR: 471 pc = "Address unreachable"; 472 break; 473 case ICMP6_DST_UNREACH_NOPORT: 474 if (ilen >= ICMP6_MINLEN + IPV6_HDR_LEN + 475 sizeof (struct udphdr)) { 476 477 ip6_t *orig_ip6hdr = (ip6_t *)&icmp6[1]; 478 479 switch (orig_ip6hdr->ip6_nxt) { 480 case IPPROTO_TCP: { 481 struct tcphdr *orig_thdr = 482 (struct tcphdr *)&orig_ip6hdr[1]; 483 484 (void) sprintf(buff, "TCP port %hu" 485 " unreachable", 486 ntohs(orig_thdr->th_dport)); 487 pc = buff; 488 break; 489 } 490 case IPPROTO_UDP: { 491 struct udphdr *orig_uhdr = 492 (struct udphdr *)&orig_ip6hdr[1]; 493 494 (void) sprintf(buff, "UDP port %hu" 495 " unreachable", 496 ntohs(orig_uhdr->uh_dport)); 497 pc = buff; 498 break; 499 } 500 default: 501 pc = "Port unreachable"; 502 break; 503 } 504 } else { 505 pc = "Bad port"; 506 } 507 break; 508 default: 509 break; 510 } 511 break; 512 case ICMP6_PACKET_TOO_BIG: 513 pt = "Packet too big"; 514 break; 515 case ND_REDIRECT: 516 pt = "Redirect"; 517 break; 518 case ICMP6_TIME_EXCEEDED: 519 pt = "Time exceeded"; 520 switch (icmp6->icmp6_code) { 521 case ICMP6_TIME_EXCEED_TRANSIT: 522 pc = "Hop limit exceeded in transit"; 523 break; 524 case ICMP6_TIME_EXCEED_REASSEMBLY: 525 pc = "Fragment reassembly time exceeded"; 526 break; 527 default: 528 break; 529 } 530 break; 531 case ICMP6_PARAM_PROB: 532 pt = "Parameter problem"; 533 switch (icmp6->icmp6_code) { 534 case ICMP6_PARAMPROB_HEADER: 535 pc = "Erroneous header field"; 536 break; 537 case ICMP6_PARAMPROB_NEXTHEADER: 538 pc = "Unrecognized next header type"; 539 break; 540 case ICMP6_PARAMPROB_OPTION: 541 pc = "Unrecognized IPv6 option"; 542 break; 543 } 544 break; 545 case ICMP6_ECHO_REQUEST: 546 pt = "Echo request"; 547 (void) sprintf(buff, "ID: %d Sequence number: %d", 548 ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 549 pc = buff; 550 break; 551 case ICMP6_ECHO_REPLY: 552 pt = "Echo reply"; 553 (void) sprintf(buff, "ID: %d Sequence number: %d", 554 ntohs(icmp6->icmp6_id), ntohs(icmp6->icmp6_seq)); 555 pc = buff; 556 break; 557 case MLD_LISTENER_QUERY: 558 if (ilen == MLD_MINLEN) 559 pt = "Group membership query - MLDv1"; 560 else if (ilen >= MLD_V2_QUERY_MINLEN) 561 pt = "Group membership query - MLDv2"; 562 else 563 pt = "Unknown membership query"; 564 break; 565 case MLD_LISTENER_REPORT: 566 pt = "Group membership report - MLDv1"; 567 break; 568 case MLD_LISTENER_REDUCTION: 569 pt = "Group membership termination - MLDv1"; 570 break; 571 case MLD_V2_LISTENER_REPORT: 572 pt = "Group membership report - MLDv2"; 573 break; 574 case ND_ROUTER_SOLICIT: 575 pt = "Router solicitation"; 576 break; 577 case ND_ROUTER_ADVERT: 578 pt = "Router advertisement"; 579 break; 580 case ND_NEIGHBOR_SOLICIT: 581 pt = "Neighbor solicitation"; 582 break; 583 case ND_NEIGHBOR_ADVERT: 584 pt = "Neighbor advertisement"; 585 break; 586 default: 587 break; 588 } 589 590 if (flags & F_SUM) { 591 line = get_sum_line(); 592 if (*pc) 593 (void) sprintf(line, "ICMPv6 %s (%s)", pt, pc); 594 else 595 (void) sprintf(line, "ICMPv6 %s", pt); 596 } 597 598 if (flags & F_DTAIL) { 599 show_header("ICMPv6: ", "ICMPv6 Header", ilen); 600 show_space(); 601 (void) sprintf(get_line(0, 0), "Type = %d (%s)", 602 icmp6->icmp6_type, pt); 603 if (*pc) 604 (void) sprintf(get_line(0, 0), "Code = %d (%s)", 605 icmp6->icmp6_code, pc); 606 else 607 (void) sprintf(get_line(0, 0), "Code = %d", 608 icmp6->icmp6_code); 609 (void) sprintf(get_line(0, 0), "Checksum = %x", 610 ntohs(icmp6->icmp6_cksum)); 611 612 switch (icmp6->icmp6_type) { 613 case ICMP6_DST_UNREACH: 614 if (ilen > ICMP6_MINLEN + IPV6_HDR_LEN) { 615 show_space(); 616 (void) sprintf(get_line(0, 0), 617 "[ subject header follows ]"); 618 show_space(); 619 prot_nest_prefix = "ICMPv6:"; 620 (void) interpret_ipv6(flags, (ip6_t *)&icmp6[1], 621 ICMP6_MINLEN + IPV6_HDR_LEN); 622 prot_nest_prefix = ""; 623 } 624 break; 625 case ICMP6_PACKET_TOO_BIG: 626 show_space(); 627 (void) sprintf(get_line(0, 0), 628 " Packet too big MTU = %d", 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