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