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