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