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