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