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 #include <sys/cdefs.h> 23 #ifndef lint 24 #if 0 25 static const char rcsid[] _U_ = 26 "@(#) Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 guy Exp"; 27 #else 28 __RCSID("$NetBSD: print-icmp6.c,v 1.3 2011/12/27 15:12:45 christos Exp $"); 29 #endif 30 #endif 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #ifdef INET6 37 38 #include <tcpdump-stdinc.h> 39 40 #include <stdio.h> 41 #include <string.h> 42 43 #include "interface.h" 44 #include "addrtoname.h" 45 #include "extract.h" 46 47 #include "ip6.h" 48 #include "icmp6.h" 49 #include "ipproto.h" 50 51 #include "udp.h" 52 #include "ah.h" 53 54 static const char *get_rtpref(u_int); 55 static const char *get_lifetime(u_int32_t); 56 static void print_lladdr(const u_char *, size_t); 57 static void icmp6_opt_print(const u_char *, int); 58 static void mld6_print(const u_char *); 59 static void mldv2_report_print(const u_char *, u_int); 60 static void mldv2_query_print(const u_char *, u_int); 61 static struct udphdr *get_upperlayer(u_char *, u_int *); 62 static void dnsname_print(const u_char *, const u_char *); 63 static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); 64 static void icmp6_rrenum_print(const u_char *, const u_char *); 65 66 #ifndef abs 67 #define abs(a) ((0 < (a)) ? (a) : -(a)) 68 #endif 69 70 /* inline the various RPL definitions */ 71 #define ND_RPL_MESSAGE 0x9B 72 73 static struct tok icmp6_type_values[] = { 74 { ICMP6_DST_UNREACH, "destination unreachable"}, 75 { ICMP6_PACKET_TOO_BIG, "packet too big"}, 76 { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, 77 { ICMP6_PARAM_PROB, "parameter problem"}, 78 { ICMP6_ECHO_REQUEST, "echo request"}, 79 { ICMP6_ECHO_REPLY, "echo reply"}, 80 { MLD6_LISTENER_QUERY, "multicast listener query"}, 81 { MLD6_LISTENER_REPORT, "multicast listener report"}, 82 { MLD6_LISTENER_DONE, "multicast listener done"}, 83 { ND_ROUTER_SOLICIT, "router solicitation"}, 84 { ND_ROUTER_ADVERT, "router advertisement"}, 85 { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 86 { ND_NEIGHBOR_ADVERT, "neighbor advertisement"}, 87 { ND_REDIRECT, "redirect"}, 88 { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 89 { IND_SOLICIT, "inverse neighbor solicitation"}, 90 { IND_ADVERT, "inverse neighbor advertisement"}, 91 { MLDV2_LISTENER_REPORT, "multicast listener report v2"}, 92 { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, 93 { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, 94 { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, 95 { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, 96 { ICMP6_WRUREQUEST, "who-are-you request"}, 97 { ICMP6_WRUREPLY, "who-are-you reply"}, 98 { ICMP6_NI_QUERY, "node information query"}, 99 { ICMP6_NI_REPLY, "node information reply"}, 100 { MLD6_MTRACE, "mtrace message"}, 101 { MLD6_MTRACE_RESP, "mtrace response"}, 102 { ND_RPL_MESSAGE, "RPL"}, 103 { 0, NULL } 104 }; 105 106 static struct tok icmp6_dst_unreach_code_values[] = { 107 { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, 108 { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, 109 { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, 110 { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, 111 { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, 112 { 0, NULL } 113 }; 114 115 static struct tok icmp6_opt_pi_flag_values[] = { 116 { ND_OPT_PI_FLAG_ONLINK, "onlink" }, 117 { ND_OPT_PI_FLAG_AUTO, "auto" }, 118 { ND_OPT_PI_FLAG_ROUTER, "router" }, 119 { 0, NULL } 120 }; 121 122 static struct tok icmp6_opt_ra_flag_values[] = { 123 { ND_RA_FLAG_MANAGED, "managed" }, 124 { ND_RA_FLAG_OTHER, "other stateful"}, 125 { ND_RA_FLAG_HOME_AGENT, "home agent"}, 126 { 0, NULL } 127 }; 128 129 static struct tok icmp6_nd_na_flag_values[] = { 130 { ND_NA_FLAG_ROUTER, "router" }, 131 { ND_NA_FLAG_SOLICITED, "solicited" }, 132 { ND_NA_FLAG_OVERRIDE, "override" }, 133 { 0, NULL } 134 }; 135 136 137 static struct tok icmp6_opt_values[] = { 138 { ND_OPT_SOURCE_LINKADDR, "source link-address"}, 139 { ND_OPT_TARGET_LINKADDR, "destination link-address"}, 140 { ND_OPT_PREFIX_INFORMATION, "prefix info"}, 141 { ND_OPT_REDIRECTED_HEADER, "redirected header"}, 142 { ND_OPT_MTU, "mtu"}, 143 { ND_OPT_RDNSS, "rdnss"}, 144 { ND_OPT_ADVINTERVAL, "advertisement interval"}, 145 { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 146 { ND_OPT_ROUTE_INFO, "route info"}, 147 { 0, NULL } 148 }; 149 150 /* mldv2 report types */ 151 static struct tok mldv2report2str[] = { 152 { 1, "is_in" }, 153 { 2, "is_ex" }, 154 { 3, "to_in" }, 155 { 4, "to_ex" }, 156 { 5, "allow" }, 157 { 6, "block" }, 158 { 0, NULL } 159 }; 160 161 static const char * 162 get_rtpref(u_int v) 163 { 164 static const char *rtpref_str[] = { 165 "medium", /* 00 */ 166 "high", /* 01 */ 167 "rsv", /* 10 */ 168 "low" /* 11 */ 169 }; 170 171 return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 172 } 173 174 static const char * 175 get_lifetime(u_int32_t v) 176 { 177 static char buf[20]; 178 179 if (v == (u_int32_t)~0UL) 180 return "infinity"; 181 else { 182 snprintf(buf, sizeof(buf), "%u", v); 183 return buf; 184 } 185 } 186 187 static void 188 print_lladdr(const u_int8_t *p, size_t l) 189 { 190 const u_int8_t *ep, *q; 191 192 q = p; 193 ep = p + l; 194 while (l > 0 && q < ep) { 195 if (q > p) 196 printf(":"); 197 printf("%02x", *q++); 198 l--; 199 } 200 } 201 202 static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, 203 u_int len) 204 { 205 size_t i; 206 register const u_int16_t *sp; 207 u_int32_t sum; 208 union { 209 struct { 210 struct in6_addr ph_src; 211 struct in6_addr ph_dst; 212 u_int32_t ph_len; 213 u_int8_t ph_zero[3]; 214 u_int8_t ph_nxt; 215 } ph; 216 u_int16_t pa[20]; 217 } phu; 218 219 /* pseudo-header */ 220 memset(&phu, 0, sizeof(phu)); 221 phu.ph.ph_src = ip6->ip6_src; 222 phu.ph.ph_dst = ip6->ip6_dst; 223 phu.ph.ph_len = htonl(len); 224 phu.ph.ph_nxt = IPPROTO_ICMPV6; 225 226 sum = 0; 227 for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 228 sum += phu.pa[i]; 229 230 sp = (const u_int16_t *)icp; 231 232 for (i = 0; i < (len & ~1); i += 2) 233 sum += *sp++; 234 235 if (len & 1) 236 sum += htons((*(const u_int8_t *)sp) << 8); 237 238 while (sum > 0xffff) 239 sum = (sum & 0xffff) + (sum >> 16); 240 sum = ~sum & 0xffff; 241 242 return (sum); 243 } 244 245 enum ND_RPL_CODE { 246 ND_RPL_DAG_IS=0x01, 247 ND_RPL_DAG_IO=0x02, 248 ND_RPL_DAO =0x04 249 }; 250 251 enum ND_RPL_DIO_FLAGS { 252 ND_RPL_DIO_GROUNDED = 0x80, 253 ND_RPL_DIO_DATRIG = 0x40, 254 ND_RPL_DIO_DASUPPORT= 0x20, 255 ND_RPL_DIO_RES4 = 0x10, 256 ND_RPL_DIO_RES3 = 0x08, 257 ND_RPL_DIO_PRF_MASK = 0x07, /* 3-bit preference */ 258 }; 259 260 struct nd_rpl_dio { 261 u_int8_t rpl_flags; 262 u_int8_t rpl_seq; 263 u_int8_t rpl_instanceid; 264 u_int8_t rpl_dagrank; 265 u_int8_t rpl_dagid[16]; 266 }; 267 268 static void 269 rpl_print(netdissect_options *ndo, 270 const struct icmp6_hdr *hdr, 271 const u_char *bp, u_int length _U_) 272 { 273 struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp; 274 275 ND_TCHECK(dio->rpl_dagid); 276 277 switch(hdr->icmp6_code) { 278 case ND_RPL_DAG_IS: 279 ND_PRINT((ndo, ", DAG Information Solicitation")); 280 if(ndo->ndo_vflag) { 281 } 282 break; 283 case ND_RPL_DAG_IO: 284 ND_PRINT((ndo, ", DAG Information Object")); 285 if(ndo->ndo_vflag) { 286 char dagid[65]; 287 char *d = dagid; 288 int i; 289 for(i=0;i<16;i++) { 290 if(isprint(dio->rpl_dagid[i])) { 291 *d++ = dio->rpl_dagid[i]; 292 } else { 293 int cnt=snprintf(d,4,"0x%02x", 294 dio->rpl_dagid[i]); 295 d += cnt; 296 } 297 } 298 *d++ = '\0'; 299 ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]", 300 dio->rpl_seq, 301 dio->rpl_instanceid, 302 dio->rpl_dagrank, 303 dagid)); 304 } 305 break; 306 case ND_RPL_DAO: 307 ND_PRINT((ndo, ", Destination Advertisement Object")); 308 if(ndo->ndo_vflag) { 309 } 310 break; 311 default: 312 ND_PRINT((ndo, ", RPL message, unknown code %u",hdr->icmp6_code)); 313 break; 314 } 315 return; 316 trunc: 317 ND_PRINT((ndo," [|truncated]")); 318 return; 319 320 } 321 322 323 void 324 icmp6_print(netdissect_options *ndo, 325 const u_char *bp, u_int length, const u_char *bp2, int fragmented) 326 { 327 const struct icmp6_hdr *dp; 328 const struct ip6_hdr *ip; 329 const struct ip6_hdr *oip; 330 const struct udphdr *ouh; 331 int dport; 332 const u_char *ep; 333 u_int prot; 334 335 dp = (struct icmp6_hdr *)bp; 336 ip = (struct ip6_hdr *)bp2; 337 oip = (struct ip6_hdr *)(dp + 1); 338 /* 'ep' points to the end of available data. */ 339 ep = snapend; 340 341 TCHECK(dp->icmp6_cksum); 342 343 if (vflag && !fragmented) { 344 int sum = dp->icmp6_cksum; 345 346 if (TTEST2(bp[0], length)) { 347 sum = icmp6_cksum(ip, dp, length); 348 if (sum != 0) 349 (void)printf("[bad icmp6 cksum %x!] ", sum); 350 else 351 (void)printf("[icmp6 sum ok] "); 352 } 353 } 354 355 printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 356 357 /* display cosmetics: print the packet length for printer that use the vflag now */ 358 if (vflag) 359 switch (dp->icmp6_type) { 360 case ND_ROUTER_SOLICIT: 361 case ND_ROUTER_ADVERT: 362 case ND_NEIGHBOR_ADVERT: 363 case ND_NEIGHBOR_SOLICIT: 364 case ND_REDIRECT: 365 case ICMP6_HADISCOV_REPLY: 366 case ICMP6_MOBILEPREFIX_ADVERT: 367 printf(", length %u", length); 368 break; 369 default: 370 break; 371 } 372 373 switch (dp->icmp6_type) { 374 case ICMP6_DST_UNREACH: 375 TCHECK(oip->ip6_dst); 376 printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 377 switch (dp->icmp6_code) { 378 379 case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 380 case ICMP6_DST_UNREACH_ADMIN: 381 case ICMP6_DST_UNREACH_ADDR: 382 printf(" %s",ip6addr_string(&oip->ip6_dst)); 383 break; 384 case ICMP6_DST_UNREACH_BEYONDSCOPE: 385 printf(" %s, source address %s", 386 ip6addr_string(&oip->ip6_dst), 387 ip6addr_string(&oip->ip6_src)); 388 break; 389 case ICMP6_DST_UNREACH_NOPORT: 390 if ((ouh = get_upperlayer((u_char *)oip, &prot)) 391 == NULL) 392 goto trunc; 393 394 dport = EXTRACT_16BITS(&ouh->uh_dport); 395 switch (prot) { 396 case IPPROTO_TCP: 397 printf(", %s tcp port %s", 398 ip6addr_string(&oip->ip6_dst), 399 tcpport_string(dport)); 400 break; 401 case IPPROTO_UDP: 402 printf(", %s udp port %s", 403 ip6addr_string(&oip->ip6_dst), 404 udpport_string(dport)); 405 break; 406 default: 407 printf(", %s protocol %d port %d unreachable", 408 ip6addr_string(&oip->ip6_dst), 409 oip->ip6_nxt, dport); 410 break; 411 } 412 break; 413 default: 414 if (vflag <= 1) { 415 print_unknown_data(bp,"\n\t",length); 416 return; 417 } 418 break; 419 } 420 break; 421 case ICMP6_PACKET_TOO_BIG: 422 TCHECK(dp->icmp6_mtu); 423 printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 424 break; 425 case ICMP6_TIME_EXCEEDED: 426 TCHECK(oip->ip6_dst); 427 switch (dp->icmp6_code) { 428 case ICMP6_TIME_EXCEED_TRANSIT: 429 printf(" for %s", 430 ip6addr_string(&oip->ip6_dst)); 431 break; 432 case ICMP6_TIME_EXCEED_REASSEMBLY: 433 printf(" (reassembly)"); 434 break; 435 default: 436 printf(", unknown code (%u)", dp->icmp6_code); 437 break; 438 } 439 break; 440 case ICMP6_PARAM_PROB: 441 TCHECK(oip->ip6_dst); 442 switch (dp->icmp6_code) { 443 case ICMP6_PARAMPROB_HEADER: 444 printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 445 break; 446 case ICMP6_PARAMPROB_NEXTHEADER: 447 printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 448 break; 449 case ICMP6_PARAMPROB_OPTION: 450 printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 451 break; 452 default: 453 printf(", code-#%d", 454 dp->icmp6_code); 455 break; 456 } 457 break; 458 case ICMP6_ECHO_REQUEST: 459 case ICMP6_ECHO_REPLY: 460 TCHECK(dp->icmp6_seq); 461 printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 462 break; 463 case ICMP6_MEMBERSHIP_QUERY: 464 if (length == MLD_MINLEN) { 465 mld6_print((const u_char *)dp); 466 } else if (length >= MLDV2_MINLEN) { 467 printf("v2 "); 468 mldv2_query_print((const u_char *)dp, length); 469 } else { 470 printf(" unknown-version (len %u) ", length); 471 } 472 break; 473 case ICMP6_MEMBERSHIP_REPORT: 474 mld6_print((const u_char *)dp); 475 break; 476 case ICMP6_MEMBERSHIP_REDUCTION: 477 mld6_print((const u_char *)dp); 478 break; 479 case ND_ROUTER_SOLICIT: 480 #define RTSOLLEN 8 481 if (vflag) { 482 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 483 length - RTSOLLEN); 484 } 485 break; 486 case ND_ROUTER_ADVERT: 487 #define RTADVLEN 16 488 if (vflag) { 489 struct nd_router_advert *p; 490 491 p = (struct nd_router_advert *)dp; 492 TCHECK(p->nd_ra_retransmit); 493 printf("\n\thop limit %u, Flags [%s]" \ 494 ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 495 (u_int)p->nd_ra_curhoplimit, 496 bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 497 get_rtpref(p->nd_ra_flags_reserved), 498 EXTRACT_16BITS(&p->nd_ra_router_lifetime), 499 EXTRACT_32BITS(&p->nd_ra_reachable), 500 EXTRACT_32BITS(&p->nd_ra_retransmit)); 501 502 icmp6_opt_print((const u_char *)dp + RTADVLEN, 503 length - RTADVLEN); 504 } 505 break; 506 case ND_NEIGHBOR_SOLICIT: 507 { 508 struct nd_neighbor_solicit *p; 509 p = (struct nd_neighbor_solicit *)dp; 510 TCHECK(p->nd_ns_target); 511 printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 512 if (vflag) { 513 #define NDSOLLEN 24 514 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 515 length - NDSOLLEN); 516 } 517 } 518 break; 519 case ND_NEIGHBOR_ADVERT: 520 { 521 struct nd_neighbor_advert *p; 522 523 p = (struct nd_neighbor_advert *)dp; 524 TCHECK(p->nd_na_target); 525 printf(", tgt is %s", 526 ip6addr_string(&p->nd_na_target)); 527 if (vflag) { 528 printf(", Flags [%s]", 529 bittok2str(icmp6_nd_na_flag_values, 530 "none", 531 EXTRACT_32BITS(&p->nd_na_flags_reserved))); 532 #define NDADVLEN 24 533 icmp6_opt_print((const u_char *)dp + NDADVLEN, 534 length - NDADVLEN); 535 #undef NDADVLEN 536 } 537 } 538 break; 539 case ND_REDIRECT: 540 #define RDR(i) ((struct nd_redirect *)(i)) 541 TCHECK(RDR(dp)->nd_rd_dst); 542 printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 543 TCHECK(RDR(dp)->nd_rd_target); 544 printf(" to %s", 545 getname6((const u_char*)&RDR(dp)->nd_rd_target)); 546 #define REDIRECTLEN 40 547 if (vflag) { 548 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 549 length - REDIRECTLEN); 550 } 551 break; 552 #undef REDIRECTLEN 553 #undef RDR 554 case ICMP6_ROUTER_RENUMBERING: 555 icmp6_rrenum_print(bp, ep); 556 break; 557 case ICMP6_NI_QUERY: 558 case ICMP6_NI_REPLY: 559 icmp6_nodeinfo_print(length, bp, ep); 560 break; 561 case IND_SOLICIT: 562 case IND_ADVERT: 563 break; 564 case ICMP6_V2_MEMBERSHIP_REPORT: 565 mldv2_report_print((const u_char *) dp, length); 566 break; 567 case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 568 case ICMP6_HADISCOV_REQUEST: 569 TCHECK(dp->icmp6_data16[0]); 570 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 571 break; 572 case ICMP6_HADISCOV_REPLY: 573 if (vflag) { 574 struct in6_addr *in6; 575 u_char *cp; 576 577 TCHECK(dp->icmp6_data16[0]); 578 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 579 cp = (u_char *)dp + length; 580 in6 = (struct in6_addr *)(dp + 1); 581 for (; (u_char *)in6 < cp; in6++) { 582 TCHECK(*in6); 583 printf(", %s", ip6addr_string(in6)); 584 } 585 } 586 break; 587 case ICMP6_MOBILEPREFIX_ADVERT: 588 if (vflag) { 589 TCHECK(dp->icmp6_data16[0]); 590 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 591 if (dp->icmp6_data16[1] & 0xc0) 592 printf(" "); 593 if (dp->icmp6_data16[1] & 0x80) 594 printf("M"); 595 if (dp->icmp6_data16[1] & 0x40) 596 printf("O"); 597 #define MPADVLEN 8 598 icmp6_opt_print((const u_char *)dp + MPADVLEN, 599 length - MPADVLEN); 600 } 601 break; 602 case ND_RPL_MESSAGE: 603 rpl_print(ndo, dp, &dp->icmp6_data8[0], length); 604 break; 605 default: 606 printf(", length %u", length); 607 if (vflag <= 1) 608 print_unknown_data(bp,"\n\t", length); 609 return; 610 } 611 if (!vflag) 612 printf(", length %u", length); 613 return; 614 trunc: 615 fputs("[|icmp6]", stdout); 616 } 617 618 static struct udphdr * 619 get_upperlayer(u_char *bp, u_int *prot) 620 { 621 const u_char *ep; 622 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 623 struct udphdr *uh; 624 struct ip6_hbh *hbh; 625 struct ip6_frag *fragh; 626 struct ah *ah; 627 u_int nh; 628 int hlen; 629 630 /* 'ep' points to the end of available data. */ 631 ep = snapend; 632 633 if (!TTEST(ip6->ip6_nxt)) 634 return NULL; 635 636 nh = ip6->ip6_nxt; 637 hlen = sizeof(struct ip6_hdr); 638 639 while (bp < ep) { 640 bp += hlen; 641 642 switch(nh) { 643 case IPPROTO_UDP: 644 case IPPROTO_TCP: 645 uh = (struct udphdr *)bp; 646 if (TTEST(uh->uh_dport)) { 647 *prot = nh; 648 return(uh); 649 } 650 else 651 return(NULL); 652 /* NOTREACHED */ 653 654 case IPPROTO_HOPOPTS: 655 case IPPROTO_DSTOPTS: 656 case IPPROTO_ROUTING: 657 hbh = (struct ip6_hbh *)bp; 658 if (!TTEST(hbh->ip6h_len)) 659 return(NULL); 660 nh = hbh->ip6h_nxt; 661 hlen = (hbh->ip6h_len + 1) << 3; 662 break; 663 664 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 665 fragh = (struct ip6_frag *)bp; 666 if (!TTEST(fragh->ip6f_offlg)) 667 return(NULL); 668 /* fragments with non-zero offset are meaningless */ 669 if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 670 return(NULL); 671 nh = fragh->ip6f_nxt; 672 hlen = sizeof(struct ip6_frag); 673 break; 674 675 case IPPROTO_AH: 676 ah = (struct ah *)bp; 677 if (!TTEST(ah->ah_len)) 678 return(NULL); 679 nh = ah->ah_nxt; 680 hlen = (ah->ah_len + 2) << 2; 681 break; 682 683 default: /* unknown or undecodable header */ 684 *prot = nh; /* meaningless, but set here anyway */ 685 return(NULL); 686 } 687 } 688 689 return(NULL); /* should be notreached, though */ 690 } 691 692 static void 693 icmp6_opt_print(const u_char *bp, int resid) 694 { 695 const struct nd_opt_hdr *op; 696 const struct nd_opt_hdr *opl; /* why there's no struct? */ 697 const struct nd_opt_prefix_info *opp; 698 const struct icmp6_opts_redirect *opr; 699 const struct nd_opt_mtu *opm; 700 const struct nd_opt_rdnss *oprd; 701 const struct nd_opt_advinterval *opa; 702 const struct nd_opt_homeagent_info *oph; 703 const struct nd_opt_route_info *opri; 704 const u_char *cp, *ep; 705 struct in6_addr in6, *in6p; 706 size_t l; 707 u_int i; 708 709 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 710 711 cp = bp; 712 /* 'ep' points to the end of available data. */ 713 ep = snapend; 714 715 while (cp < ep) { 716 op = (struct nd_opt_hdr *)cp; 717 718 ECHECK(op->nd_opt_len); 719 if (resid <= 0) 720 return; 721 if (op->nd_opt_len == 0) 722 goto trunc; 723 if (cp + (op->nd_opt_len << 3) > ep) 724 goto trunc; 725 726 printf("\n\t %s option (%u), length %u (%u): ", 727 tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 728 op->nd_opt_type, 729 op->nd_opt_len << 3, 730 op->nd_opt_len); 731 732 switch (op->nd_opt_type) { 733 case ND_OPT_SOURCE_LINKADDR: 734 opl = (struct nd_opt_hdr *)op; 735 l = (op->nd_opt_len << 3) - 2; 736 print_lladdr(cp + 2, l); 737 break; 738 case ND_OPT_TARGET_LINKADDR: 739 opl = (struct nd_opt_hdr *)op; 740 l = (op->nd_opt_len << 3) - 2; 741 print_lladdr(cp + 2, l); 742 break; 743 case ND_OPT_PREFIX_INFORMATION: 744 opp = (struct nd_opt_prefix_info *)op; 745 TCHECK(opp->nd_opt_pi_prefix); 746 printf("%s/%u%s, Flags [%s], valid time %ss", 747 ip6addr_string(&opp->nd_opt_pi_prefix), 748 opp->nd_opt_pi_prefix_len, 749 (op->nd_opt_len != 4) ? "badlen" : "", 750 bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 751 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 752 printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 753 break; 754 case ND_OPT_REDIRECTED_HEADER: 755 opr = (struct icmp6_opts_redirect *)op; 756 print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 757 /* xxx */ 758 break; 759 case ND_OPT_MTU: 760 opm = (struct nd_opt_mtu *)op; 761 TCHECK(opm->nd_opt_mtu_mtu); 762 printf(" %u%s", 763 EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 764 (op->nd_opt_len != 1) ? "bad option length" : "" ); 765 break; 766 case ND_OPT_RDNSS: 767 oprd = (struct nd_opt_rdnss *)op; 768 l = (op->nd_opt_len - 1) / 2; 769 printf(" lifetime %us,", 770 EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)); 771 for (i = 0; i < l; i++) { 772 TCHECK(oprd->nd_opt_rdnss_addr[i]); 773 printf(" addr: %s", 774 ip6addr_string(&oprd->nd_opt_rdnss_addr[i])); 775 } 776 break; 777 case ND_OPT_ADVINTERVAL: 778 opa = (struct nd_opt_advinterval *)op; 779 TCHECK(opa->nd_opt_adv_interval); 780 printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 781 break; 782 case ND_OPT_HOMEAGENT_INFO: 783 oph = (struct nd_opt_homeagent_info *)op; 784 TCHECK(oph->nd_opt_hai_lifetime); 785 printf(" preference %u, lifetime %u", 786 EXTRACT_16BITS(&oph->nd_opt_hai_preference), 787 EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 788 break; 789 case ND_OPT_ROUTE_INFO: 790 opri = (struct nd_opt_route_info *)op; 791 TCHECK(opri->nd_opt_rti_lifetime); 792 memset(&in6, 0, sizeof(in6)); 793 in6p = (struct in6_addr *)(opri + 1); 794 switch (op->nd_opt_len) { 795 case 1: 796 break; 797 case 2: 798 TCHECK2(*in6p, 8); 799 memcpy(&in6, opri + 1, 8); 800 break; 801 case 3: 802 TCHECK(*in6p); 803 memcpy(&in6, opri + 1, sizeof(in6)); 804 break; 805 default: 806 goto trunc; 807 } 808 printf(" %s/%u", ip6addr_string(&in6), 809 opri->nd_opt_rti_prefixlen); 810 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 811 printf(", lifetime=%s", 812 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 813 break; 814 default: 815 if (vflag <= 1) { 816 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 817 return; 818 } 819 break; 820 } 821 /* do we want to see an additional hexdump ? */ 822 if (vflag> 1) 823 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 824 825 cp += op->nd_opt_len << 3; 826 resid -= op->nd_opt_len << 3; 827 } 828 return; 829 830 trunc: 831 fputs("[ndp opt]", stdout); 832 return; 833 #undef ECHECK 834 } 835 836 static void 837 mld6_print(const u_char *bp) 838 { 839 struct mld6_hdr *mp = (struct mld6_hdr *)bp; 840 const u_char *ep; 841 842 /* 'ep' points to the end of available data. */ 843 ep = snapend; 844 845 if ((u_char *)mp + sizeof(*mp) > ep) 846 return; 847 848 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 849 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 850 } 851 852 static void 853 mldv2_report_print(const u_char *bp, u_int len) 854 { 855 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 856 u_int group, nsrcs, ngroups; 857 u_int i, j; 858 859 /* Minimum len is 8 */ 860 if (len < 8) { 861 printf(" [invalid len %d]", len); 862 return; 863 } 864 865 TCHECK(icp->icmp6_data16[1]); 866 ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]); 867 printf(", %d group record(s)", ngroups); 868 if (vflag > 0) { 869 /* Print the group records */ 870 group = 8; 871 for (i = 0; i < ngroups; i++) { 872 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 873 if (len < group + 20) { 874 printf(" [invalid number of groups]"); 875 return; 876 } 877 TCHECK2(bp[group + 4], sizeof(struct in6_addr)); 878 printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 879 printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 880 bp[group])); 881 nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 882 /* Check the number of sources and print them */ 883 if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) { 884 printf(" [invalid number of sources %d]", nsrcs); 885 return; 886 } 887 if (vflag == 1) 888 printf(", %d source(s)", nsrcs); 889 else { 890 /* Print the sources */ 891 (void)printf(" {"); 892 for (j = 0; j < nsrcs; j++) { 893 TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)], 894 sizeof(struct in6_addr)); 895 printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); 896 } 897 (void)printf(" }"); 898 } 899 /* Next group record */ 900 group += 20 + nsrcs * sizeof(struct in6_addr); 901 printf("]"); 902 } 903 } 904 return; 905 trunc: 906 (void)printf("[|icmp6]"); 907 return; 908 } 909 910 static void 911 mldv2_query_print(const u_char *bp, u_int len) 912 { 913 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 914 u_int mrc; 915 int mrt, qqi; 916 u_int nsrcs; 917 register u_int i; 918 919 /* Minimum len is 28 */ 920 if (len < 28) { 921 printf(" [invalid len %d]", len); 922 return; 923 } 924 TCHECK(icp->icmp6_data16[0]); 925 mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]); 926 if (mrc < 32768) { 927 mrt = mrc; 928 } else { 929 mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 930 } 931 if (vflag) { 932 (void)printf(" [max resp delay=%d]", mrt); 933 } 934 TCHECK2(bp[8], sizeof(struct in6_addr)); 935 printf(" [gaddr %s", ip6addr_string(&bp[8])); 936 937 if (vflag) { 938 TCHECK(bp[25]); 939 if (bp[24] & 0x08) { 940 printf(" sflag"); 941 } 942 if (bp[24] & 0x07) { 943 printf(" robustness=%d", bp[24] & 0x07); 944 } 945 if (bp[25] < 128) { 946 qqi = bp[25]; 947 } else { 948 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 949 } 950 printf(" qqi=%d", qqi); 951 } 952 953 TCHECK2(bp[26], 2); 954 nsrcs = EXTRACT_16BITS(&bp[26]); 955 if (nsrcs > 0) { 956 if (len < 28 + nsrcs * sizeof(struct in6_addr)) 957 printf(" [invalid number of sources]"); 958 else if (vflag > 1) { 959 printf(" {"); 960 for (i = 0; i < nsrcs; i++) { 961 TCHECK2(bp[28 + i * sizeof(struct in6_addr)], 962 sizeof(struct in6_addr)); 963 printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); 964 } 965 printf(" }"); 966 } else 967 printf(", %d source(s)", nsrcs); 968 } 969 printf("]"); 970 return; 971 trunc: 972 (void)printf("[|icmp6]"); 973 return; 974 } 975 976 static void 977 dnsname_print(const u_char *cp, const u_char *ep) 978 { 979 int i; 980 981 /* DNS name decoding - no decompression */ 982 printf(", \""); 983 while (cp < ep) { 984 i = *cp++; 985 if (i) { 986 if (i > ep - cp) { 987 printf("???"); 988 break; 989 } 990 while (i-- && cp < ep) { 991 safeputchar(*cp); 992 cp++; 993 } 994 if (cp + 1 < ep && *cp) 995 printf("."); 996 } else { 997 if (cp == ep) { 998 /* FQDN */ 999 printf("."); 1000 } else if (cp + 1 == ep && *cp == '\0') { 1001 /* truncated */ 1002 } else { 1003 /* invalid */ 1004 printf("???"); 1005 } 1006 break; 1007 } 1008 } 1009 printf("\""); 1010 } 1011 1012 static void 1013 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 1014 { 1015 struct icmp6_nodeinfo *ni6; 1016 struct icmp6_hdr *dp; 1017 const u_char *cp; 1018 size_t siz, i; 1019 int needcomma; 1020 1021 if (ep < bp) 1022 return; 1023 dp = (struct icmp6_hdr *)bp; 1024 ni6 = (struct icmp6_nodeinfo *)bp; 1025 siz = ep - bp; 1026 1027 switch (ni6->ni_type) { 1028 case ICMP6_NI_QUERY: 1029 if (siz == sizeof(*dp) + 4) { 1030 /* KAME who-are-you */ 1031 printf(" who-are-you request"); 1032 break; 1033 } 1034 printf(" node information query"); 1035 1036 TCHECK2(*dp, sizeof(*ni6)); 1037 ni6 = (struct icmp6_nodeinfo *)dp; 1038 printf(" ("); /*)*/ 1039 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1040 case NI_QTYPE_NOOP: 1041 printf("noop"); 1042 break; 1043 case NI_QTYPE_SUPTYPES: 1044 printf("supported qtypes"); 1045 i = EXTRACT_16BITS(&ni6->ni_flags); 1046 if (i) 1047 printf(" [%s]", (i & 0x01) ? "C" : ""); 1048 break; 1049 break; 1050 case NI_QTYPE_FQDN: 1051 printf("DNS name"); 1052 break; 1053 case NI_QTYPE_NODEADDR: 1054 printf("node addresses"); 1055 i = ni6->ni_flags; 1056 if (!i) 1057 break; 1058 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 1059 printf(" [%s%s%s%s%s%s]", 1060 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1061 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1062 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1063 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1064 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1065 (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 1066 break; 1067 default: 1068 printf("unknown"); 1069 break; 1070 } 1071 1072 if (ni6->ni_qtype == NI_QTYPE_NOOP || 1073 ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 1074 if (siz != sizeof(*ni6)) 1075 if (vflag) 1076 printf(", invalid len"); 1077 /*(*/ 1078 printf(")"); 1079 break; 1080 } 1081 1082 1083 /* XXX backward compat, icmp-name-lookup-03 */ 1084 if (siz == sizeof(*ni6)) { 1085 printf(", 03 draft"); 1086 /*(*/ 1087 printf(")"); 1088 break; 1089 } 1090 1091 switch (ni6->ni_code) { 1092 case ICMP6_NI_SUBJ_IPV6: 1093 if (!TTEST2(*dp, 1094 sizeof(*ni6) + sizeof(struct in6_addr))) 1095 break; 1096 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 1097 if (vflag) 1098 printf(", invalid subject len"); 1099 break; 1100 } 1101 printf(", subject=%s", 1102 getname6((const u_char *)(ni6 + 1))); 1103 break; 1104 case ICMP6_NI_SUBJ_FQDN: 1105 printf(", subject=DNS name"); 1106 cp = (const u_char *)(ni6 + 1); 1107 if (cp[0] == ep - cp - 1) { 1108 /* icmp-name-lookup-03, pascal string */ 1109 if (vflag) 1110 printf(", 03 draft"); 1111 cp++; 1112 printf(", \""); 1113 while (cp < ep) { 1114 safeputchar(*cp); 1115 cp++; 1116 } 1117 printf("\""); 1118 } else 1119 dnsname_print(cp, ep); 1120 break; 1121 case ICMP6_NI_SUBJ_IPV4: 1122 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 1123 break; 1124 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 1125 if (vflag) 1126 printf(", invalid subject len"); 1127 break; 1128 } 1129 printf(", subject=%s", 1130 getname((const u_char *)(ni6 + 1))); 1131 break; 1132 default: 1133 printf(", unknown subject"); 1134 break; 1135 } 1136 1137 /*(*/ 1138 printf(")"); 1139 break; 1140 1141 case ICMP6_NI_REPLY: 1142 if (icmp6len > siz) { 1143 printf("[|icmp6: node information reply]"); 1144 break; 1145 } 1146 1147 needcomma = 0; 1148 1149 ni6 = (struct icmp6_nodeinfo *)dp; 1150 printf(" node information reply"); 1151 printf(" ("); /*)*/ 1152 switch (ni6->ni_code) { 1153 case ICMP6_NI_SUCCESS: 1154 if (vflag) { 1155 printf("success"); 1156 needcomma++; 1157 } 1158 break; 1159 case ICMP6_NI_REFUSED: 1160 printf("refused"); 1161 needcomma++; 1162 if (siz != sizeof(*ni6)) 1163 if (vflag) 1164 printf(", invalid length"); 1165 break; 1166 case ICMP6_NI_UNKNOWN: 1167 printf("unknown"); 1168 needcomma++; 1169 if (siz != sizeof(*ni6)) 1170 if (vflag) 1171 printf(", invalid length"); 1172 break; 1173 } 1174 1175 if (ni6->ni_code != ICMP6_NI_SUCCESS) { 1176 /*(*/ 1177 printf(")"); 1178 break; 1179 } 1180 1181 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1182 case NI_QTYPE_NOOP: 1183 if (needcomma) 1184 printf(", "); 1185 printf("noop"); 1186 if (siz != sizeof(*ni6)) 1187 if (vflag) 1188 printf(", invalid length"); 1189 break; 1190 case NI_QTYPE_SUPTYPES: 1191 if (needcomma) 1192 printf(", "); 1193 printf("supported qtypes"); 1194 i = EXTRACT_16BITS(&ni6->ni_flags); 1195 if (i) 1196 printf(" [%s]", (i & 0x01) ? "C" : ""); 1197 break; 1198 case NI_QTYPE_FQDN: 1199 if (needcomma) 1200 printf(", "); 1201 printf("DNS name"); 1202 cp = (const u_char *)(ni6 + 1) + 4; 1203 if (cp[0] == ep - cp - 1) { 1204 /* icmp-name-lookup-03, pascal string */ 1205 if (vflag) 1206 printf(", 03 draft"); 1207 cp++; 1208 printf(", \""); 1209 while (cp < ep) { 1210 safeputchar(*cp); 1211 cp++; 1212 } 1213 printf("\""); 1214 } else 1215 dnsname_print(cp, ep); 1216 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 1217 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 1218 break; 1219 case NI_QTYPE_NODEADDR: 1220 if (needcomma) 1221 printf(", "); 1222 printf("node addresses"); 1223 i = sizeof(*ni6); 1224 while (i < siz) { 1225 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 1226 break; 1227 printf(" %s", getname6(bp + i)); 1228 i += sizeof(struct in6_addr); 1229 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 1230 i += sizeof(int32_t); 1231 } 1232 i = ni6->ni_flags; 1233 if (!i) 1234 break; 1235 printf(" [%s%s%s%s%s%s%s]", 1236 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1237 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1238 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1239 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1240 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1241 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 1242 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 1243 break; 1244 default: 1245 if (needcomma) 1246 printf(", "); 1247 printf("unknown"); 1248 break; 1249 } 1250 1251 /*(*/ 1252 printf(")"); 1253 break; 1254 } 1255 return; 1256 1257 trunc: 1258 fputs("[|icmp6]", stdout); 1259 } 1260 1261 static void 1262 icmp6_rrenum_print(const u_char *bp, const u_char *ep) 1263 { 1264 struct icmp6_router_renum *rr6; 1265 const char *cp; 1266 struct rr_pco_match *match; 1267 struct rr_pco_use *use; 1268 char hbuf[NI_MAXHOST]; 1269 int n; 1270 1271 if (ep < bp) 1272 return; 1273 rr6 = (struct icmp6_router_renum *)bp; 1274 cp = (const char *)(rr6 + 1); 1275 1276 TCHECK(rr6->rr_reserved); 1277 switch (rr6->rr_code) { 1278 case ICMP6_ROUTER_RENUMBERING_COMMAND: 1279 printf("router renum: command"); 1280 break; 1281 case ICMP6_ROUTER_RENUMBERING_RESULT: 1282 printf("router renum: result"); 1283 break; 1284 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 1285 printf("router renum: sequence number reset"); 1286 break; 1287 default: 1288 printf("router renum: code-#%d", rr6->rr_code); 1289 break; 1290 } 1291 1292 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 1293 1294 if (vflag) { 1295 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 1296 printf("["); /*]*/ 1297 if (rr6->rr_flags) { 1298 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 1299 F(ICMP6_RR_FLAGS_REQRESULT, "R"), 1300 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 1301 F(ICMP6_RR_FLAGS_SPECSITE, "S"), 1302 F(ICMP6_RR_FLAGS_PREVDONE, "P")); 1303 } 1304 printf("seg=%u,", rr6->rr_segnum); 1305 printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)); 1306 if (rr6->rr_reserved) 1307 printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)); 1308 /*[*/ 1309 printf("]"); 1310 #undef F 1311 } 1312 1313 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 1314 match = (struct rr_pco_match *)cp; 1315 cp = (const char *)(match + 1); 1316 1317 TCHECK(match->rpm_prefix); 1318 1319 if (vflag > 1) 1320 printf("\n\t"); 1321 else 1322 printf(" "); 1323 printf("match("); /*)*/ 1324 switch (match->rpm_code) { 1325 case RPM_PCO_ADD: printf("add"); break; 1326 case RPM_PCO_CHANGE: printf("change"); break; 1327 case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 1328 default: printf("#%u", match->rpm_code); break; 1329 } 1330 1331 if (vflag) { 1332 printf(",ord=%u", match->rpm_ordinal); 1333 printf(",min=%u", match->rpm_minlen); 1334 printf(",max=%u", match->rpm_maxlen); 1335 } 1336 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 1337 printf(",%s/%u", hbuf, match->rpm_matchlen); 1338 else 1339 printf(",?/%u", match->rpm_matchlen); 1340 /*(*/ 1341 printf(")"); 1342 1343 n = match->rpm_len - 3; 1344 if (n % 4) 1345 goto trunc; 1346 n /= 4; 1347 while (n-- > 0) { 1348 use = (struct rr_pco_use *)cp; 1349 cp = (const char *)(use + 1); 1350 1351 TCHECK(use->rpu_prefix); 1352 1353 if (vflag > 1) 1354 printf("\n\t"); 1355 else 1356 printf(" "); 1357 printf("use("); /*)*/ 1358 if (use->rpu_flags) { 1359 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 1360 printf("%s%s,", 1361 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 1362 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 1363 #undef F 1364 } 1365 if (vflag) { 1366 printf("mask=0x%x,", use->rpu_ramask); 1367 printf("raflags=0x%x,", use->rpu_raflags); 1368 if (~use->rpu_vltime == 0) 1369 printf("vltime=infty,"); 1370 else 1371 printf("vltime=%u,", 1372 EXTRACT_32BITS(&use->rpu_vltime)); 1373 if (~use->rpu_pltime == 0) 1374 printf("pltime=infty,"); 1375 else 1376 printf("pltime=%u,", 1377 EXTRACT_32BITS(&use->rpu_pltime)); 1378 } 1379 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 1380 sizeof(hbuf))) 1381 printf("%s/%u/%u", hbuf, use->rpu_uselen, 1382 use->rpu_keeplen); 1383 else 1384 printf("?/%u/%u", use->rpu_uselen, 1385 use->rpu_keeplen); 1386 /*(*/ 1387 printf(")"); 1388 } 1389 } 1390 1391 return; 1392 1393 trunc: 1394 fputs("[|icmp6]", stdout); 1395 } 1396 1397 #endif /* INET6 */ 1398