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