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