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