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