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