1 /* $OpenBSD: print-icmp6.c,v 1.15 2015/01/16 06:40:21 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #ifdef INET6 25 26 #include <ctype.h> 27 28 #include <sys/time.h> 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 32 #include <net/if.h> 33 34 #include <netinet/in.h> 35 #include <netinet/if_ether.h> 36 #include <netinet/ip.h> 37 #include <netinet/ip_icmp.h> 38 #include <netinet/ip_var.h> 39 #include <netinet/udp.h> 40 #include <netinet/udp_var.h> 41 #include <netinet/tcp.h> 42 43 #include <arpa/inet.h> 44 45 #include <stdio.h> 46 #include <string.h> 47 48 #include <netinet/ip6.h> 49 #include <netinet/icmp6.h> 50 #include <netinet6/mld6.h> 51 52 #include "interface.h" 53 #include "addrtoname.h" 54 #include "extract.h" 55 56 void icmp6_opt_print(const u_char *, int); 57 void mld6_print(const u_char *); 58 void mldv2_query_print(const u_char *, u_int); 59 void mldv2_report_print(const u_char *, u_int); 60 61 /* mldv2 report types */ 62 static struct tok mldv2report2str[] = { 63 { 1, "is_in" }, 64 { 2, "is_ex" }, 65 { 3, "to_in" }, 66 { 4, "to_ex" }, 67 { 5, "allow" }, 68 { 6, "block" }, 69 { 0, NULL } 70 }; 71 72 #define MLDV2_QUERY_QRV 24 73 #define MLDV2_QUERY_QQIC 25 74 #define MLDV2_QUERY_NSRCS 26 75 #define MLDV2_QUERY_SRC0 28 76 77 #define MLDV2_QUERY_QRV_SFLAG (1 << 3) 78 79 #define MLD_V1_QUERY_MINLEN 24 80 81 #define MLDV2_REPORT_GROUP0 8 82 83 #define MLDV2_REPORT_MINLEN 8 84 #define MLDV2_REPORT_MINGRPLEN 20 85 86 #define MLDV2_RGROUP_NSRCS 2 87 #define MLDV2_RGROUP_MADDR 4 88 89 #define MLDV2_MRC_FLOAT (1 << 15) 90 #define MLDV2_MRD(mant, exp) ((mant | 0x1000) << (exp + 3)) 91 92 #define MLDV2_QQIC_FLOAT (1 << 7) 93 #define MLDV2_QQI(mant, exp) ((mant | 0x10) << (exp + 3)) 94 95 static int 96 icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icmp6, 97 u_int len) 98 { 99 union { 100 struct { 101 struct in6_addr ph_src; 102 struct in6_addr ph_dst; 103 u_int32_t ph_len; 104 u_int8_t ph_zero[3]; 105 u_int8_t ph_nxt; 106 } ph; 107 u_int16_t pa[20]; 108 } phu; 109 size_t i; 110 u_int32_t sum = 0; 111 112 /* pseudo-header */ 113 memset(&phu, 0, sizeof(phu)); 114 phu.ph.ph_src = ip6->ip6_src; 115 phu.ph.ph_dst = ip6->ip6_dst; 116 phu.ph.ph_len = htonl(len); 117 phu.ph.ph_nxt = IPPROTO_ICMPV6; 118 119 for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 120 sum += phu.pa[i]; 121 122 return in_cksum((u_short *)icmp6, len, sum); 123 } 124 125 void 126 icmp6_print(const u_char *bp, u_int length, const u_char *bp2) 127 { 128 register const struct icmp6_hdr *dp; 129 register const struct ip6_hdr *ip; 130 register const char *str; 131 register const struct ip6_hdr *oip; 132 register const struct udphdr *ouh; 133 register int hlen, dport; 134 register const u_char *ep; 135 char buf[256]; 136 int icmp6len; 137 138 #if 0 139 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc 140 #endif 141 142 dp = (struct icmp6_hdr *)bp; 143 ip = (struct ip6_hdr *)bp2; 144 oip = (struct ip6_hdr *)(dp + 1); 145 str = buf; 146 /* 'ep' points to the end of avaible data. */ 147 ep = snapend; 148 if (ip->ip6_plen) 149 icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) - 150 (bp - bp2)); 151 else /* XXX: jumbo payload case... */ 152 icmp6len = snapend - bp; 153 154 #if 0 155 (void)printf("%s > %s: ", 156 ip6addr_string(&ip->ip6_src), 157 ip6addr_string(&ip->ip6_dst)); 158 #endif 159 160 TCHECK(dp->icmp6_code); 161 switch (dp->icmp6_type) { 162 case ICMP6_DST_UNREACH: 163 TCHECK(oip->ip6_dst); 164 switch (dp->icmp6_code) { 165 case ICMP6_DST_UNREACH_NOROUTE: 166 printf("icmp6: %s unreachable route", 167 ip6addr_string(&oip->ip6_dst)); 168 break; 169 case ICMP6_DST_UNREACH_ADMIN: 170 printf("icmp6: %s unreachable prohibited", 171 ip6addr_string(&oip->ip6_dst)); 172 break; 173 #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE 174 case ICMP6_DST_UNREACH_BEYONDSCOPE: 175 #else 176 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 177 #endif 178 printf("icmp6: %s beyond scope of source address %s", 179 ip6addr_string(&oip->ip6_dst), 180 ip6addr_string(&oip->ip6_src)); 181 break; 182 case ICMP6_DST_UNREACH_ADDR: 183 printf("icmp6: %s unreachable address", 184 ip6addr_string(&oip->ip6_dst)); 185 break; 186 case ICMP6_DST_UNREACH_NOPORT: 187 TCHECK(oip->ip6_nxt); 188 hlen = sizeof(struct ip6_hdr); 189 ouh = (struct udphdr *)(((u_char *)oip) + hlen); 190 TCHECK(ouh->uh_dport); 191 dport = ntohs(ouh->uh_dport); 192 switch (oip->ip6_nxt) { 193 case IPPROTO_TCP: 194 printf("icmp6: %s tcp port %s unreachable", 195 ip6addr_string(&oip->ip6_dst), 196 tcpport_string(dport)); 197 break; 198 case IPPROTO_UDP: 199 printf("icmp6: %s udp port %s unreachable", 200 ip6addr_string(&oip->ip6_dst), 201 udpport_string(dport)); 202 break; 203 default: 204 printf("icmp6: %s protocol %d port %d unreachable", 205 ip6addr_string(&oip->ip6_dst), 206 oip->ip6_nxt, dport); 207 break; 208 } 209 break; 210 default: 211 printf("icmp6: %s unreachable code-#%d", 212 ip6addr_string(&oip->ip6_dst), 213 dp->icmp6_code); 214 break; 215 } 216 break; 217 case ICMP6_PACKET_TOO_BIG: 218 TCHECK(dp->icmp6_mtu); 219 printf("icmp6: too big %u", (u_int32_t)ntohl(dp->icmp6_mtu)); 220 break; 221 case ICMP6_TIME_EXCEEDED: 222 TCHECK(oip->ip6_dst); 223 switch (dp->icmp6_code) { 224 case ICMP6_TIME_EXCEED_TRANSIT: 225 printf("icmp6: time exceeded in-transit for %s", 226 ip6addr_string(&oip->ip6_dst)); 227 break; 228 case ICMP6_TIME_EXCEED_REASSEMBLY: 229 printf("icmp6: ip6 reassembly time exceeded"); 230 break; 231 default: 232 printf("icmp6: time exceeded code-#%d", 233 dp->icmp6_code); 234 break; 235 } 236 break; 237 case ICMP6_PARAM_PROB: 238 TCHECK(oip->ip6_dst); 239 switch (dp->icmp6_code) { 240 case ICMP6_PARAMPROB_HEADER: 241 printf("icmp6: parameter problem errorneous - octet %u", 242 (u_int32_t)ntohl(dp->icmp6_pptr)); 243 break; 244 case ICMP6_PARAMPROB_NEXTHEADER: 245 printf("icmp6: parameter problem next header - octet %u", 246 (u_int32_t)ntohl(dp->icmp6_pptr)); 247 break; 248 case ICMP6_PARAMPROB_OPTION: 249 printf("icmp6: parameter problem option - octet %u", 250 (u_int32_t)ntohl(dp->icmp6_pptr)); 251 break; 252 default: 253 printf("icmp6: parameter problem code-#%d", 254 dp->icmp6_code); 255 break; 256 } 257 break; 258 case ICMP6_ECHO_REQUEST: 259 case ICMP6_ECHO_REPLY: 260 printf("icmp6: echo %s", dp->icmp6_type == ICMP6_ECHO_REQUEST ? 261 "request" : "reply"); 262 if (vflag) { 263 TCHECK(dp->icmp6_seq); 264 printf(" (id:%04x seq:%u)", 265 ntohs(dp->icmp6_id), ntohs(dp->icmp6_seq)); 266 } 267 break; 268 case ICMP6_MEMBERSHIP_QUERY: 269 printf("icmp6: multicast listener query "); 270 if (length == MLD_V1_QUERY_MINLEN) { 271 mld6_print((const u_char *)dp); 272 } else if (length >= MLD_V2_QUERY_MINLEN) { 273 printf("v2 "); 274 mldv2_query_print((const u_char *)dp, length); 275 } else { 276 printf("unknown-version (len %u) ", length); 277 } 278 break; 279 case ICMP6_MEMBERSHIP_REPORT: 280 printf("icmp6: multicast listener report "); 281 mld6_print((const u_char *)dp); 282 break; 283 case ICMP6_MEMBERSHIP_REDUCTION: 284 printf("icmp6: multicast listener done "); 285 mld6_print((const u_char *)dp); 286 break; 287 case ND_ROUTER_SOLICIT: 288 printf("icmp6: router solicitation "); 289 if (vflag) { 290 #define RTSOLLEN 8 291 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 292 icmp6len - RTSOLLEN); 293 } 294 break; 295 case ND_ROUTER_ADVERT: 296 printf("icmp6: router advertisement"); 297 if (vflag) { 298 struct nd_router_advert *p; 299 300 p = (struct nd_router_advert *)dp; 301 TCHECK(p->nd_ra_retransmit); 302 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); 303 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) 304 printf("M"); 305 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) 306 printf("O"); 307 if (p->nd_ra_flags_reserved != 0) 308 printf(" "); 309 printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime)); 310 printf("reachable_time=%u, ", 311 (u_int32_t)ntohl(p->nd_ra_reachable)); 312 printf("retrans_time=%u)", 313 (u_int32_t)ntohl(p->nd_ra_retransmit)); 314 #define RTADVLEN 16 315 icmp6_opt_print((const u_char *)dp + RTADVLEN, 316 icmp6len - RTADVLEN); 317 } 318 break; 319 case ND_NEIGHBOR_SOLICIT: 320 { 321 struct nd_neighbor_solicit *p; 322 p = (struct nd_neighbor_solicit *)dp; 323 TCHECK(p->nd_ns_target); 324 printf("icmp6: neighbor sol: who has %s", 325 ip6addr_string(&p->nd_ns_target)); 326 if (vflag) { 327 #define NDSOLLEN 24 328 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 329 icmp6len - NDSOLLEN); 330 } 331 } 332 break; 333 case ND_NEIGHBOR_ADVERT: 334 { 335 struct nd_neighbor_advert *p; 336 337 p = (struct nd_neighbor_advert *)dp; 338 TCHECK(p->nd_na_target); 339 printf("icmp6: neighbor adv: tgt is %s", 340 ip6addr_string(&p->nd_na_target)); 341 if (vflag) { 342 #define ND_NA_FLAG_ALL \ 343 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) 344 /* we don't need ntohl() here. see advanced-api-04. */ 345 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { 346 #undef ND_NA_FLAG_ALL 347 u_int32_t flags; 348 349 flags = p->nd_na_flags_reserved; 350 printf("("); 351 if (flags & ND_NA_FLAG_ROUTER) 352 printf("R"); 353 if (flags & ND_NA_FLAG_SOLICITED) 354 printf("S"); 355 if (flags & ND_NA_FLAG_OVERRIDE) 356 printf("O"); 357 printf(")"); 358 } 359 #define NDADVLEN 24 360 icmp6_opt_print((const u_char *)dp + NDADVLEN, 361 icmp6len - NDADVLEN); 362 } 363 } 364 break; 365 case ND_REDIRECT: 366 { 367 #define RDR(i) ((struct nd_redirect *)(i)) 368 char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN]; 369 370 TCHECK(RDR(dp)->nd_rd_dst); 371 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target, 372 tgtbuf, INET6_ADDRSTRLEN); 373 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst, 374 dstbuf, INET6_ADDRSTRLEN); 375 printf("icmp6: redirect %s to %s", dstbuf, tgtbuf); 376 #define REDIRECTLEN 40 377 if (vflag) { 378 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 379 icmp6len - REDIRECTLEN); 380 } 381 break; 382 } 383 case ICMP6_ROUTER_RENUMBERING: 384 switch (dp->icmp6_code) { 385 case ICMP6_ROUTER_RENUMBERING_COMMAND: 386 printf("icmp6: router renum command"); 387 break; 388 case ICMP6_ROUTER_RENUMBERING_RESULT: 389 printf("icmp6: router renum result"); 390 break; 391 default: 392 printf("icmp6: router renum code-#%d", dp->icmp6_code); 393 break; 394 } 395 break; 396 #ifdef ICMP6_WRUREQUEST 397 case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/ 398 { 399 int siz; 400 siz = ep - (u_char *)(dp + 1); 401 if (siz == 4) 402 printf("icmp6: who-are-you request"); 403 else { 404 printf("icmp6: FQDN request"); 405 if (vflag) { 406 if (siz < 8) 407 printf("?(icmp6_data %d bytes)", siz); 408 else if (8 < siz) 409 printf("?(extra %d bytes)", siz - 8); 410 } 411 } 412 break; 413 } 414 #endif /*ICMP6_WRUREQUEST*/ 415 #ifdef ICMP6_WRUREPLY 416 case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/ 417 { 418 enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN; 419 u_char const *buf; 420 u_char const *cp = NULL; 421 422 buf = (u_char *)(dp + 1); 423 424 /* fair guess */ 425 if (buf[12] == ep - buf - 13) 426 mode = FQDN; 427 else if (dp->icmp6_code == 1) 428 mode = FQDN; 429 430 /* wild guess */ 431 if (mode == UNKNOWN) { 432 cp = buf + 4; 433 while (cp < ep) { 434 if (!isprint(*cp++)) 435 mode = FQDN; 436 } 437 } 438 #ifndef abs 439 #define abs(a) ((0 < (a)) ? (a) : -(a)) 440 #endif 441 if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13))) 442 mode = WRU; 443 if (mode == UNKNOWN) 444 mode = FQDN; 445 446 if (mode == WRU) { 447 cp = buf + 4; 448 printf("icmp6: who-are-you reply(\""); 449 } else if (mode == FQDN) { 450 cp = buf + 13; 451 printf("icmp6: FQDN reply(\""); 452 } 453 for (; cp < ep; cp++) 454 printf((isprint(*cp) ? "%c" : "\\%03o"), *cp); 455 printf("\""); 456 if (vflag) { 457 printf(",%s", mode == FQDN ? "FQDN" : "WRU"); 458 if (mode == FQDN) { 459 int ttl; 460 ttl = (int)ntohl(*(u_int32_t *)&buf[8]); 461 if (dp->icmp6_code == 1) 462 printf(",TTL=unknown"); 463 else if (ttl < 0) 464 printf(",TTL=%d:invalid", ttl); 465 else 466 printf(",TTL=%d", ttl); 467 if (buf[12] != ep - buf - 13) { 468 (void)printf(",invalid namelen:%d/%u", 469 buf[12], 470 (unsigned int)(ep - buf - 13)); 471 } 472 } 473 } 474 printf(")"); 475 break; 476 } 477 #endif /*ICMP6_WRUREPLY*/ 478 case MLDV2_LISTENER_REPORT: 479 printf("multicast listener report v2"); 480 mldv2_report_print((const u_char *) dp, length); 481 break; 482 default: 483 printf("icmp6: type-#%d", dp->icmp6_type); 484 break; 485 } 486 if (vflag) { 487 if (TTEST2(dp->icmp6_type, length)) { 488 u_int16_t sum, icmp6_sum; 489 sum = icmp6_cksum(ip, dp, length); 490 if (sum != 0) { 491 icmp6_sum = EXTRACT_16BITS(&dp->icmp6_cksum); 492 printf(" [bad icmp6 cksum %x! -> %x]", icmp6_sum, 493 in_cksum_shouldbe(icmp6_sum, sum)); 494 } else 495 printf(" [icmp6 cksum ok]"); 496 } 497 } 498 return; 499 trunc: 500 fputs("[|icmp6]", stdout); 501 #if 0 502 #undef TCHECK 503 #endif 504 } 505 506 void 507 icmp6_opt_print(register const u_char *bp, int resid) 508 { 509 register const struct nd_opt_hdr *op; 510 register const struct nd_opt_hdr *opl; /* why there's no struct? */ 511 register const struct nd_opt_prefix_info *opp; 512 register const struct icmp6_opts_redirect *opr; 513 register const struct nd_opt_mtu *opm; 514 register const u_char *ep; 515 int opts_len; 516 #if 0 517 register const struct ip6_hdr *ip; 518 register const char *str; 519 register const struct ip6_hdr *oip; 520 register const struct udphdr *ouh; 521 register int hlen, dport; 522 char buf[256]; 523 #endif 524 525 #if 0 526 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc 527 #endif 528 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 529 530 op = (struct nd_opt_hdr *)bp; 531 #if 0 532 ip = (struct ip6_hdr *)bp2; 533 oip = &dp->icmp6_ip6; 534 str = buf; 535 #endif 536 /* 'ep' points to the end of avaible data. */ 537 ep = snapend; 538 539 ECHECK(op->nd_opt_len); 540 if (resid <= 0) 541 return; 542 if (op->nd_opt_len == 0) 543 goto trunc; 544 if (bp + (op->nd_opt_len << 3) > ep) 545 goto trunc; 546 switch (op->nd_opt_type) { 547 case ND_OPT_SOURCE_LINKADDR: 548 opl = (struct nd_opt_hdr *)op; 549 #if 1 550 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) 551 goto trunc; 552 #else 553 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); 554 #endif 555 printf("(src lladdr: %s", 556 etheraddr_string((u_char *)(opl + 1))); 557 if (opl->nd_opt_len != 1) 558 printf("!"); 559 printf(")"); 560 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 561 resid - (op->nd_opt_len << 3)); 562 break; 563 case ND_OPT_TARGET_LINKADDR: 564 opl = (struct nd_opt_hdr *)op; 565 #if 1 566 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) 567 goto trunc; 568 #else 569 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); 570 #endif 571 printf("(tgt lladdr: %s", 572 etheraddr_string((u_char *)(opl + 1))); 573 if (opl->nd_opt_len != 1) 574 printf("!"); 575 printf(")"); 576 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 577 resid - (op->nd_opt_len << 3)); 578 break; 579 case ND_OPT_PREFIX_INFORMATION: 580 opp = (struct nd_opt_prefix_info *)op; 581 TCHECK(opp->nd_opt_pi_prefix); 582 printf("(prefix info: "); 583 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) 584 printf("L"); 585 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) 586 printf("A"); 587 if (opp->nd_opt_pi_flags_reserved) 588 printf(" "); 589 printf("valid_ltime="); 590 if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U) 591 printf("infinity"); 592 else { 593 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time)); 594 } 595 printf(", "); 596 printf("preferred_ltime="); 597 if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U) 598 printf("infinity"); 599 else { 600 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)); 601 } 602 printf(", "); 603 printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), 604 opp->nd_opt_pi_prefix_len); 605 if (opp->nd_opt_pi_len != 4) 606 printf("!"); 607 printf(")"); 608 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 609 resid - (op->nd_opt_len << 3)); 610 break; 611 case ND_OPT_REDIRECTED_HEADER: 612 opr = (struct icmp6_opts_redirect *)op; 613 printf("(redirect)"); 614 /* xxx */ 615 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 616 resid - (op->nd_opt_len << 3)); 617 break; 618 case ND_OPT_MTU: 619 opm = (struct nd_opt_mtu *)op; 620 TCHECK(opm->nd_opt_mtu_mtu); 621 printf("(mtu: "); 622 printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); 623 if (opm->nd_opt_mtu_len != 1) 624 printf("!"); 625 printf(")"); 626 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 627 resid - (op->nd_opt_len << 3)); 628 break; 629 default: 630 opts_len = op->nd_opt_len; 631 printf("(unknown opt_type=%d, opt_len=%d)", 632 op->nd_opt_type, opts_len); 633 if (opts_len == 0) 634 opts_len = 1; /* XXX */ 635 icmp6_opt_print((const u_char *)op + (opts_len << 3), 636 resid - (opts_len << 3)); 637 break; 638 } 639 return; 640 trunc: 641 fputs("[ndp opt]", stdout); 642 return; 643 #if 0 644 #undef TCHECK 645 #endif 646 #undef ECHECK 647 } 648 649 void 650 mld6_print(register const u_char *bp) 651 { 652 register struct mld_hdr *mp = (struct mld_hdr *)bp; 653 register const u_char *ep; 654 655 /* 'ep' points to the end of avaible data. */ 656 ep = snapend; 657 658 if ((u_char *)mp + sizeof(*mp) > ep) 659 return; 660 661 printf("max resp delay: %d ", ntohs(mp->mld_maxdelay)); 662 printf("addr: %s", ip6addr_string(&mp->mld_addr)); 663 664 return; 665 } 666 667 void 668 mldv2_report_print(const u_char *bp, u_int len) 669 { 670 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 671 u_int group, nsrcs, ngroups; 672 u_int i, j; 673 674 if (len < MLDV2_REPORT_MINLEN) { 675 printf(" [invalid len %d]", len); 676 return; 677 } 678 679 TCHECK(icp->icmp6_data16[1]); 680 ngroups = ntohs(icp->icmp6_data16[1]); 681 printf(", %d group record(s)", ngroups); 682 if (vflag > 0) { 683 /* Print the group records */ 684 group = MLDV2_REPORT_GROUP0; 685 for (i = 0; i < ngroups; i++) { 686 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 687 if (len < group + MLDV2_REPORT_MINGRPLEN) { 688 printf(" [invalid number of groups]"); 689 return; 690 } 691 TCHECK2(bp[group + MLDV2_RGROUP_MADDR], 692 sizeof(struct in6_addr)); 693 printf(" [gaddr %s", 694 ip6addr_string(&bp[group + MLDV2_RGROUP_MADDR])); 695 printf(" %s", tok2str(mldv2report2str, 696 " [v2-report-#%d]", bp[group])); 697 nsrcs = (bp[group + MLDV2_RGROUP_NSRCS] << 8) + 698 bp[group + MLDV2_RGROUP_NSRCS + 1]; 699 /* Check the number of sources and print them */ 700 if (len < group + MLDV2_REPORT_MINGRPLEN + 701 (nsrcs * sizeof(struct in6_addr))) { 702 printf(" [invalid number of sources %d]", nsrcs); 703 return; 704 } 705 if (vflag == 1) 706 printf(", %d source(s)", nsrcs); 707 else { 708 /* Print the sources */ 709 (void)printf(" {"); 710 for (j = 0; j < nsrcs; j++) { 711 TCHECK2(bp[group + 712 MLDV2_REPORT_MINGRPLEN + 713 j * sizeof(struct in6_addr)], 714 sizeof(struct in6_addr)); 715 printf(" %s", ip6addr_string(&bp[group + 716 MLDV2_REPORT_MINGRPLEN + j * 717 sizeof(struct in6_addr)])); 718 } 719 (void)printf(" }"); 720 } 721 /* Next group record */ 722 group += MLDV2_REPORT_MINGRPLEN + nsrcs * 723 sizeof(struct in6_addr); 724 printf("]"); 725 } 726 } 727 return; 728 trunc: 729 (void)printf("[|icmp6]"); 730 return; 731 } 732 733 void 734 mldv2_query_print(const u_char *bp, u_int len) 735 { 736 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 737 u_int mrc, qqic; 738 int mrd, qqi; 739 int mant, exp; 740 u_int nsrcs; 741 u_int i; 742 743 if (len < MLD_V2_QUERY_MINLEN) { 744 printf(" [invalid len %d]", len); 745 return; 746 } 747 TCHECK(icp->icmp6_data16[0]); 748 mrc = ntohs(icp->icmp6_data16[0]); 749 if (mrc & MLDV2_MRC_FLOAT) { 750 mant = MLD_MRC_MANT(mrc); 751 exp = MLD_MRC_EXP(mrc); 752 mrd = MLDV2_MRD(mant, exp); 753 } else { 754 mrd = mrc; 755 } 756 if (vflag) { 757 (void)printf(" [max resp delay=%d]", mrd); 758 } 759 TCHECK2(bp[8], sizeof(struct in6_addr)); 760 printf(" [gaddr %s", ip6addr_string(&bp[8])); 761 762 if (vflag) { 763 TCHECK(bp[MLDV2_QUERY_QQIC]); 764 if (bp[MLDV2_QUERY_QRV] & MLDV2_QUERY_QRV_SFLAG) { 765 printf(" sflag"); 766 } 767 if (MLD_QRV(bp[MLDV2_QUERY_QRV])) { 768 printf(" robustness=%d", MLD_QRV(bp[MLDV2_QUERY_QRV])); 769 } 770 qqic = bp[MLDV2_QUERY_QQIC]; 771 if (qqic & MLDV2_QQIC_FLOAT) { 772 mant = MLD_QQIC_MANT(qqic); 773 exp = MLD_QQIC_EXP(qqic); 774 qqi = MLDV2_QQI(mant, exp); 775 } else { 776 qqi = bp[MLDV2_QUERY_QQIC]; 777 } 778 printf(" qqi=%d", qqi); 779 } 780 781 TCHECK2(bp[MLDV2_QUERY_NSRCS], 2); 782 nsrcs = ntohs(*(u_short *)&bp[MLDV2_QUERY_NSRCS]); 783 if (nsrcs > 0) { 784 if (len < MLD_V2_QUERY_MINLEN + nsrcs * sizeof(struct in6_addr)) 785 printf(" [invalid number of sources]"); 786 else if (vflag > 1) { 787 printf(" {"); 788 for (i = 0; i < nsrcs; i++) { 789 TCHECK2(bp[MLDV2_QUERY_SRC0 + i * 790 sizeof(struct in6_addr)], 791 sizeof(struct in6_addr)); 792 printf(" %s", 793 ip6addr_string(&bp[MLDV2_QUERY_SRC0 + i * 794 sizeof(struct in6_addr)])); 795 } 796 printf(" }"); 797 } else 798 printf(", %d source(s)", nsrcs); 799 } 800 printf("]"); 801 return; 802 trunc: 803 (void)printf("[|icmp6]"); 804 return; 805 } 806 807 808 #endif /* INET6 */ 809