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.5 2013/10/20 02:58:34 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_prefix_info *opp; 683 const struct nd_opt_mtu *opm; 684 const struct nd_opt_rdnss *oprd; 685 const struct nd_opt_advinterval *opa; 686 const struct nd_opt_homeagent_info *oph; 687 const struct nd_opt_route_info *opri; 688 const u_char *cp, *ep; 689 struct in6_addr in6, *in6p; 690 size_t l; 691 u_int i; 692 693 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 694 695 cp = bp; 696 /* 'ep' points to the end of available data. */ 697 ep = snapend; 698 699 while (cp < ep) { 700 op = (struct nd_opt_hdr *)cp; 701 702 ECHECK(op->nd_opt_len); 703 if (resid <= 0) 704 return; 705 if (op->nd_opt_len == 0) 706 goto trunc; 707 if (cp + (op->nd_opt_len << 3) > ep) 708 goto trunc; 709 710 printf("\n\t %s option (%u), length %u (%u): ", 711 tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 712 op->nd_opt_type, 713 op->nd_opt_len << 3, 714 op->nd_opt_len); 715 716 switch (op->nd_opt_type) { 717 case ND_OPT_SOURCE_LINKADDR: 718 l = (op->nd_opt_len << 3) - 2; 719 print_lladdr(cp + 2, l); 720 break; 721 case ND_OPT_TARGET_LINKADDR: 722 l = (op->nd_opt_len << 3) - 2; 723 print_lladdr(cp + 2, l); 724 break; 725 case ND_OPT_PREFIX_INFORMATION: 726 opp = (struct nd_opt_prefix_info *)op; 727 TCHECK(opp->nd_opt_pi_prefix); 728 printf("%s/%u%s, Flags [%s], valid time %ss", 729 ip6addr_string(&opp->nd_opt_pi_prefix), 730 opp->nd_opt_pi_prefix_len, 731 (op->nd_opt_len != 4) ? "badlen" : "", 732 bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 733 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 734 printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 735 break; 736 case ND_OPT_REDIRECTED_HEADER: 737 print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 738 /* xxx */ 739 break; 740 case ND_OPT_MTU: 741 opm = (struct nd_opt_mtu *)op; 742 TCHECK(opm->nd_opt_mtu_mtu); 743 printf(" %u%s", 744 EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 745 (op->nd_opt_len != 1) ? "bad option length" : "" ); 746 break; 747 case ND_OPT_RDNSS: 748 oprd = (struct nd_opt_rdnss *)op; 749 l = (op->nd_opt_len - 1) / 2; 750 printf(" lifetime %us,", 751 EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)); 752 for (i = 0; i < l; i++) { 753 TCHECK(oprd->nd_opt_rdnss_addr[i]); 754 printf(" addr: %s", 755 ip6addr_string(&oprd->nd_opt_rdnss_addr[i])); 756 } 757 break; 758 case ND_OPT_ADVINTERVAL: 759 opa = (struct nd_opt_advinterval *)op; 760 TCHECK(opa->nd_opt_adv_interval); 761 printf(" %ums", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 762 break; 763 case ND_OPT_HOMEAGENT_INFO: 764 oph = (struct nd_opt_homeagent_info *)op; 765 TCHECK(oph->nd_opt_hai_lifetime); 766 printf(" preference %u, lifetime %u", 767 EXTRACT_16BITS(&oph->nd_opt_hai_preference), 768 EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 769 break; 770 case ND_OPT_ROUTE_INFO: 771 opri = (struct nd_opt_route_info *)op; 772 TCHECK(opri->nd_opt_rti_lifetime); 773 memset(&in6, 0, sizeof(in6)); 774 in6p = (struct in6_addr *)(opri + 1); 775 switch (op->nd_opt_len) { 776 case 1: 777 break; 778 case 2: 779 TCHECK2(*in6p, 8); 780 memcpy(&in6, opri + 1, 8); 781 break; 782 case 3: 783 TCHECK(*in6p); 784 memcpy(&in6, opri + 1, sizeof(in6)); 785 break; 786 default: 787 goto trunc; 788 } 789 printf(" %s/%u", ip6addr_string(&in6), 790 opri->nd_opt_rti_prefixlen); 791 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 792 printf(", lifetime=%s", 793 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 794 break; 795 default: 796 if (vflag <= 1) { 797 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 798 return; 799 } 800 break; 801 } 802 /* do we want to see an additional hexdump ? */ 803 if (vflag> 1) 804 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 805 806 cp += op->nd_opt_len << 3; 807 resid -= op->nd_opt_len << 3; 808 } 809 return; 810 811 trunc: 812 fputs("[ndp opt]", stdout); 813 return; 814 #undef ECHECK 815 } 816 817 static void 818 mld6_print(const u_char *bp) 819 { 820 struct mld6_hdr *mp = (struct mld6_hdr *)bp; 821 const u_char *ep; 822 823 /* 'ep' points to the end of available data. */ 824 ep = snapend; 825 826 if ((u_char *)mp + sizeof(*mp) > ep) 827 return; 828 829 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 830 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 831 } 832 833 static void 834 mldv2_report_print(const u_char *bp, u_int len) 835 { 836 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 837 u_int group, nsrcs, ngroups; 838 u_int i, j; 839 840 /* Minimum len is 8 */ 841 if (len < 8) { 842 printf(" [invalid len %d]", len); 843 return; 844 } 845 846 TCHECK(icp->icmp6_data16[1]); 847 ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]); 848 printf(", %d group record(s)", ngroups); 849 if (vflag > 0) { 850 /* Print the group records */ 851 group = 8; 852 for (i = 0; i < ngroups; i++) { 853 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 854 if (len < group + 20) { 855 printf(" [invalid number of groups]"); 856 return; 857 } 858 TCHECK2(bp[group + 4], sizeof(struct in6_addr)); 859 printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 860 printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 861 bp[group])); 862 nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 863 /* Check the number of sources and print them */ 864 if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) { 865 printf(" [invalid number of sources %d]", nsrcs); 866 return; 867 } 868 if (vflag == 1) 869 printf(", %d source(s)", nsrcs); 870 else { 871 /* Print the sources */ 872 (void)printf(" {"); 873 for (j = 0; j < nsrcs; j++) { 874 TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)], 875 sizeof(struct in6_addr)); 876 printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); 877 } 878 (void)printf(" }"); 879 } 880 /* Next group record */ 881 group += 20 + nsrcs * sizeof(struct in6_addr); 882 printf("]"); 883 } 884 } 885 return; 886 trunc: 887 (void)printf("[|icmp6]"); 888 return; 889 } 890 891 static void 892 mldv2_query_print(const u_char *bp, u_int len) 893 { 894 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 895 u_int mrc; 896 int mrt, qqi; 897 u_int nsrcs; 898 register u_int i; 899 900 /* Minimum len is 28 */ 901 if (len < 28) { 902 printf(" [invalid len %d]", len); 903 return; 904 } 905 TCHECK(icp->icmp6_data16[0]); 906 mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]); 907 if (mrc < 32768) { 908 mrt = mrc; 909 } else { 910 mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 911 } 912 if (vflag) { 913 (void)printf(" [max resp delay=%d]", mrt); 914 } 915 TCHECK2(bp[8], sizeof(struct in6_addr)); 916 printf(" [gaddr %s", ip6addr_string(&bp[8])); 917 918 if (vflag) { 919 TCHECK(bp[25]); 920 if (bp[24] & 0x08) { 921 printf(" sflag"); 922 } 923 if (bp[24] & 0x07) { 924 printf(" robustness=%d", bp[24] & 0x07); 925 } 926 if (bp[25] < 128) { 927 qqi = bp[25]; 928 } else { 929 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 930 } 931 printf(" qqi=%d", qqi); 932 } 933 934 TCHECK2(bp[26], 2); 935 nsrcs = EXTRACT_16BITS(&bp[26]); 936 if (nsrcs > 0) { 937 if (len < 28 + nsrcs * sizeof(struct in6_addr)) 938 printf(" [invalid number of sources]"); 939 else if (vflag > 1) { 940 printf(" {"); 941 for (i = 0; i < nsrcs; i++) { 942 TCHECK2(bp[28 + i * sizeof(struct in6_addr)], 943 sizeof(struct in6_addr)); 944 printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); 945 } 946 printf(" }"); 947 } else 948 printf(", %d source(s)", nsrcs); 949 } 950 printf("]"); 951 return; 952 trunc: 953 (void)printf("[|icmp6]"); 954 return; 955 } 956 957 static void 958 dnsname_print(const u_char *cp, const u_char *ep) 959 { 960 int i; 961 962 /* DNS name decoding - no decompression */ 963 printf(", \""); 964 while (cp < ep) { 965 i = *cp++; 966 if (i) { 967 if (i > ep - cp) { 968 printf("???"); 969 break; 970 } 971 while (i-- && cp < ep) { 972 safeputchar(*cp); 973 cp++; 974 } 975 if (cp + 1 < ep && *cp) 976 printf("."); 977 } else { 978 if (cp == ep) { 979 /* FQDN */ 980 printf("."); 981 } else if (cp + 1 == ep && *cp == '\0') { 982 /* truncated */ 983 } else { 984 /* invalid */ 985 printf("???"); 986 } 987 break; 988 } 989 } 990 printf("\""); 991 } 992 993 static void 994 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 995 { 996 struct icmp6_nodeinfo *ni6; 997 struct icmp6_hdr *dp; 998 const u_char *cp; 999 size_t siz, i; 1000 int needcomma; 1001 1002 if (ep < bp) 1003 return; 1004 dp = (struct icmp6_hdr *)bp; 1005 ni6 = (struct icmp6_nodeinfo *)bp; 1006 siz = ep - bp; 1007 1008 switch (ni6->ni_type) { 1009 case ICMP6_NI_QUERY: 1010 if (siz == sizeof(*dp) + 4) { 1011 /* KAME who-are-you */ 1012 printf(" who-are-you request"); 1013 break; 1014 } 1015 printf(" node information query"); 1016 1017 TCHECK2(*dp, sizeof(*ni6)); 1018 ni6 = (struct icmp6_nodeinfo *)dp; 1019 printf(" ("); /*)*/ 1020 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1021 case NI_QTYPE_NOOP: 1022 printf("noop"); 1023 break; 1024 case NI_QTYPE_SUPTYPES: 1025 printf("supported qtypes"); 1026 i = EXTRACT_16BITS(&ni6->ni_flags); 1027 if (i) 1028 printf(" [%s]", (i & 0x01) ? "C" : ""); 1029 break; 1030 break; 1031 case NI_QTYPE_FQDN: 1032 printf("DNS name"); 1033 break; 1034 case NI_QTYPE_NODEADDR: 1035 printf("node addresses"); 1036 i = ni6->ni_flags; 1037 if (!i) 1038 break; 1039 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 1040 printf(" [%s%s%s%s%s%s]", 1041 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1042 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1043 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1044 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1045 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1046 (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 1047 break; 1048 default: 1049 printf("unknown"); 1050 break; 1051 } 1052 1053 if (ni6->ni_qtype == NI_QTYPE_NOOP || 1054 ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 1055 if (siz != sizeof(*ni6)) 1056 if (vflag) 1057 printf(", invalid len"); 1058 /*(*/ 1059 printf(")"); 1060 break; 1061 } 1062 1063 1064 /* XXX backward compat, icmp-name-lookup-03 */ 1065 if (siz == sizeof(*ni6)) { 1066 printf(", 03 draft"); 1067 /*(*/ 1068 printf(")"); 1069 break; 1070 } 1071 1072 switch (ni6->ni_code) { 1073 case ICMP6_NI_SUBJ_IPV6: 1074 if (!TTEST2(*dp, 1075 sizeof(*ni6) + sizeof(struct in6_addr))) 1076 break; 1077 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 1078 if (vflag) 1079 printf(", invalid subject len"); 1080 break; 1081 } 1082 printf(", subject=%s", 1083 getname6((const u_char *)(ni6 + 1))); 1084 break; 1085 case ICMP6_NI_SUBJ_FQDN: 1086 printf(", subject=DNS name"); 1087 cp = (const u_char *)(ni6 + 1); 1088 if (cp[0] == ep - cp - 1) { 1089 /* icmp-name-lookup-03, pascal string */ 1090 if (vflag) 1091 printf(", 03 draft"); 1092 cp++; 1093 printf(", \""); 1094 while (cp < ep) { 1095 safeputchar(*cp); 1096 cp++; 1097 } 1098 printf("\""); 1099 } else 1100 dnsname_print(cp, ep); 1101 break; 1102 case ICMP6_NI_SUBJ_IPV4: 1103 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 1104 break; 1105 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 1106 if (vflag) 1107 printf(", invalid subject len"); 1108 break; 1109 } 1110 printf(", subject=%s", 1111 getname((const u_char *)(ni6 + 1))); 1112 break; 1113 default: 1114 printf(", unknown subject"); 1115 break; 1116 } 1117 1118 /*(*/ 1119 printf(")"); 1120 break; 1121 1122 case ICMP6_NI_REPLY: 1123 if (icmp6len > siz) { 1124 printf("[|icmp6: node information reply]"); 1125 break; 1126 } 1127 1128 needcomma = 0; 1129 1130 ni6 = (struct icmp6_nodeinfo *)dp; 1131 printf(" node information reply"); 1132 printf(" ("); /*)*/ 1133 switch (ni6->ni_code) { 1134 case ICMP6_NI_SUCCESS: 1135 if (vflag) { 1136 printf("success"); 1137 needcomma++; 1138 } 1139 break; 1140 case ICMP6_NI_REFUSED: 1141 printf("refused"); 1142 needcomma++; 1143 if (siz != sizeof(*ni6)) 1144 if (vflag) 1145 printf(", invalid length"); 1146 break; 1147 case ICMP6_NI_UNKNOWN: 1148 printf("unknown"); 1149 needcomma++; 1150 if (siz != sizeof(*ni6)) 1151 if (vflag) 1152 printf(", invalid length"); 1153 break; 1154 } 1155 1156 if (ni6->ni_code != ICMP6_NI_SUCCESS) { 1157 /*(*/ 1158 printf(")"); 1159 break; 1160 } 1161 1162 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1163 case NI_QTYPE_NOOP: 1164 if (needcomma) 1165 printf(", "); 1166 printf("noop"); 1167 if (siz != sizeof(*ni6)) 1168 if (vflag) 1169 printf(", invalid length"); 1170 break; 1171 case NI_QTYPE_SUPTYPES: 1172 if (needcomma) 1173 printf(", "); 1174 printf("supported qtypes"); 1175 i = EXTRACT_16BITS(&ni6->ni_flags); 1176 if (i) 1177 printf(" [%s]", (i & 0x01) ? "C" : ""); 1178 break; 1179 case NI_QTYPE_FQDN: 1180 if (needcomma) 1181 printf(", "); 1182 printf("DNS name"); 1183 cp = (const u_char *)(ni6 + 1) + 4; 1184 if (cp[0] == ep - cp - 1) { 1185 /* icmp-name-lookup-03, pascal string */ 1186 if (vflag) 1187 printf(", 03 draft"); 1188 cp++; 1189 printf(", \""); 1190 while (cp < ep) { 1191 safeputchar(*cp); 1192 cp++; 1193 } 1194 printf("\""); 1195 } else 1196 dnsname_print(cp, ep); 1197 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 1198 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 1199 break; 1200 case NI_QTYPE_NODEADDR: 1201 if (needcomma) 1202 printf(", "); 1203 printf("node addresses"); 1204 i = sizeof(*ni6); 1205 while (i < siz) { 1206 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 1207 break; 1208 printf(" %s", getname6(bp + i)); 1209 i += sizeof(struct in6_addr); 1210 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 1211 i += sizeof(int32_t); 1212 } 1213 i = ni6->ni_flags; 1214 if (!i) 1215 break; 1216 printf(" [%s%s%s%s%s%s%s]", 1217 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1218 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1219 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1220 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1221 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1222 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 1223 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 1224 break; 1225 default: 1226 if (needcomma) 1227 printf(", "); 1228 printf("unknown"); 1229 break; 1230 } 1231 1232 /*(*/ 1233 printf(")"); 1234 break; 1235 } 1236 return; 1237 1238 trunc: 1239 fputs("[|icmp6]", stdout); 1240 } 1241 1242 static void 1243 icmp6_rrenum_print(const u_char *bp, const u_char *ep) 1244 { 1245 struct icmp6_router_renum *rr6; 1246 const char *cp; 1247 struct rr_pco_match *match; 1248 struct rr_pco_use *use; 1249 char hbuf[NI_MAXHOST]; 1250 int n; 1251 1252 if (ep < bp) 1253 return; 1254 rr6 = (struct icmp6_router_renum *)bp; 1255 cp = (const char *)(rr6 + 1); 1256 1257 TCHECK(rr6->rr_reserved); 1258 switch (rr6->rr_code) { 1259 case ICMP6_ROUTER_RENUMBERING_COMMAND: 1260 printf("router renum: command"); 1261 break; 1262 case ICMP6_ROUTER_RENUMBERING_RESULT: 1263 printf("router renum: result"); 1264 break; 1265 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 1266 printf("router renum: sequence number reset"); 1267 break; 1268 default: 1269 printf("router renum: code-#%d", rr6->rr_code); 1270 break; 1271 } 1272 1273 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 1274 1275 if (vflag) { 1276 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 1277 printf("["); /*]*/ 1278 if (rr6->rr_flags) { 1279 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 1280 F(ICMP6_RR_FLAGS_REQRESULT, "R"), 1281 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 1282 F(ICMP6_RR_FLAGS_SPECSITE, "S"), 1283 F(ICMP6_RR_FLAGS_PREVDONE, "P")); 1284 } 1285 printf("seg=%u,", rr6->rr_segnum); 1286 printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)); 1287 if (rr6->rr_reserved) 1288 printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)); 1289 /*[*/ 1290 printf("]"); 1291 #undef F 1292 } 1293 1294 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 1295 match = (struct rr_pco_match *)cp; 1296 cp = (const char *)(match + 1); 1297 1298 TCHECK(match->rpm_prefix); 1299 1300 if (vflag > 1) 1301 printf("\n\t"); 1302 else 1303 printf(" "); 1304 printf("match("); /*)*/ 1305 switch (match->rpm_code) { 1306 case RPM_PCO_ADD: printf("add"); break; 1307 case RPM_PCO_CHANGE: printf("change"); break; 1308 case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 1309 default: printf("#%u", match->rpm_code); break; 1310 } 1311 1312 if (vflag) { 1313 printf(",ord=%u", match->rpm_ordinal); 1314 printf(",min=%u", match->rpm_minlen); 1315 printf(",max=%u", match->rpm_maxlen); 1316 } 1317 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 1318 printf(",%s/%u", hbuf, match->rpm_matchlen); 1319 else 1320 printf(",?/%u", match->rpm_matchlen); 1321 /*(*/ 1322 printf(")"); 1323 1324 n = match->rpm_len - 3; 1325 if (n % 4) 1326 goto trunc; 1327 n /= 4; 1328 while (n-- > 0) { 1329 use = (struct rr_pco_use *)cp; 1330 cp = (const char *)(use + 1); 1331 1332 TCHECK(use->rpu_prefix); 1333 1334 if (vflag > 1) 1335 printf("\n\t"); 1336 else 1337 printf(" "); 1338 printf("use("); /*)*/ 1339 if (use->rpu_flags) { 1340 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 1341 printf("%s%s,", 1342 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 1343 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 1344 #undef F 1345 } 1346 if (vflag) { 1347 printf("mask=0x%x,", use->rpu_ramask); 1348 printf("raflags=0x%x,", use->rpu_raflags); 1349 if (~use->rpu_vltime == 0) 1350 printf("vltime=infty,"); 1351 else 1352 printf("vltime=%u,", 1353 EXTRACT_32BITS(&use->rpu_vltime)); 1354 if (~use->rpu_pltime == 0) 1355 printf("pltime=infty,"); 1356 else 1357 printf("pltime=%u,", 1358 EXTRACT_32BITS(&use->rpu_pltime)); 1359 } 1360 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 1361 sizeof(hbuf))) 1362 printf("%s/%u/%u", hbuf, use->rpu_uselen, 1363 use->rpu_keeplen); 1364 else 1365 printf("?/%u/%u", use->rpu_uselen, 1366 use->rpu_keeplen); 1367 /*(*/ 1368 printf(")"); 1369 } 1370 } 1371 1372 return; 1373 1374 trunc: 1375 fputs("[|icmp6]", stdout); 1376 } 1377 1378 #endif /* INET6 */ 1379