1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22 #ifndef lint 23 static const char rcsid[] _U_ = 24 "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.72.2.4 2004/03/24 00:14:09 guy Exp $"; 25 #endif 26 27 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #ifdef INET6 32 33 #include <tcpdump-stdinc.h> 34 35 #include <stdio.h> 36 #include <string.h> 37 38 #include "ip6.h" 39 #include "icmp6.h" 40 #include "ipproto.h" 41 42 #include "interface.h" 43 #include "addrtoname.h" 44 #include "extract.h" 45 46 #include "udp.h" 47 #include "ah.h" 48 49 static const char *get_rtpref(u_int); 50 static const char *get_lifetime(u_int32_t); 51 static void print_lladdr(const u_char *, size_t); 52 static void icmp6_opt_print(const u_char *, int); 53 static void mld6_print(const u_char *); 54 static struct udphdr *get_upperlayer(u_char *, u_int *); 55 static void dnsname_print(const u_char *, const u_char *); 56 static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); 57 static void icmp6_rrenum_print(const u_char *, const u_char *); 58 59 #ifndef abs 60 #define abs(a) ((0 < (a)) ? (a) : -(a)) 61 #endif 62 63 static const char * 64 get_rtpref(u_int v) 65 { 66 static const char *rtpref_str[] = { 67 "medium", /* 00 */ 68 "high", /* 01 */ 69 "rsv", /* 10 */ 70 "low" /* 11 */ 71 }; 72 73 return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 74 } 75 76 static const char * 77 get_lifetime(u_int32_t v) 78 { 79 static char buf[20]; 80 81 if (v == (u_int32_t)~0UL) 82 return "infinity"; 83 else { 84 snprintf(buf, sizeof(buf), "%u", v); 85 return buf; 86 } 87 } 88 89 static void 90 print_lladdr(const u_int8_t *p, size_t l) 91 { 92 const u_int8_t *ep, *q; 93 94 q = p; 95 ep = p + l; 96 while (l > 0 && q < ep) { 97 if (q > p) 98 printf(":"); 99 printf("%02x", *q++); 100 l--; 101 } 102 } 103 104 static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, 105 u_int len) 106 { 107 size_t i; 108 register const u_int16_t *sp; 109 u_int32_t sum; 110 union { 111 struct { 112 struct in6_addr ph_src; 113 struct in6_addr ph_dst; 114 u_int32_t ph_len; 115 u_int8_t ph_zero[3]; 116 u_int8_t ph_nxt; 117 } ph; 118 u_int16_t pa[20]; 119 } phu; 120 121 /* pseudo-header */ 122 memset(&phu, 0, sizeof(phu)); 123 phu.ph.ph_src = ip6->ip6_src; 124 phu.ph.ph_dst = ip6->ip6_dst; 125 phu.ph.ph_len = htonl(len); 126 phu.ph.ph_nxt = IPPROTO_ICMPV6; 127 128 sum = 0; 129 for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 130 sum += phu.pa[i]; 131 132 sp = (const u_int16_t *)icp; 133 134 for (i = 0; i < (len & ~1); i += 2) 135 sum += *sp++; 136 137 if (len & 1) 138 sum += htons((*(const u_int8_t *)sp) << 8); 139 140 while (sum > 0xffff) 141 sum = (sum & 0xffff) + (sum >> 16); 142 sum = ~sum & 0xffff; 143 144 return (sum); 145 } 146 147 void 148 icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented) 149 { 150 const struct icmp6_hdr *dp; 151 const struct ip6_hdr *ip; 152 const char *str; 153 const struct ip6_hdr *oip; 154 const struct udphdr *ouh; 155 int dport; 156 const u_char *ep; 157 char buf[256]; 158 u_int prot; 159 160 dp = (struct icmp6_hdr *)bp; 161 ip = (struct ip6_hdr *)bp2; 162 oip = (struct ip6_hdr *)(dp + 1); 163 str = buf; 164 /* 'ep' points to the end of available data. */ 165 ep = snapend; 166 167 TCHECK(dp->icmp6_cksum); 168 169 if (vflag && !fragmented) { 170 int sum = dp->icmp6_cksum; 171 172 if (TTEST2(bp[0], length)) { 173 sum = icmp6_cksum(ip, dp, length); 174 if (sum != 0) 175 (void)printf("[bad icmp6 cksum %x!] ", sum); 176 else 177 (void)printf("[icmp6 sum ok] "); 178 } 179 } 180 181 switch (dp->icmp6_type) { 182 case ICMP6_DST_UNREACH: 183 TCHECK(oip->ip6_dst); 184 switch (dp->icmp6_code) { 185 case ICMP6_DST_UNREACH_NOROUTE: 186 printf("icmp6: %s unreachable route", 187 ip6addr_string(&oip->ip6_dst)); 188 break; 189 case ICMP6_DST_UNREACH_ADMIN: 190 printf("icmp6: %s unreachable prohibited", 191 ip6addr_string(&oip->ip6_dst)); 192 break; 193 case ICMP6_DST_UNREACH_BEYONDSCOPE: 194 printf("icmp6: %s beyond scope of source address %s", 195 ip6addr_string(&oip->ip6_dst), 196 ip6addr_string(&oip->ip6_src)); 197 break; 198 case ICMP6_DST_UNREACH_ADDR: 199 printf("icmp6: %s unreachable address", 200 ip6addr_string(&oip->ip6_dst)); 201 break; 202 case ICMP6_DST_UNREACH_NOPORT: 203 if ((ouh = get_upperlayer((u_char *)oip, &prot)) 204 == NULL) 205 goto trunc; 206 207 dport = EXTRACT_16BITS(&ouh->uh_dport); 208 switch (prot) { 209 case IPPROTO_TCP: 210 printf("icmp6: %s tcp port %s unreachable", 211 ip6addr_string(&oip->ip6_dst), 212 tcpport_string(dport)); 213 break; 214 case IPPROTO_UDP: 215 printf("icmp6: %s udp port %s unreachable", 216 ip6addr_string(&oip->ip6_dst), 217 udpport_string(dport)); 218 break; 219 default: 220 printf("icmp6: %s protocol %d port %d unreachable", 221 ip6addr_string(&oip->ip6_dst), 222 oip->ip6_nxt, dport); 223 break; 224 } 225 break; 226 default: 227 printf("icmp6: %s unreachable code-#%d", 228 ip6addr_string(&oip->ip6_dst), 229 dp->icmp6_code); 230 break; 231 } 232 break; 233 case ICMP6_PACKET_TOO_BIG: 234 TCHECK(dp->icmp6_mtu); 235 printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 236 break; 237 case ICMP6_TIME_EXCEEDED: 238 TCHECK(oip->ip6_dst); 239 switch (dp->icmp6_code) { 240 case ICMP6_TIME_EXCEED_TRANSIT: 241 printf("icmp6: time exceeded in-transit for %s", 242 ip6addr_string(&oip->ip6_dst)); 243 break; 244 case ICMP6_TIME_EXCEED_REASSEMBLY: 245 printf("icmp6: ip6 reassembly time exceeded"); 246 break; 247 default: 248 printf("icmp6: time exceeded code-#%d", 249 dp->icmp6_code); 250 break; 251 } 252 break; 253 case ICMP6_PARAM_PROB: 254 TCHECK(oip->ip6_dst); 255 switch (dp->icmp6_code) { 256 case ICMP6_PARAMPROB_HEADER: 257 printf("icmp6: parameter problem errorneous - octet %u", 258 EXTRACT_32BITS(&dp->icmp6_pptr)); 259 break; 260 case ICMP6_PARAMPROB_NEXTHEADER: 261 printf("icmp6: parameter problem next header - octet %u", 262 EXTRACT_32BITS(&dp->icmp6_pptr)); 263 break; 264 case ICMP6_PARAMPROB_OPTION: 265 printf("icmp6: parameter problem option - octet %u", 266 EXTRACT_32BITS(&dp->icmp6_pptr)); 267 break; 268 default: 269 printf("icmp6: parameter problem code-#%d", 270 dp->icmp6_code); 271 break; 272 } 273 break; 274 case ICMP6_ECHO_REQUEST: 275 case ICMP6_ECHO_REPLY: 276 TCHECK(dp->icmp6_seq); 277 printf("icmp6: echo %s seq %u", 278 dp->icmp6_type == ICMP6_ECHO_REQUEST ? 279 "request" : "reply", 280 EXTRACT_16BITS(&dp->icmp6_seq)); 281 break; 282 case ICMP6_MEMBERSHIP_QUERY: 283 printf("icmp6: multicast listener query "); 284 mld6_print((const u_char *)dp); 285 break; 286 case ICMP6_MEMBERSHIP_REPORT: 287 printf("icmp6: multicast listener report "); 288 mld6_print((const u_char *)dp); 289 break; 290 case ICMP6_MEMBERSHIP_REDUCTION: 291 printf("icmp6: multicast listener done "); 292 mld6_print((const u_char *)dp); 293 break; 294 case ND_ROUTER_SOLICIT: 295 printf("icmp6: router solicitation "); 296 if (vflag) { 297 #define RTSOLLEN 8 298 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 299 length - RTSOLLEN); 300 } 301 break; 302 case ND_ROUTER_ADVERT: 303 printf("icmp6: router advertisement"); 304 if (vflag) { 305 struct nd_router_advert *p; 306 307 p = (struct nd_router_advert *)dp; 308 TCHECK(p->nd_ra_retransmit); 309 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); 310 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) 311 printf("M"); 312 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) 313 printf("O"); 314 if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT) 315 printf("H"); 316 317 if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK) 318 != 0) 319 printf(" "); 320 321 printf("pref=%s, ", 322 get_rtpref(p->nd_ra_flags_reserved)); 323 324 printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime)); 325 printf("reachable_time=%u, ", 326 EXTRACT_32BITS(&p->nd_ra_reachable)); 327 printf("retrans_time=%u)", 328 EXTRACT_32BITS(&p->nd_ra_retransmit)); 329 #define RTADVLEN 16 330 icmp6_opt_print((const u_char *)dp + RTADVLEN, 331 length - 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 length - 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 length - NDADVLEN); 377 #undef NDADVLEN 378 } 379 } 380 break; 381 case ND_REDIRECT: 382 #define RDR(i) ((struct nd_redirect *)(i)) 383 TCHECK(RDR(dp)->nd_rd_dst); 384 printf("icmp6: redirect %s", 385 getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 386 TCHECK(RDR(dp)->nd_rd_target); 387 printf(" to %s", 388 getname6((const u_char*)&RDR(dp)->nd_rd_target)); 389 #define REDIRECTLEN 40 390 if (vflag) { 391 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 392 length - REDIRECTLEN); 393 } 394 break; 395 #undef REDIRECTLEN 396 #undef RDR 397 case ICMP6_ROUTER_RENUMBERING: 398 icmp6_rrenum_print(bp, ep); 399 break; 400 case ICMP6_NI_QUERY: 401 case ICMP6_NI_REPLY: 402 icmp6_nodeinfo_print(length, bp, ep); 403 break; 404 case ICMP6_HADISCOV_REQUEST: 405 printf("icmp6: ha discovery request"); 406 if (vflag) { 407 TCHECK(dp->icmp6_data16[0]); 408 printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0])); 409 } 410 break; 411 case ICMP6_HADISCOV_REPLY: 412 printf("icmp6: ha discovery reply"); 413 if (vflag) { 414 struct in6_addr *in6; 415 u_char *cp; 416 417 TCHECK(dp->icmp6_data16[0]); 418 printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0])); 419 cp = (u_char *)dp + length; 420 in6 = (struct in6_addr *)(dp + 1); 421 for (; (u_char *)in6 < cp; in6++) { 422 TCHECK(*in6); 423 printf(", %s", ip6addr_string(in6)); 424 } 425 printf(")"); 426 } 427 break; 428 case ICMP6_MOBILEPREFIX_SOLICIT: 429 printf("icmp6: mobile router solicitation"); 430 if (vflag) { 431 TCHECK(dp->icmp6_data16[0]); 432 printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0])); 433 } 434 break; 435 case ICMP6_MOBILEPREFIX_ADVERT: 436 printf("icmp6: mobile router advertisement"); 437 if (vflag) { 438 TCHECK(dp->icmp6_data16[0]); 439 printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0])); 440 if (dp->icmp6_data16[1] & 0xc0) 441 printf(" "); 442 if (dp->icmp6_data16[1] & 0x80) 443 printf("M"); 444 if (dp->icmp6_data16[1] & 0x40) 445 printf("O"); 446 printf(")"); 447 #define MPADVLEN 8 448 icmp6_opt_print((const u_char *)dp + MPADVLEN, 449 length - MPADVLEN); 450 } 451 break; 452 default: 453 printf("icmp6: type-#%d", dp->icmp6_type); 454 break; 455 } 456 return; 457 trunc: 458 fputs("[|icmp6]", stdout); 459 } 460 461 static struct udphdr * 462 get_upperlayer(u_char *bp, u_int *prot) 463 { 464 const u_char *ep; 465 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 466 struct udphdr *uh; 467 struct ip6_hbh *hbh; 468 struct ip6_frag *fragh; 469 struct ah *ah; 470 u_int nh; 471 int hlen; 472 473 /* 'ep' points to the end of available data. */ 474 ep = snapend; 475 476 if (!TTEST(ip6->ip6_nxt)) 477 return NULL; 478 479 nh = ip6->ip6_nxt; 480 hlen = sizeof(struct ip6_hdr); 481 482 while (bp < snapend) { 483 bp += hlen; 484 485 switch(nh) { 486 case IPPROTO_UDP: 487 case IPPROTO_TCP: 488 uh = (struct udphdr *)bp; 489 if (TTEST(uh->uh_dport)) { 490 *prot = nh; 491 return(uh); 492 } 493 else 494 return(NULL); 495 /* NOTREACHED */ 496 497 case IPPROTO_HOPOPTS: 498 case IPPROTO_DSTOPTS: 499 case IPPROTO_ROUTING: 500 hbh = (struct ip6_hbh *)bp; 501 if (!TTEST(hbh->ip6h_len)) 502 return(NULL); 503 nh = hbh->ip6h_nxt; 504 hlen = (hbh->ip6h_len + 1) << 3; 505 break; 506 507 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 508 fragh = (struct ip6_frag *)bp; 509 if (!TTEST(fragh->ip6f_offlg)) 510 return(NULL); 511 /* fragments with non-zero offset are meaningless */ 512 if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 513 return(NULL); 514 nh = fragh->ip6f_nxt; 515 hlen = sizeof(struct ip6_frag); 516 break; 517 518 case IPPROTO_AH: 519 ah = (struct ah *)bp; 520 if (!TTEST(ah->ah_len)) 521 return(NULL); 522 nh = ah->ah_nxt; 523 hlen = (ah->ah_len + 2) << 2; 524 break; 525 526 default: /* unknown or undecodable header */ 527 *prot = nh; /* meaningless, but set here anyway */ 528 return(NULL); 529 } 530 } 531 532 return(NULL); /* should be notreached, though */ 533 } 534 535 static void 536 icmp6_opt_print(const u_char *bp, int resid) 537 { 538 const struct nd_opt_hdr *op; 539 const struct nd_opt_hdr *opl; /* why there's no struct? */ 540 const struct nd_opt_prefix_info *opp; 541 const struct icmp6_opts_redirect *opr; 542 const struct nd_opt_mtu *opm; 543 const struct nd_opt_advinterval *opa; 544 const struct nd_opt_homeagent_info *oph; 545 const struct nd_opt_route_info *opri; 546 const u_char *cp, *ep; 547 struct in6_addr in6, *in6p; 548 size_t l; 549 550 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 551 552 cp = bp; 553 /* 'ep' points to the end of available data. */ 554 ep = snapend; 555 556 while (cp < ep) { 557 op = (struct nd_opt_hdr *)cp; 558 559 ECHECK(op->nd_opt_len); 560 if (resid <= 0) 561 return; 562 if (op->nd_opt_len == 0) 563 goto trunc; 564 if (cp + (op->nd_opt_len << 3) > ep) 565 goto trunc; 566 567 switch (op->nd_opt_type) { 568 case ND_OPT_SOURCE_LINKADDR: 569 opl = (struct nd_opt_hdr *)op; 570 printf("(src lladdr: "); 571 l = (op->nd_opt_len << 3) - 2; 572 print_lladdr(cp + 2, l); 573 /*(*/ 574 printf(")"); 575 break; 576 case ND_OPT_TARGET_LINKADDR: 577 opl = (struct nd_opt_hdr *)op; 578 printf("(tgt lladdr: "); 579 l = (op->nd_opt_len << 3) - 2; 580 print_lladdr(cp + 2, l); 581 /*(*/ 582 printf(")"); 583 break; 584 case ND_OPT_PREFIX_INFORMATION: 585 opp = (struct nd_opt_prefix_info *)op; 586 TCHECK(opp->nd_opt_pi_prefix); 587 printf("(prefix info: "); /*)*/ 588 if (op->nd_opt_len != 4) { 589 printf("badlen"); 590 /*(*/ 591 printf(")"); 592 break; 593 } 594 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) 595 printf("L"); 596 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) 597 printf("A"); 598 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER) 599 printf("R"); 600 if (opp->nd_opt_pi_flags_reserved) 601 printf(" "); 602 printf("valid_ltime=%s,", 603 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 604 printf("preferred_ltime=%s,", 605 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 606 printf("prefix=%s/%d", 607 ip6addr_string(&opp->nd_opt_pi_prefix), 608 opp->nd_opt_pi_prefix_len); 609 if (opp->nd_opt_pi_len != 4) 610 printf("!"); 611 /*(*/ 612 printf(")"); 613 break; 614 case ND_OPT_REDIRECTED_HEADER: 615 opr = (struct icmp6_opts_redirect *)op; 616 printf("(redirect)"); 617 /* xxx */ 618 break; 619 case ND_OPT_MTU: 620 opm = (struct nd_opt_mtu *)op; 621 TCHECK(opm->nd_opt_mtu_mtu); 622 printf("(mtu:"); /*)*/ 623 if (op->nd_opt_len != 1) { 624 printf("badlen"); 625 /*(*/ 626 printf(")"); 627 break; 628 } 629 printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu)); 630 if (opm->nd_opt_mtu_len != 1) 631 printf("!"); 632 printf(")"); 633 break; 634 case ND_OPT_ADVINTERVAL: 635 opa = (struct nd_opt_advinterval *)op; 636 TCHECK(opa->nd_opt_adv_interval); 637 printf("(advint:"); /*)*/ 638 printf(" advint=%u", 639 EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 640 /*(*/ 641 printf(")"); 642 break; 643 case ND_OPT_HOMEAGENT_INFO: 644 oph = (struct nd_opt_homeagent_info *)op; 645 TCHECK(oph->nd_opt_hai_lifetime); 646 printf("(ha info:"); /*)*/ 647 printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference)); 648 printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 649 printf(")"); 650 break; 651 case ND_OPT_ROUTE_INFO: 652 opri = (struct nd_opt_route_info *)op; 653 TCHECK(opri->nd_opt_rti_lifetime); 654 memset(&in6, 0, sizeof(in6)); 655 in6p = (struct in6_addr *)(opri + 1); 656 switch (op->nd_opt_len) { 657 case 1: 658 break; 659 case 2: 660 TCHECK2(*in6p, 8); 661 memcpy(&in6, opri + 1, 8); 662 break; 663 case 3: 664 TCHECK(*in6p); 665 memcpy(&in6, opri + 1, sizeof(in6)); 666 break; 667 default: 668 goto trunc; 669 } 670 printf("(rtinfo:"); /*)*/ 671 printf(" %s/%u", ip6addr_string(&in6), 672 opri->nd_opt_rti_prefixlen); 673 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 674 printf(", lifetime=%s", 675 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 676 /*(*/ 677 printf(")"); 678 break; 679 default: 680 printf("(unknown opt_type=%d, opt_len=%d)", 681 op->nd_opt_type, op->nd_opt_len); 682 break; 683 } 684 685 cp += op->nd_opt_len << 3; 686 resid -= op->nd_opt_len << 3; 687 } 688 return; 689 690 trunc: 691 fputs("[ndp opt]", stdout); 692 return; 693 #undef ECHECK 694 } 695 696 static void 697 mld6_print(const u_char *bp) 698 { 699 struct mld6_hdr *mp = (struct mld6_hdr *)bp; 700 const u_char *ep; 701 702 /* 'ep' points to the end of available data. */ 703 ep = snapend; 704 705 if ((u_char *)mp + sizeof(*mp) > ep) 706 return; 707 708 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 709 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 710 } 711 712 static void 713 dnsname_print(const u_char *cp, const u_char *ep) 714 { 715 int i; 716 717 /* DNS name decoding - no decompression */ 718 printf(", \""); 719 while (cp < ep) { 720 i = *cp++; 721 if (i) { 722 if (i > ep - cp) { 723 printf("???"); 724 break; 725 } 726 while (i-- && cp < ep) { 727 safeputchar(*cp); 728 cp++; 729 } 730 if (cp + 1 < ep && *cp) 731 printf("."); 732 } else { 733 if (cp == ep) { 734 /* FQDN */ 735 printf("."); 736 } else if (cp + 1 == ep && *cp == '\0') { 737 /* truncated */ 738 } else { 739 /* invalid */ 740 printf("???"); 741 } 742 break; 743 } 744 } 745 printf("\""); 746 } 747 748 static void 749 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 750 { 751 struct icmp6_nodeinfo *ni6; 752 struct icmp6_hdr *dp; 753 const u_char *cp; 754 size_t siz, i; 755 int needcomma; 756 757 if (ep < bp) 758 return; 759 dp = (struct icmp6_hdr *)bp; 760 ni6 = (struct icmp6_nodeinfo *)bp; 761 siz = ep - bp; 762 763 switch (ni6->ni_type) { 764 case ICMP6_NI_QUERY: 765 if (siz == sizeof(*dp) + 4) { 766 /* KAME who-are-you */ 767 printf("icmp6: who-are-you request"); 768 break; 769 } 770 printf("icmp6: node information query"); 771 772 TCHECK2(*dp, sizeof(*ni6)); 773 ni6 = (struct icmp6_nodeinfo *)dp; 774 printf(" ("); /*)*/ 775 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 776 case NI_QTYPE_NOOP: 777 printf("noop"); 778 break; 779 case NI_QTYPE_SUPTYPES: 780 printf("supported qtypes"); 781 i = EXTRACT_16BITS(&ni6->ni_flags); 782 if (i) 783 printf(" [%s]", (i & 0x01) ? "C" : ""); 784 break; 785 break; 786 case NI_QTYPE_FQDN: 787 printf("DNS name"); 788 break; 789 case NI_QTYPE_NODEADDR: 790 printf("node addresses"); 791 i = ni6->ni_flags; 792 if (!i) 793 break; 794 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 795 printf(" [%s%s%s%s%s%s]", 796 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 797 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 798 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 799 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 800 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 801 (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 802 break; 803 default: 804 printf("unknown"); 805 break; 806 } 807 808 if (ni6->ni_qtype == NI_QTYPE_NOOP || 809 ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 810 if (siz != sizeof(*ni6)) 811 if (vflag) 812 printf(", invalid len"); 813 /*(*/ 814 printf(")"); 815 break; 816 } 817 818 819 /* XXX backward compat, icmp-name-lookup-03 */ 820 if (siz == sizeof(*ni6)) { 821 printf(", 03 draft"); 822 /*(*/ 823 printf(")"); 824 break; 825 } 826 827 switch (ni6->ni_code) { 828 case ICMP6_NI_SUBJ_IPV6: 829 if (!TTEST2(*dp, 830 sizeof(*ni6) + sizeof(struct in6_addr))) 831 break; 832 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 833 if (vflag) 834 printf(", invalid subject len"); 835 break; 836 } 837 printf(", subject=%s", 838 getname6((const u_char *)(ni6 + 1))); 839 break; 840 case ICMP6_NI_SUBJ_FQDN: 841 printf(", subject=DNS name"); 842 cp = (const u_char *)(ni6 + 1); 843 if (cp[0] == ep - cp - 1) { 844 /* icmp-name-lookup-03, pascal string */ 845 if (vflag) 846 printf(", 03 draft"); 847 cp++; 848 printf(", \""); 849 while (cp < ep) { 850 safeputchar(*cp); 851 cp++; 852 } 853 printf("\""); 854 } else 855 dnsname_print(cp, ep); 856 break; 857 case ICMP6_NI_SUBJ_IPV4: 858 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 859 break; 860 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 861 if (vflag) 862 printf(", invalid subject len"); 863 break; 864 } 865 printf(", subject=%s", 866 getname((const u_char *)(ni6 + 1))); 867 break; 868 default: 869 printf(", unknown subject"); 870 break; 871 } 872 873 /*(*/ 874 printf(")"); 875 break; 876 877 case ICMP6_NI_REPLY: 878 if (icmp6len > siz) { 879 printf("[|icmp6: node information reply]"); 880 break; 881 } 882 883 needcomma = 0; 884 885 ni6 = (struct icmp6_nodeinfo *)dp; 886 printf("icmp6: node information reply"); 887 printf(" ("); /*)*/ 888 switch (ni6->ni_code) { 889 case ICMP6_NI_SUCCESS: 890 if (vflag) { 891 printf("success"); 892 needcomma++; 893 } 894 break; 895 case ICMP6_NI_REFUSED: 896 printf("refused"); 897 needcomma++; 898 if (siz != sizeof(*ni6)) 899 if (vflag) 900 printf(", invalid length"); 901 break; 902 case ICMP6_NI_UNKNOWN: 903 printf("unknown"); 904 needcomma++; 905 if (siz != sizeof(*ni6)) 906 if (vflag) 907 printf(", invalid length"); 908 break; 909 } 910 911 if (ni6->ni_code != ICMP6_NI_SUCCESS) { 912 /*(*/ 913 printf(")"); 914 break; 915 } 916 917 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 918 case NI_QTYPE_NOOP: 919 if (needcomma) 920 printf(", "); 921 printf("noop"); 922 if (siz != sizeof(*ni6)) 923 if (vflag) 924 printf(", invalid length"); 925 break; 926 case NI_QTYPE_SUPTYPES: 927 if (needcomma) 928 printf(", "); 929 printf("supported qtypes"); 930 i = EXTRACT_16BITS(&ni6->ni_flags); 931 if (i) 932 printf(" [%s]", (i & 0x01) ? "C" : ""); 933 break; 934 case NI_QTYPE_FQDN: 935 if (needcomma) 936 printf(", "); 937 printf("DNS name"); 938 cp = (const u_char *)(ni6 + 1) + 4; 939 if (cp[0] == ep - cp - 1) { 940 /* icmp-name-lookup-03, pascal string */ 941 if (vflag) 942 printf(", 03 draft"); 943 cp++; 944 printf(", \""); 945 while (cp < ep) { 946 safeputchar(*cp); 947 cp++; 948 } 949 printf("\""); 950 } else 951 dnsname_print(cp, ep); 952 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 953 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 954 break; 955 case NI_QTYPE_NODEADDR: 956 if (needcomma) 957 printf(", "); 958 printf("node addresses"); 959 i = sizeof(*ni6); 960 while (i < siz) { 961 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 962 break; 963 printf(" %s", getname6(bp + i)); 964 i += sizeof(struct in6_addr); 965 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 966 i += sizeof(int32_t); 967 } 968 i = ni6->ni_flags; 969 if (!i) 970 break; 971 printf(" [%s%s%s%s%s%s%s]", 972 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 973 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 974 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 975 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 976 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 977 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 978 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 979 break; 980 default: 981 if (needcomma) 982 printf(", "); 983 printf("unknown"); 984 break; 985 } 986 987 /*(*/ 988 printf(")"); 989 break; 990 } 991 return; 992 993 trunc: 994 fputs("[|icmp6]", stdout); 995 } 996 997 static void 998 icmp6_rrenum_print(const u_char *bp, const u_char *ep) 999 { 1000 struct icmp6_router_renum *rr6; 1001 struct icmp6_hdr *dp; 1002 size_t siz; 1003 const char *cp; 1004 struct rr_pco_match *match; 1005 struct rr_pco_use *use; 1006 char hbuf[NI_MAXHOST]; 1007 int n; 1008 1009 if (ep < bp) 1010 return; 1011 dp = (struct icmp6_hdr *)bp; 1012 rr6 = (struct icmp6_router_renum *)bp; 1013 siz = ep - bp; 1014 cp = (const char *)(rr6 + 1); 1015 1016 TCHECK(rr6->rr_reserved); 1017 switch (rr6->rr_code) { 1018 case ICMP6_ROUTER_RENUMBERING_COMMAND: 1019 printf("router renum: command"); 1020 break; 1021 case ICMP6_ROUTER_RENUMBERING_RESULT: 1022 printf("router renum: result"); 1023 break; 1024 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 1025 printf("router renum: sequence number reset"); 1026 break; 1027 default: 1028 printf("router renum: code-#%d", rr6->rr_code); 1029 break; 1030 } 1031 1032 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 1033 1034 if (vflag) { 1035 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 1036 printf("["); /*]*/ 1037 if (rr6->rr_flags) { 1038 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 1039 F(ICMP6_RR_FLAGS_REQRESULT, "R"), 1040 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 1041 F(ICMP6_RR_FLAGS_SPECSITE, "S"), 1042 F(ICMP6_RR_FLAGS_PREVDONE, "P")); 1043 } 1044 printf("seg=%u,", rr6->rr_segnum); 1045 printf("maxdelay=%u", rr6->rr_maxdelay); 1046 if (rr6->rr_reserved) 1047 printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved)); 1048 /*[*/ 1049 printf("]"); 1050 #undef F 1051 } 1052 1053 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 1054 match = (struct rr_pco_match *)cp; 1055 cp = (const char *)(match + 1); 1056 1057 TCHECK(match->rpm_prefix); 1058 1059 if (vflag > 1) 1060 printf("\n\t"); 1061 else 1062 printf(" "); 1063 printf("match("); /*)*/ 1064 switch (match->rpm_code) { 1065 case RPM_PCO_ADD: printf("add"); break; 1066 case RPM_PCO_CHANGE: printf("change"); break; 1067 case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 1068 default: printf("#%u", match->rpm_code); break; 1069 } 1070 1071 if (vflag) { 1072 printf(",ord=%u", match->rpm_ordinal); 1073 printf(",min=%u", match->rpm_minlen); 1074 printf(",max=%u", match->rpm_maxlen); 1075 } 1076 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 1077 printf(",%s/%u", hbuf, match->rpm_matchlen); 1078 else 1079 printf(",?/%u", match->rpm_matchlen); 1080 /*(*/ 1081 printf(")"); 1082 1083 n = match->rpm_len - 3; 1084 if (n % 4) 1085 goto trunc; 1086 n /= 4; 1087 while (n-- > 0) { 1088 use = (struct rr_pco_use *)cp; 1089 cp = (const char *)(use + 1); 1090 1091 TCHECK(use->rpu_prefix); 1092 1093 if (vflag > 1) 1094 printf("\n\t"); 1095 else 1096 printf(" "); 1097 printf("use("); /*)*/ 1098 if (use->rpu_flags) { 1099 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 1100 printf("%s%s,", 1101 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 1102 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 1103 #undef F 1104 } 1105 if (vflag) { 1106 printf("mask=0x%x,", use->rpu_ramask); 1107 printf("raflags=0x%x,", use->rpu_raflags); 1108 if (~use->rpu_vltime == 0) 1109 printf("vltime=infty,"); 1110 else 1111 printf("vltime=%u,", 1112 EXTRACT_32BITS(&use->rpu_vltime)); 1113 if (~use->rpu_pltime == 0) 1114 printf("pltime=infty,"); 1115 else 1116 printf("pltime=%u,", 1117 EXTRACT_32BITS(&use->rpu_pltime)); 1118 } 1119 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 1120 sizeof(hbuf))) 1121 printf("%s/%u/%u", hbuf, use->rpu_uselen, 1122 use->rpu_keeplen); 1123 else 1124 printf("?/%u/%u", use->rpu_uselen, 1125 use->rpu_keeplen); 1126 /*(*/ 1127 printf(")"); 1128 } 1129 } 1130 1131 return; 1132 1133 trunc: 1134 fputs("[|icmp6]", stdout); 1135 } 1136 1137 #endif /* INET6 */ 1138