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[] = 24 "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.2.2.1 2000/01/11 06:58:24 fenner Exp $"; 25 #endif 26 27 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 #ifdef INET6 32 33 #include <ctype.h> 34 35 #include <sys/param.h> 36 #include <sys/time.h> 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 40 #include <net/if.h> 41 42 #include <netinet/in.h> 43 #include <netinet/if_ether.h> 44 #include <netinet/in_systm.h> 45 #include <netinet/ip.h> 46 #include <netinet/ip_icmp.h> 47 #include <netinet/ip_var.h> 48 #include <netinet/udp.h> 49 #include <netinet/udp_var.h> 50 #include <netinet/tcp.h> 51 52 #include <arpa/inet.h> 53 54 #include <stdio.h> 55 56 #include <netinet/ip6.h> 57 #include <netinet/icmp6.h> 58 59 #include "interface.h" 60 #include "addrtoname.h" 61 62 void icmp6_opt_print(const u_char *, int); 63 void mld6_print(const u_char *); 64 65 void 66 icmp6_print(register const u_char *bp, register const u_char *bp2) 67 { 68 register const struct icmp6_hdr *dp; 69 register const struct ip6_hdr *ip; 70 register const char *str; 71 register const struct ip6_hdr *oip; 72 register const struct udphdr *ouh; 73 register int hlen, dport; 74 register const u_char *ep; 75 char buf[256]; 76 int icmp6len; 77 78 #if 0 79 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc 80 #endif 81 82 dp = (struct icmp6_hdr *)bp; 83 ip = (struct ip6_hdr *)bp2; 84 oip = (struct ip6_hdr *)(dp + 1); 85 str = buf; 86 /* 'ep' points to the end of avaible data. */ 87 ep = snapend; 88 if (ip->ip6_plen) 89 icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) - 90 (bp - bp2)); 91 else /* XXX: jumbo payload case... */ 92 icmp6len = snapend - bp; 93 94 #if 0 95 (void)printf("%s > %s: ", 96 ip6addr_string(&ip->ip6_src), 97 ip6addr_string(&ip->ip6_dst)); 98 #endif 99 100 TCHECK(dp->icmp6_code); 101 switch(dp->icmp6_type) { 102 case ICMP6_DST_UNREACH: 103 TCHECK(oip->ip6_dst); 104 switch (dp->icmp6_code) { 105 case ICMP6_DST_UNREACH_NOROUTE: 106 printf("icmp6: %s unreachable route", 107 ip6addr_string(&oip->ip6_dst)); 108 break; 109 case ICMP6_DST_UNREACH_ADMIN: 110 printf("icmp6: %s unreachable prohibited", 111 ip6addr_string(&oip->ip6_dst)); 112 break; 113 #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE 114 case ICMP6_DST_UNREACH_BEYONDSCOPE: 115 #else 116 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 117 #endif 118 printf("icmp6: %s beyond scope of source address %s", 119 ip6addr_string(&oip->ip6_dst), 120 ip6addr_string(&oip->ip6_src)); 121 break; 122 case ICMP6_DST_UNREACH_ADDR: 123 printf("icmp6: %s unreachable address", 124 ip6addr_string(&oip->ip6_dst)); 125 break; 126 case ICMP6_DST_UNREACH_NOPORT: 127 TCHECK(oip->ip6_nxt); 128 hlen = sizeof(struct ip6_hdr); 129 ouh = (struct udphdr *)(((u_char *)oip) + hlen); 130 dport = ntohs(ouh->uh_dport); 131 switch (oip->ip6_nxt) { 132 case IPPROTO_TCP: 133 printf("icmp6: %s tcp port %s unreachable", 134 ip6addr_string(&oip->ip6_dst), 135 tcpport_string(dport)); 136 break; 137 case IPPROTO_UDP: 138 printf("icmp6: %s udp port %s unreachable", 139 ip6addr_string(&oip->ip6_dst), 140 udpport_string(dport)); 141 break; 142 default: 143 printf("icmp6: %s protocol %d port %d unreachable", 144 ip6addr_string(&oip->ip6_dst), 145 oip->ip6_nxt, dport); 146 break; 147 } 148 break; 149 default: 150 printf("icmp6: %s unreachable code-#%d", 151 ip6addr_string(&oip->ip6_dst), 152 dp->icmp6_code); 153 break; 154 } 155 break; 156 case ICMP6_PACKET_TOO_BIG: 157 TCHECK(dp->icmp6_mtu); 158 printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu)); 159 break; 160 case ICMP6_TIME_EXCEEDED: 161 TCHECK(oip->ip6_dst); 162 switch (dp->icmp6_code) { 163 case ICMP6_TIME_EXCEED_TRANSIT: 164 printf("icmp6: time exceeded in-transit for %s", 165 ip6addr_string(&oip->ip6_dst)); 166 break; 167 case ICMP6_TIME_EXCEED_REASSEMBLY: 168 printf("icmp6: ip6 reassembly time exceeded"); 169 break; 170 default: 171 printf("icmp6: time exceeded code-#%d", 172 dp->icmp6_code); 173 break; 174 } 175 break; 176 case ICMP6_PARAM_PROB: 177 TCHECK(oip->ip6_dst); 178 switch (dp->icmp6_code) { 179 case ICMP6_PARAMPROB_HEADER: 180 printf("icmp6: parameter problem errorneous - octet %u\n", 181 (u_int32_t)ntohl(dp->icmp6_pptr)); 182 break; 183 case ICMP6_PARAMPROB_NEXTHEADER: 184 printf("icmp6: parameter problem next header - octet %u\n", 185 (u_int32_t)ntohl(dp->icmp6_pptr)); 186 break; 187 case ICMP6_PARAMPROB_OPTION: 188 printf("icmp6: parameter problem option - octet %u\n", 189 (u_int32_t)ntohl(dp->icmp6_pptr)); 190 break; 191 default: 192 printf("icmp6: parameter problem code-#%d", 193 dp->icmp6_code); 194 break; 195 } 196 break; 197 case ICMP6_ECHO_REQUEST: 198 printf("icmp6: echo request"); 199 break; 200 case ICMP6_ECHO_REPLY: 201 printf("icmp6: echo reply"); 202 break; 203 case ICMP6_MEMBERSHIP_QUERY: 204 printf("icmp6: multicast listener query "); 205 mld6_print((const u_char *)dp); 206 break; 207 case ICMP6_MEMBERSHIP_REPORT: 208 printf("icmp6: multicast listener report "); 209 mld6_print((const u_char *)dp); 210 break; 211 case ICMP6_MEMBERSHIP_REDUCTION: 212 printf("icmp6: multicast listener done "); 213 mld6_print((const u_char *)dp); 214 break; 215 case ND_ROUTER_SOLICIT: 216 printf("icmp6: router solicitation "); 217 if (vflag) { 218 #define RTSOLLEN 8 219 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 220 icmp6len - RTSOLLEN); 221 } 222 break; 223 case ND_ROUTER_ADVERT: 224 printf("icmp6: router advertisement"); 225 if (vflag) { 226 struct nd_router_advert *p; 227 228 p = (struct nd_router_advert *)dp; 229 TCHECK(p->nd_ra_retransmit); 230 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); 231 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) 232 printf("M"); 233 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) 234 printf("O"); 235 if (p->nd_ra_flags_reserved != 0) 236 printf(" "); 237 printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime)); 238 printf("reachable_time=%u, ", 239 (u_int32_t)ntohl(p->nd_ra_reachable)); 240 printf("retrans_time=%u)", 241 (u_int32_t)ntohl(p->nd_ra_retransmit)); 242 #define RTADVLEN 16 243 icmp6_opt_print((const u_char *)dp + RTADVLEN, 244 icmp6len - RTADVLEN); 245 } 246 break; 247 case ND_NEIGHBOR_SOLICIT: 248 { 249 struct nd_neighbor_solicit *p; 250 p = (struct nd_neighbor_solicit *)dp; 251 TCHECK(p->nd_ns_target); 252 printf("icmp6: neighbor sol: who has %s", 253 ip6addr_string(&p->nd_ns_target)); 254 if (vflag) { 255 #define NDSOLLEN 24 256 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 257 icmp6len - NDSOLLEN); 258 } 259 } 260 break; 261 case ND_NEIGHBOR_ADVERT: 262 { 263 struct nd_neighbor_advert *p; 264 265 p = (struct nd_neighbor_advert *)dp; 266 TCHECK(p->nd_na_target); 267 printf("icmp6: neighbor adv: tgt is %s", 268 ip6addr_string(&p->nd_na_target)); 269 if (vflag) { 270 #define ND_NA_FLAG_ALL \ 271 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) 272 /* we don't need ntohl() here. see advanced-api-04. */ 273 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { 274 #undef ND_NA_FLAG_ALL 275 u_int32_t flags; 276 277 flags = p->nd_na_flags_reserved; 278 printf("("); 279 if (flags & ND_NA_FLAG_ROUTER) 280 printf("R"); 281 if (flags & ND_NA_FLAG_SOLICITED) 282 printf("S"); 283 if (flags & ND_NA_FLAG_OVERRIDE) 284 printf("O"); 285 printf(")"); 286 } 287 #define NDADVLEN 24 288 icmp6_opt_print((const u_char *)dp + NDADVLEN, 289 icmp6len - NDADVLEN); 290 } 291 } 292 break; 293 case ND_REDIRECT: 294 { 295 #define RDR(i) ((struct nd_redirect *)(i)) 296 char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN]; 297 298 TCHECK(RDR(dp)->nd_rd_dst); 299 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target, 300 tgtbuf, INET6_ADDRSTRLEN); 301 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst, 302 dstbuf, INET6_ADDRSTRLEN); 303 printf("icmp6: redirect %s to %s", dstbuf, tgtbuf); 304 #define REDIRECTLEN 40 305 if (vflag) { 306 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 307 icmp6len - REDIRECTLEN); 308 } 309 break; 310 } 311 case ICMP6_ROUTER_RENUMBERING: 312 switch (dp->icmp6_code) { 313 case ICMP6_ROUTER_RENUMBERING_COMMAND: 314 printf("icmp6: router renum command"); 315 break; 316 case ICMP6_ROUTER_RENUMBERING_RESULT: 317 printf("icmp6: router renum result"); 318 break; 319 default: 320 printf("icmp6: router renum code-#%d", dp->icmp6_code); 321 break; 322 } 323 break; 324 #ifdef ICMP6_WRUREQUEST 325 case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/ 326 { 327 int siz; 328 siz = ep - (u_char *)(dp + 1); 329 if (siz == 4) 330 printf("icmp6: who-are-you request"); 331 else { 332 printf("icmp6: FQDN request"); 333 if (vflag) { 334 if (siz < 8) 335 printf("?(icmp6_data %d bytes)", siz); 336 else if (8 < siz) 337 printf("?(extra %d bytes)", siz - 8); 338 } 339 } 340 break; 341 } 342 #endif /*ICMP6_WRUREQUEST*/ 343 #ifdef ICMP6_WRUREPLY 344 case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/ 345 { 346 enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN; 347 u_char const *buf; 348 u_char const *cp = NULL; 349 350 buf = (u_char *)(dp + 1); 351 352 /* fair guess */ 353 if (buf[12] == ep - buf - 13) 354 mode = FQDN; 355 else if (dp->icmp6_code == 1) 356 mode = FQDN; 357 358 /* wild guess */ 359 if (mode == UNKNOWN) { 360 cp = buf + 4; 361 while (cp < ep) { 362 if (!isprint(*cp++)) 363 mode = FQDN; 364 } 365 } 366 #ifndef abs 367 #define abs(a) ((0 < (a)) ? (a) : -(a)) 368 #endif 369 if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13))) 370 mode = WRU; 371 if (mode == UNKNOWN) 372 mode = FQDN; 373 374 if (mode == WRU) { 375 cp = buf + 4; 376 printf("icmp6: who-are-you reply(\""); 377 } else if (mode == FQDN) { 378 cp = buf + 13; 379 printf("icmp6: FQDN reply(\""); 380 } 381 for (; cp < ep; cp++) 382 printf((isprint(*cp) ? "%c" : "\\%03o"), *cp); 383 printf("\""); 384 if (vflag) { 385 printf(",%s", mode == FQDN ? "FQDN" : "WRU"); 386 if (mode == FQDN) { 387 long ttl; 388 ttl = (long)ntohl(*(u_long *)&buf[8]); 389 if (dp->icmp6_code == 1) 390 printf(",TTL=unknown"); 391 else if (ttl < 0) 392 printf(",TTL=%ld:invalid", ttl); 393 else 394 printf(",TTL=%ld", ttl); 395 if (buf[12] != ep - buf - 13) { 396 (void)printf(",invalid namelen:%d/%u", 397 buf[12], 398 (unsigned int)(ep - buf - 13)); 399 } 400 } 401 } 402 printf(")"); 403 break; 404 } 405 #endif /*ICMP6_WRUREPLY*/ 406 default: 407 printf("icmp6: type-#%d", dp->icmp6_type); 408 break; 409 } 410 return; 411 trunc: 412 fputs("[|icmp6]", stdout); 413 #if 0 414 #undef TCHECK 415 #endif 416 } 417 418 void 419 icmp6_opt_print(register const u_char *bp, int resid) 420 { 421 register const struct nd_opt_hdr *op; 422 register const struct nd_opt_hdr *opl; /* why there's no struct? */ 423 register const struct nd_opt_prefix_info *opp; 424 register const struct icmp6_opts_redirect *opr; 425 register const struct nd_opt_mtu *opm; 426 register const u_char *ep; 427 int opts_len; 428 #if 0 429 register const struct ip6_hdr *ip; 430 register const char *str; 431 register const struct ip6_hdr *oip; 432 register const struct udphdr *ouh; 433 register int hlen, dport; 434 char buf[256]; 435 #endif 436 437 #if 0 438 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc 439 #endif 440 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 441 442 op = (struct nd_opt_hdr *)bp; 443 #if 0 444 ip = (struct ip6_hdr *)bp2; 445 oip = &dp->icmp6_ip6; 446 str = buf; 447 #endif 448 /* 'ep' points to the end of avaible data. */ 449 ep = snapend; 450 451 ECHECK(op->nd_opt_len); 452 if (resid <= 0) 453 return; 454 switch(op->nd_opt_type) { 455 case ND_OPT_SOURCE_LINKADDR: 456 opl = (struct nd_opt_hdr *)op; 457 #if 1 458 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) 459 goto trunc; 460 #else 461 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); 462 #endif 463 printf("(src lladdr: %s", 464 etheraddr_string((u_char *)(opl + 1))); 465 if (opl->nd_opt_len != 1) 466 printf("!"); 467 printf(")"); 468 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 469 resid - (op->nd_opt_len << 3)); 470 break; 471 case ND_OPT_TARGET_LINKADDR: 472 opl = (struct nd_opt_hdr *)op; 473 #if 1 474 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) 475 goto trunc; 476 #else 477 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); 478 #endif 479 printf("(tgt lladdr: %s", 480 etheraddr_string((u_char *)(opl + 1))); 481 if (opl->nd_opt_len != 1) 482 printf("!"); 483 printf(")"); 484 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 485 resid - (op->nd_opt_len << 3)); 486 break; 487 case ND_OPT_PREFIX_INFORMATION: 488 opp = (struct nd_opt_prefix_info *)op; 489 TCHECK(opp->nd_opt_pi_prefix); 490 printf("(prefix info: "); 491 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) 492 printf("L"); 493 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) 494 printf("A"); 495 if (opp->nd_opt_pi_flags_reserved) 496 printf(" "); 497 printf("valid_ltime="); 498 if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U) 499 printf("infinity"); 500 else { 501 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time)); 502 } 503 printf(", "); 504 printf("preffered_ltime="); 505 if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U) 506 printf("infinity"); 507 else { 508 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)); 509 } 510 printf(", "); 511 printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), 512 opp->nd_opt_pi_prefix_len); 513 if (opp->nd_opt_pi_len != 4) 514 printf("!"); 515 printf(")"); 516 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 517 resid - (op->nd_opt_len << 3)); 518 break; 519 case ND_OPT_REDIRECTED_HEADER: 520 opr = (struct icmp6_opts_redirect *)op; 521 printf("(redirect)"); 522 /* xxx */ 523 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 524 resid - (op->nd_opt_len << 3)); 525 break; 526 case ND_OPT_MTU: 527 opm = (struct nd_opt_mtu *)op; 528 TCHECK(opm->nd_opt_mtu_mtu); 529 printf("(mtu: "); 530 printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); 531 if (opm->nd_opt_mtu_len != 1) 532 printf("!"); 533 printf(")"); 534 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 535 resid - (op->nd_opt_len << 3)); 536 break; 537 default: 538 opts_len = op->nd_opt_len; 539 printf("(unknwon opt_type=%d, opt_len=%d)", 540 op->nd_opt_type, opts_len); 541 if (opts_len == 0) 542 opts_len = 1; /* XXX */ 543 icmp6_opt_print((const u_char *)op + (opts_len << 3), 544 resid - (opts_len << 3)); 545 break; 546 } 547 return; 548 trunc: 549 fputs("[ndp opt]", stdout); 550 return; 551 #if 0 552 #undef TCHECK 553 #endif 554 #undef ECHECK 555 } 556 557 void 558 mld6_print(register const u_char *bp) 559 { 560 register struct mld6_hdr *mp = (struct mld6_hdr *)bp; 561 register const u_char *ep; 562 563 /* 'ep' points to the end of avaible data. */ 564 ep = snapend; 565 566 if ((u_char *)mp + sizeof(*mp) > ep) 567 return; 568 569 printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay)); 570 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 571 572 return; 573 } 574 #endif /* INET6 */ 575