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