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