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