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