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.6 2005/09/05 09:29:28 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 == 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], sizeof(struct in6_addr)); 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 * sizeof(struct in6_addr))) { 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 * sizeof(struct in6_addr)], 784 sizeof(struct in6_addr)); 785 printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); 786 } 787 (void)printf(" }"); 788 } 789 /* Next group record */ 790 group += 20 + nsrcs * sizeof(struct in6_addr); 791 printf("]"); 792 } 793 } 794 return; 795 trunc: 796 (void)printf("[|icmp6]"); 797 return; 798 } 799 800 static void 801 mldv2_query_print(const u_char *bp, u_int len) 802 { 803 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 804 u_int mrc; 805 int mrt, qqi; 806 u_int nsrcs; 807 register u_int i; 808 809 /* Minimum len is 28 */ 810 if (len < 28) { 811 printf(" [invalid len %d]", len); 812 return; 813 } 814 TCHECK(icp->icmp6_data16[0]); 815 mrc = ntohs(icp->icmp6_data16[0]); 816 if (mrc < 32768) { 817 mrt = mrc; 818 } else { 819 mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 820 } 821 if (vflag) { 822 (void)printf(" [max resp delay=%d]", mrt); 823 } 824 TCHECK2(bp[8], sizeof(struct in6_addr)); 825 printf(" [gaddr %s", ip6addr_string(&bp[8])); 826 827 if (vflag) { 828 TCHECK(bp[25]); 829 if (bp[24] & 0x08) { 830 printf(" sflag"); 831 } 832 if (bp[24] & 0x07) { 833 printf(" robustness=%d", bp[24] & 0x07); 834 } 835 if (bp[25] < 128) { 836 qqi = bp[25]; 837 } else { 838 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 839 } 840 printf(" qqi=%d", qqi); 841 } 842 843 TCHECK2(bp[26], 2); 844 nsrcs = ntohs(*(u_short *)&bp[26]); 845 if (nsrcs > 0) { 846 if (len < 28 + nsrcs * sizeof(struct in6_addr)) 847 printf(" [invalid number of sources]"); 848 else if (vflag > 1) { 849 printf(" {"); 850 for (i = 0; i < nsrcs; i++) { 851 TCHECK2(bp[28 + i * sizeof(struct in6_addr)], 852 sizeof(struct in6_addr)); 853 printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); 854 } 855 printf(" }"); 856 } else 857 printf(", %d source(s)", nsrcs); 858 } 859 printf("]"); 860 return; 861 trunc: 862 (void)printf("[|icmp6]"); 863 return; 864 } 865 866 void 867 dnsname_print(const u_char *cp, const u_char *ep) 868 { 869 int i; 870 871 /* DNS name decoding - no decompression */ 872 printf(", \""); 873 while (cp < ep) { 874 i = *cp++; 875 if (i) { 876 if (i > ep - cp) { 877 printf("???"); 878 break; 879 } 880 while (i-- && cp < ep) { 881 safeputchar(*cp); 882 cp++; 883 } 884 if (cp + 1 < ep && *cp) 885 printf("."); 886 } else { 887 if (cp == ep) { 888 /* FQDN */ 889 printf("."); 890 } else if (cp + 1 == ep && *cp == '\0') { 891 /* truncated */ 892 } else { 893 /* invalid */ 894 printf("???"); 895 } 896 break; 897 } 898 } 899 printf("\""); 900 } 901 902 static void 903 icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 904 { 905 struct icmp6_nodeinfo *ni6; 906 struct icmp6_hdr *dp; 907 const u_char *cp; 908 size_t siz, i; 909 int needcomma; 910 911 if (ep < bp) 912 return; 913 dp = (struct icmp6_hdr *)bp; 914 ni6 = (struct icmp6_nodeinfo *)bp; 915 siz = ep - bp; 916 917 switch (ni6->ni_type) { 918 case ICMP6_NI_QUERY: 919 if (siz == sizeof(*dp) + 4) { 920 /* KAME who-are-you */ 921 printf(" who-are-you request"); 922 break; 923 } 924 printf(" node information query"); 925 926 TCHECK2(*dp, sizeof(*ni6)); 927 ni6 = (struct icmp6_nodeinfo *)dp; 928 printf(" ("); /*)*/ 929 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 930 case NI_QTYPE_NOOP: 931 printf("noop"); 932 break; 933 case NI_QTYPE_SUPTYPES: 934 printf("supported qtypes"); 935 i = EXTRACT_16BITS(&ni6->ni_flags); 936 if (i) 937 printf(" [%s]", (i & 0x01) ? "C" : ""); 938 break; 939 break; 940 case NI_QTYPE_FQDN: 941 printf("DNS name"); 942 break; 943 case NI_QTYPE_NODEADDR: 944 printf("node addresses"); 945 i = ni6->ni_flags; 946 if (!i) 947 break; 948 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 949 printf(" [%s%s%s%s%s%s]", 950 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 951 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 952 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 953 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 954 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 955 (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 956 break; 957 default: 958 printf("unknown"); 959 break; 960 } 961 962 if (ni6->ni_qtype == NI_QTYPE_NOOP || 963 ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 964 if (siz != sizeof(*ni6)) 965 if (vflag) 966 printf(", invalid len"); 967 /*(*/ 968 printf(")"); 969 break; 970 } 971 972 973 /* XXX backward compat, icmp-name-lookup-03 */ 974 if (siz == sizeof(*ni6)) { 975 printf(", 03 draft"); 976 /*(*/ 977 printf(")"); 978 break; 979 } 980 981 switch (ni6->ni_code) { 982 case ICMP6_NI_SUBJ_IPV6: 983 if (!TTEST2(*dp, 984 sizeof(*ni6) + sizeof(struct in6_addr))) 985 break; 986 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 987 if (vflag) 988 printf(", invalid subject len"); 989 break; 990 } 991 printf(", subject=%s", 992 getname6((const u_char *)(ni6 + 1))); 993 break; 994 case ICMP6_NI_SUBJ_FQDN: 995 printf(", subject=DNS name"); 996 cp = (const u_char *)(ni6 + 1); 997 if (cp[0] == ep - cp - 1) { 998 /* icmp-name-lookup-03, pascal string */ 999 if (vflag) 1000 printf(", 03 draft"); 1001 cp++; 1002 printf(", \""); 1003 while (cp < ep) { 1004 safeputchar(*cp); 1005 cp++; 1006 } 1007 printf("\""); 1008 } else 1009 dnsname_print(cp, ep); 1010 break; 1011 case ICMP6_NI_SUBJ_IPV4: 1012 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 1013 break; 1014 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 1015 if (vflag) 1016 printf(", invalid subject len"); 1017 break; 1018 } 1019 printf(", subject=%s", 1020 getname((const u_char *)(ni6 + 1))); 1021 break; 1022 default: 1023 printf(", unknown subject"); 1024 break; 1025 } 1026 1027 /*(*/ 1028 printf(")"); 1029 break; 1030 1031 case ICMP6_NI_REPLY: 1032 if (icmp6len > siz) { 1033 printf("[|icmp6: node information reply]"); 1034 break; 1035 } 1036 1037 needcomma = 0; 1038 1039 ni6 = (struct icmp6_nodeinfo *)dp; 1040 printf(" node information reply"); 1041 printf(" ("); /*)*/ 1042 switch (ni6->ni_code) { 1043 case ICMP6_NI_SUCCESS: 1044 if (vflag) { 1045 printf("success"); 1046 needcomma++; 1047 } 1048 break; 1049 case ICMP6_NI_REFUSED: 1050 printf("refused"); 1051 needcomma++; 1052 if (siz != sizeof(*ni6)) 1053 if (vflag) 1054 printf(", invalid length"); 1055 break; 1056 case ICMP6_NI_UNKNOWN: 1057 printf("unknown"); 1058 needcomma++; 1059 if (siz != sizeof(*ni6)) 1060 if (vflag) 1061 printf(", invalid length"); 1062 break; 1063 } 1064 1065 if (ni6->ni_code != ICMP6_NI_SUCCESS) { 1066 /*(*/ 1067 printf(")"); 1068 break; 1069 } 1070 1071 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1072 case NI_QTYPE_NOOP: 1073 if (needcomma) 1074 printf(", "); 1075 printf("noop"); 1076 if (siz != sizeof(*ni6)) 1077 if (vflag) 1078 printf(", invalid length"); 1079 break; 1080 case NI_QTYPE_SUPTYPES: 1081 if (needcomma) 1082 printf(", "); 1083 printf("supported qtypes"); 1084 i = EXTRACT_16BITS(&ni6->ni_flags); 1085 if (i) 1086 printf(" [%s]", (i & 0x01) ? "C" : ""); 1087 break; 1088 case NI_QTYPE_FQDN: 1089 if (needcomma) 1090 printf(", "); 1091 printf("DNS name"); 1092 cp = (const u_char *)(ni6 + 1) + 4; 1093 if (cp[0] == ep - cp - 1) { 1094 /* icmp-name-lookup-03, pascal string */ 1095 if (vflag) 1096 printf(", 03 draft"); 1097 cp++; 1098 printf(", \""); 1099 while (cp < ep) { 1100 safeputchar(*cp); 1101 cp++; 1102 } 1103 printf("\""); 1104 } else 1105 dnsname_print(cp, ep); 1106 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 1107 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 1108 break; 1109 case NI_QTYPE_NODEADDR: 1110 if (needcomma) 1111 printf(", "); 1112 printf("node addresses"); 1113 i = sizeof(*ni6); 1114 while (i < siz) { 1115 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 1116 break; 1117 printf(" %s", getname6(bp + i)); 1118 i += sizeof(struct in6_addr); 1119 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 1120 i += sizeof(int32_t); 1121 } 1122 i = ni6->ni_flags; 1123 if (!i) 1124 break; 1125 printf(" [%s%s%s%s%s%s%s]", 1126 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1127 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1128 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1129 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1130 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1131 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 1132 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 1133 break; 1134 default: 1135 if (needcomma) 1136 printf(", "); 1137 printf("unknown"); 1138 break; 1139 } 1140 1141 /*(*/ 1142 printf(")"); 1143 break; 1144 } 1145 return; 1146 1147 trunc: 1148 fputs("[|icmp6]", stdout); 1149 } 1150 1151 static void 1152 icmp6_rrenum_print(const u_char *bp, const u_char *ep) 1153 { 1154 struct icmp6_router_renum *rr6; 1155 const char *cp; 1156 struct rr_pco_match *match; 1157 struct rr_pco_use *use; 1158 char hbuf[NI_MAXHOST]; 1159 int n; 1160 1161 if (ep < bp) 1162 return; 1163 rr6 = (struct icmp6_router_renum *)bp; 1164 cp = (const char *)(rr6 + 1); 1165 1166 TCHECK(rr6->rr_reserved); 1167 switch (rr6->rr_code) { 1168 case ICMP6_ROUTER_RENUMBERING_COMMAND: 1169 printf("router renum: command"); 1170 break; 1171 case ICMP6_ROUTER_RENUMBERING_RESULT: 1172 printf("router renum: result"); 1173 break; 1174 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 1175 printf("router renum: sequence number reset"); 1176 break; 1177 default: 1178 printf("router renum: code-#%d", rr6->rr_code); 1179 break; 1180 } 1181 1182 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 1183 1184 if (vflag) { 1185 #define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 1186 printf("["); /*]*/ 1187 if (rr6->rr_flags) { 1188 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 1189 F(ICMP6_RR_FLAGS_REQRESULT, "R"), 1190 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 1191 F(ICMP6_RR_FLAGS_SPECSITE, "S"), 1192 F(ICMP6_RR_FLAGS_PREVDONE, "P")); 1193 } 1194 printf("seg=%u,", rr6->rr_segnum); 1195 printf("maxdelay=%u", rr6->rr_maxdelay); 1196 if (rr6->rr_reserved) 1197 printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved)); 1198 /*[*/ 1199 printf("]"); 1200 #undef F 1201 } 1202 1203 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 1204 match = (struct rr_pco_match *)cp; 1205 cp = (const char *)(match + 1); 1206 1207 TCHECK(match->rpm_prefix); 1208 1209 if (vflag > 1) 1210 printf("\n\t"); 1211 else 1212 printf(" "); 1213 printf("match("); /*)*/ 1214 switch (match->rpm_code) { 1215 case RPM_PCO_ADD: printf("add"); break; 1216 case RPM_PCO_CHANGE: printf("change"); break; 1217 case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 1218 default: printf("#%u", match->rpm_code); break; 1219 } 1220 1221 if (vflag) { 1222 printf(",ord=%u", match->rpm_ordinal); 1223 printf(",min=%u", match->rpm_minlen); 1224 printf(",max=%u", match->rpm_maxlen); 1225 } 1226 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 1227 printf(",%s/%u", hbuf, match->rpm_matchlen); 1228 else 1229 printf(",?/%u", match->rpm_matchlen); 1230 /*(*/ 1231 printf(")"); 1232 1233 n = match->rpm_len - 3; 1234 if (n % 4) 1235 goto trunc; 1236 n /= 4; 1237 while (n-- > 0) { 1238 use = (struct rr_pco_use *)cp; 1239 cp = (const char *)(use + 1); 1240 1241 TCHECK(use->rpu_prefix); 1242 1243 if (vflag > 1) 1244 printf("\n\t"); 1245 else 1246 printf(" "); 1247 printf("use("); /*)*/ 1248 if (use->rpu_flags) { 1249 #define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 1250 printf("%s%s,", 1251 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 1252 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 1253 #undef F 1254 } 1255 if (vflag) { 1256 printf("mask=0x%x,", use->rpu_ramask); 1257 printf("raflags=0x%x,", use->rpu_raflags); 1258 if (~use->rpu_vltime == 0) 1259 printf("vltime=infty,"); 1260 else 1261 printf("vltime=%u,", 1262 EXTRACT_32BITS(&use->rpu_vltime)); 1263 if (~use->rpu_pltime == 0) 1264 printf("pltime=infty,"); 1265 else 1266 printf("pltime=%u,", 1267 EXTRACT_32BITS(&use->rpu_pltime)); 1268 } 1269 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 1270 sizeof(hbuf))) 1271 printf("%s/%u/%u", hbuf, use->rpu_uselen, 1272 use->rpu_keeplen); 1273 else 1274 printf("?/%u/%u", use->rpu_uselen, 1275 use->rpu_keeplen); 1276 /*(*/ 1277 printf(")"); 1278 } 1279 } 1280 1281 return; 1282 1283 trunc: 1284 fputs("[|icmp6]", stdout); 1285 } 1286 1287 #endif /* INET6 */ 1288