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.2 2010/12/05 05:11:30 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 && (dp->icmp6_type == 359 ND_ROUTER_SOLICIT || 360 ND_ROUTER_ADVERT || 361 ND_NEIGHBOR_ADVERT || 362 ND_NEIGHBOR_SOLICIT || 363 ND_REDIRECT || 364 ICMP6_HADISCOV_REPLY || 365 ICMP6_MOBILEPREFIX_ADVERT )) 366 printf(", length %u", length); 367 368 switch (dp->icmp6_type) { 369 case ICMP6_DST_UNREACH: 370 TCHECK(oip->ip6_dst); 371 printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 372 switch (dp->icmp6_code) { 373 374 case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 375 case ICMP6_DST_UNREACH_ADMIN: 376 case ICMP6_DST_UNREACH_ADDR: 377 printf(" %s",ip6addr_string(&oip->ip6_dst)); 378 break; 379 case ICMP6_DST_UNREACH_BEYONDSCOPE: 380 printf(" %s, source address %s", 381 ip6addr_string(&oip->ip6_dst), 382 ip6addr_string(&oip->ip6_src)); 383 break; 384 case ICMP6_DST_UNREACH_NOPORT: 385 if ((ouh = get_upperlayer((u_char *)oip, &prot)) 386 == NULL) 387 goto trunc; 388 389 dport = EXTRACT_16BITS(&ouh->uh_dport); 390 switch (prot) { 391 case IPPROTO_TCP: 392 printf(", %s tcp port %s", 393 ip6addr_string(&oip->ip6_dst), 394 tcpport_string(dport)); 395 break; 396 case IPPROTO_UDP: 397 printf(", %s udp port %s", 398 ip6addr_string(&oip->ip6_dst), 399 udpport_string(dport)); 400 break; 401 default: 402 printf(", %s protocol %d port %d unreachable", 403 ip6addr_string(&oip->ip6_dst), 404 oip->ip6_nxt, dport); 405 break; 406 } 407 break; 408 default: 409 if (vflag <= 1) { 410 print_unknown_data(bp,"\n\t",length); 411 return; 412 } 413 break; 414 } 415 break; 416 case ICMP6_PACKET_TOO_BIG: 417 TCHECK(dp->icmp6_mtu); 418 printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 419 break; 420 case ICMP6_TIME_EXCEEDED: 421 TCHECK(oip->ip6_dst); 422 switch (dp->icmp6_code) { 423 case ICMP6_TIME_EXCEED_TRANSIT: 424 printf(" for %s", 425 ip6addr_string(&oip->ip6_dst)); 426 break; 427 case ICMP6_TIME_EXCEED_REASSEMBLY: 428 printf(" (reassembly)"); 429 break; 430 default: 431 printf(", unknown code (%u)", dp->icmp6_code); 432 break; 433 } 434 break; 435 case ICMP6_PARAM_PROB: 436 TCHECK(oip->ip6_dst); 437 switch (dp->icmp6_code) { 438 case ICMP6_PARAMPROB_HEADER: 439 printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 440 break; 441 case ICMP6_PARAMPROB_NEXTHEADER: 442 printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 443 break; 444 case ICMP6_PARAMPROB_OPTION: 445 printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 446 break; 447 default: 448 printf(", code-#%d", 449 dp->icmp6_code); 450 break; 451 } 452 break; 453 case ICMP6_ECHO_REQUEST: 454 case ICMP6_ECHO_REPLY: 455 TCHECK(dp->icmp6_seq); 456 printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 457 break; 458 case ICMP6_MEMBERSHIP_QUERY: 459 if (length == MLD_MINLEN) { 460 mld6_print((const u_char *)dp); 461 } else if (length >= MLDV2_MINLEN) { 462 printf("v2 "); 463 mldv2_query_print((const u_char *)dp, length); 464 } else { 465 printf(" unknown-version (len %u) ", length); 466 } 467 break; 468 case ICMP6_MEMBERSHIP_REPORT: 469 mld6_print((const u_char *)dp); 470 break; 471 case ICMP6_MEMBERSHIP_REDUCTION: 472 mld6_print((const u_char *)dp); 473 break; 474 case ND_ROUTER_SOLICIT: 475 #define RTSOLLEN 8 476 if (vflag) { 477 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 478 length - RTSOLLEN); 479 } 480 break; 481 case ND_ROUTER_ADVERT: 482 #define RTADVLEN 16 483 if (vflag) { 484 struct nd_router_advert *p; 485 486 p = (struct nd_router_advert *)dp; 487 TCHECK(p->nd_ra_retransmit); 488 printf("\n\thop limit %u, Flags [%s]" \ 489 ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 490 (u_int)p->nd_ra_curhoplimit, 491 bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 492 get_rtpref(p->nd_ra_flags_reserved), 493 EXTRACT_16BITS(&p->nd_ra_router_lifetime), 494 EXTRACT_32BITS(&p->nd_ra_reachable), 495 EXTRACT_32BITS(&p->nd_ra_retransmit)); 496 497 icmp6_opt_print((const u_char *)dp + RTADVLEN, 498 length - RTADVLEN); 499 } 500 break; 501 case ND_NEIGHBOR_SOLICIT: 502 { 503 struct nd_neighbor_solicit *p; 504 p = (struct nd_neighbor_solicit *)dp; 505 TCHECK(p->nd_ns_target); 506 printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 507 if (vflag) { 508 #define NDSOLLEN 24 509 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 510 length - NDSOLLEN); 511 } 512 } 513 break; 514 case ND_NEIGHBOR_ADVERT: 515 { 516 struct nd_neighbor_advert *p; 517 518 p = (struct nd_neighbor_advert *)dp; 519 TCHECK(p->nd_na_target); 520 printf(", tgt is %s", 521 ip6addr_string(&p->nd_na_target)); 522 if (vflag) { 523 printf(", Flags [%s]", 524 bittok2str(icmp6_nd_na_flag_values, 525 "none", 526 EXTRACT_32BITS(&p->nd_na_flags_reserved))); 527 #define NDADVLEN 24 528 icmp6_opt_print((const u_char *)dp + NDADVLEN, 529 length - NDADVLEN); 530 #undef NDADVLEN 531 } 532 } 533 break; 534 case ND_REDIRECT: 535 #define RDR(i) ((struct nd_redirect *)(i)) 536 TCHECK(RDR(dp)->nd_rd_dst); 537 printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 538 TCHECK(RDR(dp)->nd_rd_target); 539 printf(" to %s", 540 getname6((const u_char*)&RDR(dp)->nd_rd_target)); 541 #define REDIRECTLEN 40 542 if (vflag) { 543 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 544 length - REDIRECTLEN); 545 } 546 break; 547 #undef REDIRECTLEN 548 #undef RDR 549 case ICMP6_ROUTER_RENUMBERING: 550 icmp6_rrenum_print(bp, ep); 551 break; 552 case ICMP6_NI_QUERY: 553 case ICMP6_NI_REPLY: 554 icmp6_nodeinfo_print(length, bp, ep); 555 break; 556 case IND_SOLICIT: 557 case IND_ADVERT: 558 break; 559 case ICMP6_V2_MEMBERSHIP_REPORT: 560 mldv2_report_print((const u_char *) dp, length); 561 break; 562 case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 563 case ICMP6_HADISCOV_REQUEST: 564 TCHECK(dp->icmp6_data16[0]); 565 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 566 break; 567 case ICMP6_HADISCOV_REPLY: 568 if (vflag) { 569 struct in6_addr *in6; 570 u_char *cp; 571 572 TCHECK(dp->icmp6_data16[0]); 573 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 574 cp = (u_char *)dp + length; 575 in6 = (struct in6_addr *)(dp + 1); 576 for (; (u_char *)in6 < cp; in6++) { 577 TCHECK(*in6); 578 printf(", %s", ip6addr_string(in6)); 579 } 580 } 581 break; 582 case ICMP6_MOBILEPREFIX_ADVERT: 583 if (vflag) { 584 TCHECK(dp->icmp6_data16[0]); 585 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 586 if (dp->icmp6_data16[1] & 0xc0) 587 printf(" "); 588 if (dp->icmp6_data16[1] & 0x80) 589 printf("M"); 590 if (dp->icmp6_data16[1] & 0x40) 591 printf("O"); 592 #define MPADVLEN 8 593 icmp6_opt_print((const u_char *)dp + MPADVLEN, 594 length - MPADVLEN); 595 } 596 break; 597 case ND_RPL_MESSAGE: 598 rpl_print(ndo, dp, &dp->icmp6_data8[0], length); 599 break; 600 default: 601 printf(", length %u", length); 602 if (vflag <= 1) 603 print_unknown_data(bp,"\n\t", length); 604 return; 605 } 606 if (!vflag) 607 printf(", length %u", length); 608 return; 609 trunc: 610 fputs("[|icmp6]", stdout); 611 } 612 613 static struct udphdr * 614 get_upperlayer(u_char *bp, u_int *prot) 615 { 616 const u_char *ep; 617 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 618 struct udphdr *uh; 619 struct ip6_hbh *hbh; 620 struct ip6_frag *fragh; 621 struct ah *ah; 622 u_int nh; 623 int hlen; 624 625 /* 'ep' points to the end of available data. */ 626 ep = snapend; 627 628 if (!TTEST(ip6->ip6_nxt)) 629 return NULL; 630 631 nh = ip6->ip6_nxt; 632 hlen = sizeof(struct ip6_hdr); 633 634 while (bp < ep) { 635 bp += hlen; 636 637 switch(nh) { 638 case IPPROTO_UDP: 639 case IPPROTO_TCP: 640 uh = (struct udphdr *)bp; 641 if (TTEST(uh->uh_dport)) { 642 *prot = nh; 643 return(uh); 644 } 645 else 646 return(NULL); 647 /* NOTREACHED */ 648 649 case IPPROTO_HOPOPTS: 650 case IPPROTO_DSTOPTS: 651 case IPPROTO_ROUTING: 652 hbh = (struct ip6_hbh *)bp; 653 if (!TTEST(hbh->ip6h_len)) 654 return(NULL); 655 nh = hbh->ip6h_nxt; 656 hlen = (hbh->ip6h_len + 1) << 3; 657 break; 658 659 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 660 fragh = (struct ip6_frag *)bp; 661 if (!TTEST(fragh->ip6f_offlg)) 662 return(NULL); 663 /* fragments with non-zero offset are meaningless */ 664 if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 665 return(NULL); 666 nh = fragh->ip6f_nxt; 667 hlen = sizeof(struct ip6_frag); 668 break; 669 670 case IPPROTO_AH: 671 ah = (struct ah *)bp; 672 if (!TTEST(ah->ah_len)) 673 return(NULL); 674 nh = ah->ah_nxt; 675 hlen = (ah->ah_len + 2) << 2; 676 break; 677 678 default: /* unknown or undecodable header */ 679 *prot = nh; /* meaningless, but set here anyway */ 680 return(NULL); 681 } 682 } 683 684 return(NULL); /* should be notreached, though */ 685 } 686 687 static void 688 icmp6_opt_print(const u_char *bp, int resid) 689 { 690 const struct nd_opt_hdr *op; 691 const struct nd_opt_hdr *opl; /* why there's no struct? */ 692 const struct nd_opt_prefix_info *opp; 693 const struct icmp6_opts_redirect *opr; 694 const struct nd_opt_mtu *opm; 695 const struct nd_opt_rdnss *oprd; 696 const struct nd_opt_advinterval *opa; 697 const struct nd_opt_homeagent_info *oph; 698 const struct nd_opt_route_info *opri; 699 const u_char *cp, *ep; 700 struct in6_addr in6, *in6p; 701 size_t l; 702 u_int i; 703 704 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 705 706 cp = bp; 707 /* 'ep' points to the end of available data. */ 708 ep = snapend; 709 710 while (cp < ep) { 711 op = (struct nd_opt_hdr *)cp; 712 713 ECHECK(op->nd_opt_len); 714 if (resid <= 0) 715 return; 716 if (op->nd_opt_len == 0) 717 goto trunc; 718 if (cp + (op->nd_opt_len << 3) > ep) 719 goto trunc; 720 721 printf("\n\t %s option (%u), length %u (%u): ", 722 tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 723 op->nd_opt_type, 724 op->nd_opt_len << 3, 725 op->nd_opt_len); 726 727 switch (op->nd_opt_type) { 728 case ND_OPT_SOURCE_LINKADDR: 729 opl = (struct nd_opt_hdr *)op; 730 l = (op->nd_opt_len << 3) - 2; 731 print_lladdr(cp + 2, l); 732 break; 733 case ND_OPT_TARGET_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_PREFIX_INFORMATION: 739 opp = (struct nd_opt_prefix_info *)op; 740 TCHECK(opp->nd_opt_pi_prefix); 741 printf("%s/%u%s, Flags [%s], valid time %ss", 742 ip6addr_string(&opp->nd_opt_pi_prefix), 743 opp->nd_opt_pi_prefix_len, 744 (op->nd_opt_len != 4) ? "badlen" : "", 745 bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 746 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 747 printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 748 break; 749 case ND_OPT_REDIRECTED_HEADER: 750 opr = (struct icmp6_opts_redirect *)op; 751 print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 752 /* xxx */ 753 break; 754 case ND_OPT_MTU: 755 opm = (struct nd_opt_mtu *)op; 756 TCHECK(opm->nd_opt_mtu_mtu); 757 printf(" %u%s", 758 EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 759 (op->nd_opt_len != 1) ? "bad option length" : "" ); 760 break; 761 case ND_OPT_RDNSS: 762 oprd = (struct nd_opt_rdnss *)op; 763 l = (op->nd_opt_len - 1) / 2; 764 printf(" lifetime %us,", 765 EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)); 766 for (i = 0; i < l; i++) { 767 TCHECK(oprd->nd_opt_rdnss_addr[i]); 768 printf(" addr: %s", 769 ip6addr_string(&oprd->nd_opt_rdnss_addr[i])); 770 } 771 break; 772 case ND_OPT_ADVINTERVAL: 773 opa = (struct nd_opt_advinterval *)op; 774 TCHECK(opa->nd_opt_adv_interval); 775 printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 776 break; 777 case ND_OPT_HOMEAGENT_INFO: 778 oph = (struct nd_opt_homeagent_info *)op; 779 TCHECK(oph->nd_opt_hai_lifetime); 780 printf(" preference %u, lifetime %u", 781 EXTRACT_16BITS(&oph->nd_opt_hai_preference), 782 EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 783 break; 784 case ND_OPT_ROUTE_INFO: 785 opri = (struct nd_opt_route_info *)op; 786 TCHECK(opri->nd_opt_rti_lifetime); 787 memset(&in6, 0, sizeof(in6)); 788 in6p = (struct in6_addr *)(opri + 1); 789 switch (op->nd_opt_len) { 790 case 1: 791 break; 792 case 2: 793 TCHECK2(*in6p, 8); 794 memcpy(&in6, opri + 1, 8); 795 break; 796 case 3: 797 TCHECK(*in6p); 798 memcpy(&in6, opri + 1, sizeof(in6)); 799 break; 800 default: 801 goto trunc; 802 } 803 printf(" %s/%u", ip6addr_string(&in6), 804 opri->nd_opt_rti_prefixlen); 805 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 806 printf(", lifetime=%s", 807 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 808 break; 809 default: 810 if (vflag <= 1) { 811 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 812 return; 813 } 814 break; 815 } 816 /* do we want to see an additional hexdump ? */ 817 if (vflag> 1) 818 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 819 820 cp += op->nd_opt_len << 3; 821 resid -= op->nd_opt_len << 3; 822 } 823 return; 824 825 trunc: 826 fputs("[ndp opt]", stdout); 827 return; 828 #undef ECHECK 829 } 830 831 static void 832 mld6_print(const u_char *bp) 833 { 834 struct mld6_hdr *mp = (struct mld6_hdr *)bp; 835 const u_char *ep; 836 837 /* 'ep' points to the end of available data. */ 838 ep = snapend; 839 840 if ((u_char *)mp + sizeof(*mp) > ep) 841 return; 842 843 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 844 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 845 } 846 847 static void 848 mldv2_report_print(const u_char *bp, u_int len) 849 { 850 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 851 u_int group, nsrcs, ngroups; 852 u_int i, j; 853 854 /* Minimum len is 8 */ 855 if (len < 8) { 856 printf(" [invalid len %d]", len); 857 return; 858 } 859 860 TCHECK(icp->icmp6_data16[1]); 861 ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]); 862 printf(", %d group record(s)", ngroups); 863 if (vflag > 0) { 864 /* Print the group records */ 865 group = 8; 866 for (i = 0; i < ngroups; i++) { 867 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 868 if (len < group + 20) { 869 printf(" [invalid number of groups]"); 870 return; 871 } 872 TCHECK2(bp[group + 4], sizeof(struct in6_addr)); 873 printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 874 printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 875 bp[group])); 876 nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 877 /* Check the number of sources and print them */ 878 if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) { 879 printf(" [invalid number of sources %d]", nsrcs); 880 return; 881 } 882 if (vflag == 1) 883 printf(", %d source(s)", nsrcs); 884 else { 885 /* Print the sources */ 886 (void)printf(" {"); 887 for (j = 0; j < nsrcs; j++) { 888 TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)], 889 sizeof(struct in6_addr)); 890 printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); 891 } 892 (void)printf(" }"); 893 } 894 /* Next group record */ 895 group += 20 + nsrcs * sizeof(struct in6_addr); 896 printf("]"); 897 } 898 } 899 return; 900 trunc: 901 (void)printf("[|icmp6]"); 902 return; 903 } 904 905 static void 906 mldv2_query_print(const u_char *bp, u_int len) 907 { 908 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 909 u_int mrc; 910 int mrt, qqi; 911 u_int nsrcs; 912 register u_int i; 913 914 /* Minimum len is 28 */ 915 if (len < 28) { 916 printf(" [invalid len %d]", len); 917 return; 918 } 919 TCHECK(icp->icmp6_data16[0]); 920 mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]); 921 if (mrc < 32768) { 922 mrt = mrc; 923 } else { 924 mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 925 } 926 if (vflag) { 927 (void)printf(" [max resp delay=%d]", mrt); 928 } 929 TCHECK2(bp[8], sizeof(struct in6_addr)); 930 printf(" [gaddr %s", ip6addr_string(&bp[8])); 931 932 if (vflag) { 933 TCHECK(bp[25]); 934 if (bp[24] & 0x08) { 935 printf(" sflag"); 936 } 937 if (bp[24] & 0x07) { 938 printf(" robustness=%d", bp[24] & 0x07); 939 } 940 if (bp[25] < 128) { 941 qqi = bp[25]; 942 } else { 943 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 944 } 945 printf(" qqi=%d", qqi); 946 } 947 948 TCHECK2(bp[26], 2); 949 nsrcs = EXTRACT_16BITS(&bp[26]); 950 if (nsrcs > 0) { 951 if (len < 28 + nsrcs * sizeof(struct in6_addr)) 952 printf(" [invalid number of sources]"); 953 else if (vflag > 1) { 954 printf(" {"); 955 for (i = 0; i < nsrcs; i++) { 956 TCHECK2(bp[28 + i * sizeof(struct in6_addr)], 957 sizeof(struct in6_addr)); 958 printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); 959 } 960 printf(" }"); 961 } else 962 printf(", %d source(s)", nsrcs); 963 } 964 printf("]"); 965 return; 966 trunc: 967 (void)printf("[|icmp6]"); 968 return; 969 } 970 971 static void 972 dnsname_print(const u_char *cp, const u_char *ep) 973 { 974 int i; 975 976 /* DNS name decoding - no decompression */ 977 printf(", \""); 978 while (cp < ep) { 979 i = *cp++; 980 if (i) { 981 if (i > ep - cp) { 982 printf("???"); 983 break; 984 } 985 while (i-- && cp < ep) { 986 safeputchar(*cp); 987 cp++; 988 } 989 if (cp + 1 < ep && *cp) 990 printf("."); 991 } else { 992 if (cp == ep) { 993 /* FQDN */ 994 printf("."); 995 } else if (cp + 1 == ep && *cp == '\0') { 996 /* truncated */ 997 } else { 998 /* invalid */ 999 printf("???"); 1000 } 1001 break; 1002 } 1003 } 1004 printf("\""); 1005 } 1006 1007 static void 1008 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 1009 { 1010 struct icmp6_nodeinfo *ni6; 1011 struct icmp6_hdr *dp; 1012 const u_char *cp; 1013 size_t siz, i; 1014 int needcomma; 1015 1016 if (ep < bp) 1017 return; 1018 dp = (struct icmp6_hdr *)bp; 1019 ni6 = (struct icmp6_nodeinfo *)bp; 1020 siz = ep - bp; 1021 1022 switch (ni6->ni_type) { 1023 case ICMP6_NI_QUERY: 1024 if (siz == sizeof(*dp) + 4) { 1025 /* KAME who-are-you */ 1026 printf(" who-are-you request"); 1027 break; 1028 } 1029 printf(" node information query"); 1030 1031 TCHECK2(*dp, sizeof(*ni6)); 1032 ni6 = (struct icmp6_nodeinfo *)dp; 1033 printf(" ("); /*)*/ 1034 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1035 case NI_QTYPE_NOOP: 1036 printf("noop"); 1037 break; 1038 case NI_QTYPE_SUPTYPES: 1039 printf("supported qtypes"); 1040 i = EXTRACT_16BITS(&ni6->ni_flags); 1041 if (i) 1042 printf(" [%s]", (i & 0x01) ? "C" : ""); 1043 break; 1044 break; 1045 case NI_QTYPE_FQDN: 1046 printf("DNS name"); 1047 break; 1048 case NI_QTYPE_NODEADDR: 1049 printf("node addresses"); 1050 i = ni6->ni_flags; 1051 if (!i) 1052 break; 1053 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 1054 printf(" [%s%s%s%s%s%s]", 1055 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1056 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1057 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1058 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1059 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1060 (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 1061 break; 1062 default: 1063 printf("unknown"); 1064 break; 1065 } 1066 1067 if (ni6->ni_qtype == NI_QTYPE_NOOP || 1068 ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 1069 if (siz != sizeof(*ni6)) 1070 if (vflag) 1071 printf(", invalid len"); 1072 /*(*/ 1073 printf(")"); 1074 break; 1075 } 1076 1077 1078 /* XXX backward compat, icmp-name-lookup-03 */ 1079 if (siz == sizeof(*ni6)) { 1080 printf(", 03 draft"); 1081 /*(*/ 1082 printf(")"); 1083 break; 1084 } 1085 1086 switch (ni6->ni_code) { 1087 case ICMP6_NI_SUBJ_IPV6: 1088 if (!TTEST2(*dp, 1089 sizeof(*ni6) + sizeof(struct in6_addr))) 1090 break; 1091 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 1092 if (vflag) 1093 printf(", invalid subject len"); 1094 break; 1095 } 1096 printf(", subject=%s", 1097 getname6((const u_char *)(ni6 + 1))); 1098 break; 1099 case ICMP6_NI_SUBJ_FQDN: 1100 printf(", subject=DNS name"); 1101 cp = (const u_char *)(ni6 + 1); 1102 if (cp[0] == ep - cp - 1) { 1103 /* icmp-name-lookup-03, pascal string */ 1104 if (vflag) 1105 printf(", 03 draft"); 1106 cp++; 1107 printf(", \""); 1108 while (cp < ep) { 1109 safeputchar(*cp); 1110 cp++; 1111 } 1112 printf("\""); 1113 } else 1114 dnsname_print(cp, ep); 1115 break; 1116 case ICMP6_NI_SUBJ_IPV4: 1117 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 1118 break; 1119 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 1120 if (vflag) 1121 printf(", invalid subject len"); 1122 break; 1123 } 1124 printf(", subject=%s", 1125 getname((const u_char *)(ni6 + 1))); 1126 break; 1127 default: 1128 printf(", unknown subject"); 1129 break; 1130 } 1131 1132 /*(*/ 1133 printf(")"); 1134 break; 1135 1136 case ICMP6_NI_REPLY: 1137 if (icmp6len > siz) { 1138 printf("[|icmp6: node information reply]"); 1139 break; 1140 } 1141 1142 needcomma = 0; 1143 1144 ni6 = (struct icmp6_nodeinfo *)dp; 1145 printf(" node information reply"); 1146 printf(" ("); /*)*/ 1147 switch (ni6->ni_code) { 1148 case ICMP6_NI_SUCCESS: 1149 if (vflag) { 1150 printf("success"); 1151 needcomma++; 1152 } 1153 break; 1154 case ICMP6_NI_REFUSED: 1155 printf("refused"); 1156 needcomma++; 1157 if (siz != sizeof(*ni6)) 1158 if (vflag) 1159 printf(", invalid length"); 1160 break; 1161 case ICMP6_NI_UNKNOWN: 1162 printf("unknown"); 1163 needcomma++; 1164 if (siz != sizeof(*ni6)) 1165 if (vflag) 1166 printf(", invalid length"); 1167 break; 1168 } 1169 1170 if (ni6->ni_code != ICMP6_NI_SUCCESS) { 1171 /*(*/ 1172 printf(")"); 1173 break; 1174 } 1175 1176 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1177 case NI_QTYPE_NOOP: 1178 if (needcomma) 1179 printf(", "); 1180 printf("noop"); 1181 if (siz != sizeof(*ni6)) 1182 if (vflag) 1183 printf(", invalid length"); 1184 break; 1185 case NI_QTYPE_SUPTYPES: 1186 if (needcomma) 1187 printf(", "); 1188 printf("supported qtypes"); 1189 i = EXTRACT_16BITS(&ni6->ni_flags); 1190 if (i) 1191 printf(" [%s]", (i & 0x01) ? "C" : ""); 1192 break; 1193 case NI_QTYPE_FQDN: 1194 if (needcomma) 1195 printf(", "); 1196 printf("DNS name"); 1197 cp = (const u_char *)(ni6 + 1) + 4; 1198 if (cp[0] == ep - cp - 1) { 1199 /* icmp-name-lookup-03, pascal string */ 1200 if (vflag) 1201 printf(", 03 draft"); 1202 cp++; 1203 printf(", \""); 1204 while (cp < ep) { 1205 safeputchar(*cp); 1206 cp++; 1207 } 1208 printf("\""); 1209 } else 1210 dnsname_print(cp, ep); 1211 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 1212 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 1213 break; 1214 case NI_QTYPE_NODEADDR: 1215 if (needcomma) 1216 printf(", "); 1217 printf("node addresses"); 1218 i = sizeof(*ni6); 1219 while (i < siz) { 1220 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 1221 break; 1222 printf(" %s", getname6(bp + i)); 1223 i += sizeof(struct in6_addr); 1224 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 1225 i += sizeof(int32_t); 1226 } 1227 i = ni6->ni_flags; 1228 if (!i) 1229 break; 1230 printf(" [%s%s%s%s%s%s%s]", 1231 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1232 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1233 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1234 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1235 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1236 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 1237 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 1238 break; 1239 default: 1240 if (needcomma) 1241 printf(", "); 1242 printf("unknown"); 1243 break; 1244 } 1245 1246 /*(*/ 1247 printf(")"); 1248 break; 1249 } 1250 return; 1251 1252 trunc: 1253 fputs("[|icmp6]", stdout); 1254 } 1255 1256 static void 1257 icmp6_rrenum_print(const u_char *bp, const u_char *ep) 1258 { 1259 struct icmp6_router_renum *rr6; 1260 const char *cp; 1261 struct rr_pco_match *match; 1262 struct rr_pco_use *use; 1263 char hbuf[NI_MAXHOST]; 1264 int n; 1265 1266 if (ep < bp) 1267 return; 1268 rr6 = (struct icmp6_router_renum *)bp; 1269 cp = (const char *)(rr6 + 1); 1270 1271 TCHECK(rr6->rr_reserved); 1272 switch (rr6->rr_code) { 1273 case ICMP6_ROUTER_RENUMBERING_COMMAND: 1274 printf("router renum: command"); 1275 break; 1276 case ICMP6_ROUTER_RENUMBERING_RESULT: 1277 printf("router renum: result"); 1278 break; 1279 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 1280 printf("router renum: sequence number reset"); 1281 break; 1282 default: 1283 printf("router renum: code-#%d", rr6->rr_code); 1284 break; 1285 } 1286 1287 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 1288 1289 if (vflag) { 1290 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 1291 printf("["); /*]*/ 1292 if (rr6->rr_flags) { 1293 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 1294 F(ICMP6_RR_FLAGS_REQRESULT, "R"), 1295 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 1296 F(ICMP6_RR_FLAGS_SPECSITE, "S"), 1297 F(ICMP6_RR_FLAGS_PREVDONE, "P")); 1298 } 1299 printf("seg=%u,", rr6->rr_segnum); 1300 printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)); 1301 if (rr6->rr_reserved) 1302 printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)); 1303 /*[*/ 1304 printf("]"); 1305 #undef F 1306 } 1307 1308 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 1309 match = (struct rr_pco_match *)cp; 1310 cp = (const char *)(match + 1); 1311 1312 TCHECK(match->rpm_prefix); 1313 1314 if (vflag > 1) 1315 printf("\n\t"); 1316 else 1317 printf(" "); 1318 printf("match("); /*)*/ 1319 switch (match->rpm_code) { 1320 case RPM_PCO_ADD: printf("add"); break; 1321 case RPM_PCO_CHANGE: printf("change"); break; 1322 case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 1323 default: printf("#%u", match->rpm_code); break; 1324 } 1325 1326 if (vflag) { 1327 printf(",ord=%u", match->rpm_ordinal); 1328 printf(",min=%u", match->rpm_minlen); 1329 printf(",max=%u", match->rpm_maxlen); 1330 } 1331 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 1332 printf(",%s/%u", hbuf, match->rpm_matchlen); 1333 else 1334 printf(",?/%u", match->rpm_matchlen); 1335 /*(*/ 1336 printf(")"); 1337 1338 n = match->rpm_len - 3; 1339 if (n % 4) 1340 goto trunc; 1341 n /= 4; 1342 while (n-- > 0) { 1343 use = (struct rr_pco_use *)cp; 1344 cp = (const char *)(use + 1); 1345 1346 TCHECK(use->rpu_prefix); 1347 1348 if (vflag > 1) 1349 printf("\n\t"); 1350 else 1351 printf(" "); 1352 printf("use("); /*)*/ 1353 if (use->rpu_flags) { 1354 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 1355 printf("%s%s,", 1356 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 1357 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 1358 #undef F 1359 } 1360 if (vflag) { 1361 printf("mask=0x%x,", use->rpu_ramask); 1362 printf("raflags=0x%x,", use->rpu_raflags); 1363 if (~use->rpu_vltime == 0) 1364 printf("vltime=infty,"); 1365 else 1366 printf("vltime=%u,", 1367 EXTRACT_32BITS(&use->rpu_vltime)); 1368 if (~use->rpu_pltime == 0) 1369 printf("pltime=infty,"); 1370 else 1371 printf("pltime=%u,", 1372 EXTRACT_32BITS(&use->rpu_pltime)); 1373 } 1374 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 1375 sizeof(hbuf))) 1376 printf("%s/%u/%u", hbuf, use->rpu_uselen, 1377 use->rpu_keeplen); 1378 else 1379 printf("?/%u/%u", use->rpu_uselen, 1380 use->rpu_keeplen); 1381 /*(*/ 1382 printf(")"); 1383 } 1384 } 1385 1386 return; 1387 1388 trunc: 1389 fputs("[|icmp6]", stdout); 1390 } 1391 1392 #endif /* INET6 */ 1393