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