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