1 /* $OpenBSD: print-icmp6.c,v 1.22 2018/10/22 16:12:45 kn 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 (void)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, ", ntohs(p->nd_ra_router_lifetime)); 325 printf("reachable_time=%u, ", 326 (u_int32_t)ntohl(p->nd_ra_reachable)); 327 printf("retrans_time=%u)", 328 (u_int32_t)ntohl(p->nd_ra_retransmit)); 329 #define RTADVLEN 16 330 icmp6_opt_print((const u_char *)dp + RTADVLEN, 331 icmp6len - RTADVLEN); 332 } 333 break; 334 case ND_NEIGHBOR_SOLICIT: 335 { 336 struct nd_neighbor_solicit *p; 337 p = (struct nd_neighbor_solicit *)dp; 338 TCHECK(p->nd_ns_target); 339 printf("icmp6: neighbor sol: who has %s", 340 ip6addr_string(&p->nd_ns_target)); 341 if (vflag) { 342 #define NDSOLLEN 24 343 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 344 icmp6len - NDSOLLEN); 345 } 346 } 347 break; 348 case ND_NEIGHBOR_ADVERT: 349 { 350 struct nd_neighbor_advert *p; 351 352 p = (struct nd_neighbor_advert *)dp; 353 TCHECK(p->nd_na_target); 354 printf("icmp6: neighbor adv: tgt is %s", 355 ip6addr_string(&p->nd_na_target)); 356 if (vflag) { 357 #define ND_NA_FLAG_ALL \ 358 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) 359 /* we don't need ntohl() here. see advanced-api-04. */ 360 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { 361 #undef ND_NA_FLAG_ALL 362 u_int32_t flags; 363 364 flags = p->nd_na_flags_reserved; 365 printf("("); 366 if (flags & ND_NA_FLAG_ROUTER) 367 printf("R"); 368 if (flags & ND_NA_FLAG_SOLICITED) 369 printf("S"); 370 if (flags & ND_NA_FLAG_OVERRIDE) 371 printf("O"); 372 printf(")"); 373 } 374 #define NDADVLEN 24 375 icmp6_opt_print((const u_char *)dp + NDADVLEN, 376 icmp6len - NDADVLEN); 377 } 378 } 379 break; 380 case ND_REDIRECT: 381 { 382 #define RDR(i) ((struct nd_redirect *)(i)) 383 char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN]; 384 385 TCHECK(RDR(dp)->nd_rd_dst); 386 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target, 387 tgtbuf, INET6_ADDRSTRLEN); 388 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst, 389 dstbuf, INET6_ADDRSTRLEN); 390 printf("icmp6: redirect %s to %s", dstbuf, tgtbuf); 391 #define REDIRECTLEN 40 392 if (vflag) { 393 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 394 icmp6len - REDIRECTLEN); 395 } 396 break; 397 } 398 case ICMP6_ROUTER_RENUMBERING: 399 switch (dp->icmp6_code) { 400 case ICMP6_ROUTER_RENUMBERING_COMMAND: 401 printf("icmp6: router renum command"); 402 break; 403 case ICMP6_ROUTER_RENUMBERING_RESULT: 404 printf("icmp6: router renum result"); 405 break; 406 default: 407 printf("icmp6: router renum code-#%d", dp->icmp6_code); 408 break; 409 } 410 break; 411 #ifdef ICMP6_WRUREQUEST 412 case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/ 413 { 414 int siz; 415 siz = ep - (u_char *)(dp + 1); 416 if (siz == 4) 417 printf("icmp6: who-are-you request"); 418 else { 419 printf("icmp6: FQDN request"); 420 if (vflag) { 421 if (siz < 8) 422 printf("?(icmp6_data %d bytes)", siz); 423 else if (8 < siz) 424 printf("?(extra %d bytes)", siz - 8); 425 } 426 } 427 break; 428 } 429 #endif /*ICMP6_WRUREQUEST*/ 430 #ifdef ICMP6_WRUREPLY 431 case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/ 432 { 433 enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN; 434 u_char const *buf; 435 u_char const *cp = NULL; 436 437 buf = (u_char *)(dp + 1); 438 439 /* fair guess */ 440 if (buf[12] == ep - buf - 13) 441 mode = FQDN; 442 else if (dp->icmp6_code == 1) 443 mode = FQDN; 444 445 /* wild guess */ 446 if (mode == UNKNOWN) { 447 cp = buf + 4; 448 while (cp < ep) { 449 if (!isprint(*cp++)) 450 mode = FQDN; 451 } 452 } 453 if (mode == UNKNOWN && 2 < labs(buf[12] - (ep - buf - 13))) 454 mode = WRU; 455 if (mode == UNKNOWN) 456 mode = FQDN; 457 458 if (mode == WRU) { 459 cp = buf + 4; 460 printf("icmp6: who-are-you reply(\""); 461 } else if (mode == FQDN) { 462 cp = buf + 13; 463 printf("icmp6: FQDN reply(\""); 464 } 465 for (; cp < ep; cp++) 466 printf((isprint(*cp) ? "%c" : "\\%03o"), *cp); 467 printf("\""); 468 if (vflag) { 469 printf(",%s", mode == FQDN ? "FQDN" : "WRU"); 470 if (mode == FQDN) { 471 int ttl; 472 ttl = (int)ntohl(*(u_int32_t *)&buf[8]); 473 if (dp->icmp6_code == 1) 474 printf(",TTL=unknown"); 475 else if (ttl < 0) 476 printf(",TTL=%d:invalid", ttl); 477 else 478 printf(",TTL=%d", ttl); 479 if (buf[12] != ep - buf - 13) { 480 (void)printf(",invalid namelen:%d/%u", 481 buf[12], 482 (unsigned int)(ep - buf - 13)); 483 } 484 } 485 } 486 printf(")"); 487 break; 488 } 489 #endif /*ICMP6_WRUREPLY*/ 490 case MLDV2_LISTENER_REPORT: 491 printf("multicast listener report v2"); 492 mldv2_report_print((const u_char *) dp, length); 493 break; 494 default: 495 printf("icmp6: type-#%d", dp->icmp6_type); 496 break; 497 } 498 if (vflag) { 499 if (TTEST2(dp->icmp6_type, length)) { 500 u_int16_t sum, icmp6_sum; 501 sum = icmp6_cksum(ip, dp, length); 502 if (sum != 0) { 503 icmp6_sum = EXTRACT_16BITS(&dp->icmp6_cksum); 504 printf(" [bad icmp6 cksum %x! -> %x]", icmp6_sum, 505 in_cksum_shouldbe(icmp6_sum, sum)); 506 } else 507 printf(" [icmp6 cksum ok]"); 508 } 509 } 510 return; 511 trunc: 512 fputs("[|icmp6]", stdout); 513 #if 0 514 #undef TCHECK 515 #endif 516 } 517 518 void 519 icmp6_opt_print(const u_char *bp, int resid) 520 { 521 const struct nd_opt_hdr *op; 522 const struct nd_opt_hdr *opl; /* why there's no struct? */ 523 const struct nd_opt_prefix_info *opp; 524 const struct icmp6_opts_redirect *opr; 525 const struct nd_opt_mtu *opm; 526 const struct nd_opt_rdnss *oprd; 527 const struct nd_opt_route_info *opri; 528 const u_char *ep; 529 const struct in6_addr *in6p; 530 struct in6_addr in6; 531 int i, opts_len; 532 #if 0 533 const struct ip6_hdr *ip; 534 const char *str; 535 const struct ip6_hdr *oip; 536 const struct udphdr *ouh; 537 int hlen, dport; 538 char buf[256]; 539 #endif 540 541 #if 0 542 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc 543 #endif 544 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 545 546 op = (struct nd_opt_hdr *)bp; 547 #if 0 548 ip = (struct ip6_hdr *)bp2; 549 oip = &dp->icmp6_ip6; 550 str = buf; 551 #endif 552 /* 'ep' points to the end of avaible data. */ 553 ep = snapend; 554 555 ECHECK(op->nd_opt_len); 556 if (resid <= 0) 557 return; 558 if (op->nd_opt_len == 0) 559 goto trunc; 560 if (bp + (op->nd_opt_len << 3) > ep) 561 goto trunc; 562 switch (op->nd_opt_type) { 563 case ND_OPT_SOURCE_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("(src 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_TARGET_LINKADDR: 580 opl = (struct nd_opt_hdr *)op; 581 #if 1 582 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) 583 goto trunc; 584 #else 585 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); 586 #endif 587 printf("(tgt lladdr: %s", 588 etheraddr_string((u_char *)(opl + 1))); 589 if (opl->nd_opt_len != 1) 590 printf("!"); 591 printf(")"); 592 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 593 resid - (op->nd_opt_len << 3)); 594 break; 595 case ND_OPT_PREFIX_INFORMATION: 596 opp = (struct nd_opt_prefix_info *)op; 597 TCHECK(opp->nd_opt_pi_prefix); 598 printf("(prefix info: "); 599 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) 600 printf("L"); 601 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) 602 printf("A"); 603 if (opp->nd_opt_pi_flags_reserved) 604 printf(" "); 605 printf("valid_ltime="); 606 if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U) 607 printf("infinity"); 608 else { 609 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time)); 610 } 611 printf(", "); 612 printf("preferred_ltime="); 613 if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U) 614 printf("infinity"); 615 else { 616 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)); 617 } 618 printf(", "); 619 printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), 620 opp->nd_opt_pi_prefix_len); 621 if (opp->nd_opt_pi_len != 4) 622 printf("!"); 623 printf(")"); 624 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 625 resid - (op->nd_opt_len << 3)); 626 break; 627 case ND_OPT_REDIRECTED_HEADER: 628 opr = (struct icmp6_opts_redirect *)op; 629 printf("(redirect)"); 630 /* xxx */ 631 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 632 resid - (op->nd_opt_len << 3)); 633 break; 634 case ND_OPT_MTU: 635 opm = (struct nd_opt_mtu *)op; 636 TCHECK(opm->nd_opt_mtu_mtu); 637 printf("(mtu: "); 638 printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); 639 if (opm->nd_opt_mtu_len != 1) 640 printf("!"); 641 printf(")"); 642 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 643 resid - (op->nd_opt_len << 3)); 644 break; 645 case ND_OPT_ROUTE_INFO: 646 opri = (struct nd_opt_route_info *)op; 647 TCHECK(opri->nd_opt_rti_lifetime); 648 printf("(route-info: "); 649 memset(&in6, 0, sizeof(in6)); 650 in6p = (const struct in6_addr *)(opri + 1); 651 switch (op->nd_opt_len) { 652 case 1: 653 break; 654 case 2: 655 TCHECK2(*in6p, 8); 656 memcpy(&in6, opri + 1, 8); 657 break; 658 case 3: 659 TCHECK(*in6p); 660 memcpy(&in6, opri + 1, sizeof(in6)); 661 break; 662 default: 663 goto trunc; 664 } 665 printf("%s/%u, ", ip6addr_string(&in6), 666 opri->nd_opt_rti_prefixlen); 667 switch (opri->nd_opt_rti_flags & ND_RA_FLAG_RTPREF_MASK) { 668 case ND_RA_FLAG_RTPREF_HIGH: 669 printf("pref=high, "); 670 break; 671 case ND_RA_FLAG_RTPREF_MEDIUM: 672 printf("pref=medium, "); 673 break; 674 case ND_RA_FLAG_RTPREF_LOW: 675 printf("pref=low, "); 676 break; 677 case ND_RA_FLAG_RTPREF_RSV: 678 printf("pref=rsv, "); 679 break; 680 } 681 printf("lifetime=%us)", 682 (u_int32_t)ntohl(opri->nd_opt_rti_lifetime)); 683 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 684 resid - (op->nd_opt_len << 3)); 685 break; 686 case ND_OPT_RDNSS: 687 oprd = (const struct nd_opt_rdnss *)op; 688 printf("(rdnss: "); 689 TCHECK(oprd->nd_opt_rdnss_lifetime); 690 printf("lifetime=%us", 691 (u_int32_t)ntohl(oprd->nd_opt_rdnss_lifetime)); 692 if (oprd->nd_opt_rdnss_len < 3) { 693 printf("!"); 694 } else for (i = 0; i < ((oprd->nd_opt_rdnss_len - 1) / 2); i++) { 695 struct in6_addr *addr = (struct in6_addr *)(oprd + 1) + i; 696 TCHECK2(*addr, sizeof(struct in6_addr)); 697 printf(", addr=%s", ip6addr_string(addr)); 698 } 699 printf(")"); 700 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 701 resid - (op->nd_opt_len << 3)); 702 break; 703 case ND_OPT_DNSSL: 704 printf("(dnssl: opt_len=%d)", op->nd_opt_len); 705 /* XXX */ 706 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 707 resid - (op->nd_opt_len << 3)); 708 break; 709 default: 710 opts_len = op->nd_opt_len; 711 printf("(unknown opt_type=%d, opt_len=%d)", 712 op->nd_opt_type, opts_len); 713 if (opts_len == 0) 714 opts_len = 1; /* XXX */ 715 icmp6_opt_print((const u_char *)op + (opts_len << 3), 716 resid - (opts_len << 3)); 717 break; 718 } 719 return; 720 trunc: 721 fputs("[ndp opt]", stdout); 722 return; 723 #if 0 724 #undef TCHECK 725 #endif 726 #undef ECHECK 727 } 728 729 void 730 mld6_print(const u_char *bp) 731 { 732 struct mld_hdr *mp = (struct mld_hdr *)bp; 733 const u_char *ep; 734 735 /* 'ep' points to the end of avaible data. */ 736 ep = snapend; 737 738 if ((u_char *)mp + sizeof(*mp) > ep) 739 return; 740 741 printf("max resp delay: %d ", ntohs(mp->mld_maxdelay)); 742 printf("addr: %s", ip6addr_string(&mp->mld_addr)); 743 744 return; 745 } 746 747 void 748 mldv2_report_print(const u_char *bp, u_int len) 749 { 750 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 751 u_int group, nsrcs, ngroups; 752 u_int i, j; 753 754 if (len < MLDV2_REPORT_MINLEN) { 755 printf(" [invalid len %d]", len); 756 return; 757 } 758 759 TCHECK(icp->icmp6_data16[1]); 760 ngroups = ntohs(icp->icmp6_data16[1]); 761 printf(", %d group record(s)", ngroups); 762 if (vflag > 0) { 763 /* Print the group records */ 764 group = MLDV2_REPORT_GROUP0; 765 for (i = 0; i < ngroups; i++) { 766 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 767 if (len < group + MLDV2_REPORT_MINGRPLEN) { 768 printf(" [invalid number of groups]"); 769 return; 770 } 771 TCHECK2(bp[group + MLDV2_RGROUP_MADDR], 772 sizeof(struct in6_addr)); 773 printf(" [gaddr %s", 774 ip6addr_string(&bp[group + MLDV2_RGROUP_MADDR])); 775 printf(" %s", tok2str(mldv2report2str, 776 " [v2-report-#%d]", bp[group])); 777 nsrcs = (bp[group + MLDV2_RGROUP_NSRCS] << 8) + 778 bp[group + MLDV2_RGROUP_NSRCS + 1]; 779 /* Check the number of sources and print them */ 780 if (len < group + MLDV2_REPORT_MINGRPLEN + 781 (nsrcs * sizeof(struct in6_addr))) { 782 printf(" [invalid number of sources %d]", nsrcs); 783 return; 784 } 785 if (vflag == 1) 786 printf(", %d source(s)", nsrcs); 787 else { 788 /* Print the sources */ 789 (void)printf(" {"); 790 for (j = 0; j < nsrcs; j++) { 791 TCHECK2(bp[group + 792 MLDV2_REPORT_MINGRPLEN + 793 j * sizeof(struct in6_addr)], 794 sizeof(struct in6_addr)); 795 printf(" %s", ip6addr_string(&bp[group + 796 MLDV2_REPORT_MINGRPLEN + j * 797 sizeof(struct in6_addr)])); 798 } 799 (void)printf(" }"); 800 } 801 /* Next group record */ 802 group += MLDV2_REPORT_MINGRPLEN + nsrcs * 803 sizeof(struct in6_addr); 804 printf("]"); 805 } 806 } 807 return; 808 trunc: 809 (void)printf("[|icmp6]"); 810 return; 811 } 812 813 void 814 mldv2_query_print(const u_char *bp, u_int len) 815 { 816 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 817 u_int mrc, qqic; 818 int mrd, qqi; 819 int mant, exp; 820 u_int nsrcs; 821 u_int i; 822 823 if (len < MLD_V2_QUERY_MINLEN) { 824 printf(" [invalid len %d]", len); 825 return; 826 } 827 TCHECK(icp->icmp6_data16[0]); 828 mrc = ntohs(icp->icmp6_data16[0]); 829 if (mrc & MLDV2_MRC_FLOAT) { 830 mant = MLD_MRC_MANT(mrc); 831 exp = MLD_MRC_EXP(mrc); 832 mrd = MLDV2_MRD(mant, exp); 833 } else { 834 mrd = mrc; 835 } 836 if (vflag) { 837 (void)printf(" [max resp delay=%d]", mrd); 838 } 839 TCHECK2(bp[8], sizeof(struct in6_addr)); 840 printf(" [gaddr %s", ip6addr_string(&bp[8])); 841 842 if (vflag) { 843 TCHECK(bp[MLDV2_QUERY_QQIC]); 844 if (bp[MLDV2_QUERY_QRV] & MLDV2_QUERY_QRV_SFLAG) { 845 printf(" sflag"); 846 } 847 if (MLD_QRV(bp[MLDV2_QUERY_QRV])) { 848 printf(" robustness=%d", MLD_QRV(bp[MLDV2_QUERY_QRV])); 849 } 850 qqic = bp[MLDV2_QUERY_QQIC]; 851 if (qqic & MLDV2_QQIC_FLOAT) { 852 mant = MLD_QQIC_MANT(qqic); 853 exp = MLD_QQIC_EXP(qqic); 854 qqi = MLDV2_QQI(mant, exp); 855 } else { 856 qqi = bp[MLDV2_QUERY_QQIC]; 857 } 858 printf(" qqi=%d", qqi); 859 } 860 861 TCHECK2(bp[MLDV2_QUERY_NSRCS], 2); 862 nsrcs = ntohs(*(u_short *)&bp[MLDV2_QUERY_NSRCS]); 863 if (nsrcs > 0) { 864 if (len < MLD_V2_QUERY_MINLEN + nsrcs * sizeof(struct in6_addr)) 865 printf(" [invalid number of sources]"); 866 else if (vflag > 1) { 867 printf(" {"); 868 for (i = 0; i < nsrcs; i++) { 869 TCHECK2(bp[MLDV2_QUERY_SRC0 + i * 870 sizeof(struct in6_addr)], 871 sizeof(struct in6_addr)); 872 printf(" %s", 873 ip6addr_string(&bp[MLDV2_QUERY_SRC0 + i * 874 sizeof(struct in6_addr)])); 875 } 876 printf(" }"); 877 } else 878 printf(", %d source(s)", nsrcs); 879 } 880 printf("]"); 881 return; 882 trunc: 883 (void)printf("[|icmp6]"); 884 return; 885 } 886