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