diff options
Diffstat (limited to 'usr.sbin/tcpdump/print-icmp6.c')
-rw-r--r-- | usr.sbin/tcpdump/print-icmp6.c | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/usr.sbin/tcpdump/print-icmp6.c b/usr.sbin/tcpdump/print-icmp6.c new file mode 100644 index 00000000000..f60cb846179 --- /dev/null +++ b/usr.sbin/tcpdump/print-icmp6.c @@ -0,0 +1,572 @@ +/* $OpenBSD: print-icmp6.c,v 1.1 2000/04/26 21:35:40 jakob Exp $ */ + +/* + * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static const char rcsid[] = + "@(#) /master/usr.sbin/tcpdump/tcpdump/print-icmp.c,v 2.1 1995/02/03 18:14:42 polk Exp (LBL)"; +#endif + +#ifdef INET6 + +#include <ctype.h> + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <net/if.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> + +#include <arpa/inet.h> + +#include <stdio.h> + +#include <netinet/ip6.h> +#include <netinet/icmp6.h> + +#include "interface.h" +#include "addrtoname.h" + +void icmp6_opt_print(const u_char *, int); +void mld6_print(const u_char *); + +void +icmp6_print(register const u_char *bp, register const u_char *bp2) +{ + register const struct icmp6_hdr *dp; + register const struct ip6_hdr *ip; + register const char *str; + register const struct ip6_hdr *oip; + register const struct udphdr *ouh; + register int hlen, dport; + register const u_char *ep; + char buf[256]; + int icmp6len; + +#if 0 +#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc +#endif + + dp = (struct icmp6_hdr *)bp; + ip = (struct ip6_hdr *)bp2; + oip = (struct ip6_hdr *)(dp + 1); + str = buf; + /* 'ep' points to the end of avaible data. */ + ep = snapend; + if (ip->ip6_plen) + icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) - + (bp - bp2)); + else /* XXX: jumbo payload case... */ + icmp6len = snapend - bp; + +#if 0 + (void)printf("%s > %s: ", + ip6addr_string(&ip->ip6_src), + ip6addr_string(&ip->ip6_dst)); +#endif + + TCHECK(dp->icmp6_code); + switch (dp->icmp6_type) { + case ICMP6_DST_UNREACH: + TCHECK(oip->ip6_dst); + switch (dp->icmp6_code) { + case ICMP6_DST_UNREACH_NOROUTE: + printf("icmp6: %s unreachable route", + ip6addr_string(&oip->ip6_dst)); + break; + case ICMP6_DST_UNREACH_ADMIN: + printf("icmp6: %s unreachable prohibited", + ip6addr_string(&oip->ip6_dst)); + break; +#ifdef ICMP6_DST_UNREACH_BEYONDSCOPE + case ICMP6_DST_UNREACH_BEYONDSCOPE: +#else + case ICMP6_DST_UNREACH_NOTNEIGHBOR: +#endif + printf("icmp6: %s beyond scope of source address %s", + ip6addr_string(&oip->ip6_dst), + ip6addr_string(&oip->ip6_src)); + break; + case ICMP6_DST_UNREACH_ADDR: + printf("icmp6: %s unreachable address", + ip6addr_string(&oip->ip6_dst)); + break; + case ICMP6_DST_UNREACH_NOPORT: + TCHECK(oip->ip6_nxt); + hlen = sizeof(struct ip6_hdr); + ouh = (struct udphdr *)(((u_char *)oip) + hlen); + dport = ntohs(ouh->uh_dport); + switch (oip->ip6_nxt) { + case IPPROTO_TCP: + printf("icmp6: %s tcp port %s unreachable", + ip6addr_string(&oip->ip6_dst), + tcpport_string(dport)); + break; + case IPPROTO_UDP: + printf("icmp6: %s udp port %s unreachable", + ip6addr_string(&oip->ip6_dst), + udpport_string(dport)); + break; + default: + printf("icmp6: %s protocol %d port %d unreachable", + ip6addr_string(&oip->ip6_dst), + oip->ip6_nxt, dport); + break; + } + break; + default: + printf("icmp6: %s unreachable code-#%d", + ip6addr_string(&oip->ip6_dst), + dp->icmp6_code); + break; + } + break; + case ICMP6_PACKET_TOO_BIG: + TCHECK(dp->icmp6_mtu); + printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu)); + break; + case ICMP6_TIME_EXCEEDED: + TCHECK(oip->ip6_dst); + switch (dp->icmp6_code) { + case ICMP6_TIME_EXCEED_TRANSIT: + printf("icmp6: time exceeded in-transit for %s", + ip6addr_string(&oip->ip6_dst)); + break; + case ICMP6_TIME_EXCEED_REASSEMBLY: + printf("icmp6: ip6 reassembly time exceeded"); + break; + default: + printf("icmp6: time exceeded code-#%d", + dp->icmp6_code); + break; + } + break; + case ICMP6_PARAM_PROB: + TCHECK(oip->ip6_dst); + switch (dp->icmp6_code) { + case ICMP6_PARAMPROB_HEADER: + printf("icmp6: parameter problem errorneous - octet %u\n", + (u_int32_t)ntohl(dp->icmp6_pptr)); + break; + case ICMP6_PARAMPROB_NEXTHEADER: + printf("icmp6: parameter problem next header - octet %u\n", + (u_int32_t)ntohl(dp->icmp6_pptr)); + break; + case ICMP6_PARAMPROB_OPTION: + printf("icmp6: parameter problem option - octet %u\n", + (u_int32_t)ntohl(dp->icmp6_pptr)); + break; + default: + printf("icmp6: parameter problem code-#%d", + dp->icmp6_code); + break; + } + break; + case ICMP6_ECHO_REQUEST: + printf("icmp6: echo request"); + break; + case ICMP6_ECHO_REPLY: + printf("icmp6: echo reply"); + break; + case ICMP6_MEMBERSHIP_QUERY: + printf("icmp6: multicast listener query "); + mld6_print((const u_char *)dp); + break; + case ICMP6_MEMBERSHIP_REPORT: + printf("icmp6: multicast listener report "); + mld6_print((const u_char *)dp); + break; + case ICMP6_MEMBERSHIP_REDUCTION: + printf("icmp6: multicast listener done "); + mld6_print((const u_char *)dp); + break; + case ND_ROUTER_SOLICIT: + printf("icmp6: router solicitation "); + if (vflag) { +#define RTSOLLEN 8 + icmp6_opt_print((const u_char *)dp + RTSOLLEN, + icmp6len - RTSOLLEN); + } + break; + case ND_ROUTER_ADVERT: + printf("icmp6: router advertisement"); + if (vflag) { + struct nd_router_advert *p; + + p = (struct nd_router_advert *)dp; + TCHECK(p->nd_ra_retransmit); + printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); + if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) + printf("M"); + if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) + printf("O"); + if (p->nd_ra_flags_reserved != 0) + printf(" "); + printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime)); + printf("reachable_time=%u, ", + (u_int32_t)ntohl(p->nd_ra_reachable)); + printf("retrans_time=%u)", + (u_int32_t)ntohl(p->nd_ra_retransmit)); +#define RTADVLEN 16 + icmp6_opt_print((const u_char *)dp + RTADVLEN, + icmp6len - RTADVLEN); + } + break; + case ND_NEIGHBOR_SOLICIT: + { + struct nd_neighbor_solicit *p; + p = (struct nd_neighbor_solicit *)dp; + TCHECK(p->nd_ns_target); + printf("icmp6: neighbor sol: who has %s", + ip6addr_string(&p->nd_ns_target)); + if (vflag) { +#define NDSOLLEN 24 + icmp6_opt_print((const u_char *)dp + NDSOLLEN, + icmp6len - NDSOLLEN); + } + } + break; + case ND_NEIGHBOR_ADVERT: + { + struct nd_neighbor_advert *p; + + p = (struct nd_neighbor_advert *)dp; + TCHECK(p->nd_na_target); + printf("icmp6: neighbor adv: tgt is %s", + ip6addr_string(&p->nd_na_target)); + if (vflag) { +#define ND_NA_FLAG_ALL \ + (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) + /* we don't need ntohl() here. see advanced-api-04. */ + if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { +#undef ND_NA_FLAG_ALL + u_int32_t flags; + + flags = p->nd_na_flags_reserved; + printf("("); + if (flags & ND_NA_FLAG_ROUTER) + printf("R"); + if (flags & ND_NA_FLAG_SOLICITED) + printf("S"); + if (flags & ND_NA_FLAG_OVERRIDE) + printf("O"); + printf(")"); + } +#define NDADVLEN 24 + icmp6_opt_print((const u_char *)dp + NDADVLEN, + icmp6len - NDADVLEN); + } + } + break; + case ND_REDIRECT: + { +#define RDR(i) ((struct nd_redirect *)(i)) + char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN]; + + TCHECK(RDR(dp)->nd_rd_dst); + inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target, + tgtbuf, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst, + dstbuf, INET6_ADDRSTRLEN); + printf("icmp6: redirect %s to %s", dstbuf, tgtbuf); +#define REDIRECTLEN 40 + if (vflag) { + icmp6_opt_print((const u_char *)dp + REDIRECTLEN, + icmp6len - REDIRECTLEN); + } + break; + } + case ICMP6_ROUTER_RENUMBERING: + switch (dp->icmp6_code) { + case ICMP6_ROUTER_RENUMBERING_COMMAND: + printf("icmp6: router renum command"); + break; + case ICMP6_ROUTER_RENUMBERING_RESULT: + printf("icmp6: router renum result"); + break; + default: + printf("icmp6: router renum code-#%d", dp->icmp6_code); + break; + } + break; +#ifdef ICMP6_WRUREQUEST + case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/ + { + int siz; + siz = ep - (u_char *)(dp + 1); + if (siz == 4) + printf("icmp6: who-are-you request"); + else { + printf("icmp6: FQDN request"); + if (vflag) { + if (siz < 8) + printf("?(icmp6_data %d bytes)", siz); + else if (8 < siz) + printf("?(extra %d bytes)", siz - 8); + } + } + break; + } +#endif /*ICMP6_WRUREQUEST*/ +#ifdef ICMP6_WRUREPLY + case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/ + { + enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN; + u_char const *buf; + u_char const *cp = NULL; + + buf = (u_char *)(dp + 1); + + /* fair guess */ + if (buf[12] == ep - buf - 13) + mode = FQDN; + else if (dp->icmp6_code == 1) + mode = FQDN; + + /* wild guess */ + if (mode == UNKNOWN) { + cp = buf + 4; + while (cp < ep) { + if (!isprint(*cp++)) + mode = FQDN; + } + } +#ifndef abs +#define abs(a) ((0 < (a)) ? (a) : -(a)) +#endif + if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13))) + mode = WRU; + if (mode == UNKNOWN) + mode = FQDN; + + if (mode == WRU) { + cp = buf + 4; + printf("icmp6: who-are-you reply(\""); + } else if (mode == FQDN) { + cp = buf + 13; + printf("icmp6: FQDN reply(\""); + } + for (; cp < ep; cp++) + printf((isprint(*cp) ? "%c" : "\\%03o"), *cp); + printf("\""); + if (vflag) { + printf(",%s", mode == FQDN ? "FQDN" : "WRU"); + if (mode == FQDN) { + long ttl; + ttl = (long)ntohl(*(u_long *)&buf[8]); + if (dp->icmp6_code == 1) + printf(",TTL=unknown"); + else if (ttl < 0) + printf(",TTL=%ld:invalid", ttl); + else + printf(",TTL=%ld", ttl); + if (buf[12] != ep - buf - 13) { + (void)printf(",invalid namelen:%d/%u", + buf[12], + (unsigned int)(ep - buf - 13)); + } + } + } + printf(")"); + break; + } +#endif /*ICMP6_WRUREPLY*/ + default: + printf("icmp6: type-#%d", dp->icmp6_type); + break; + } + return; +trunc: + fputs("[|icmp6]", stdout); +#if 0 +#undef TCHECK +#endif +} + +void +icmp6_opt_print(register const u_char *bp, int resid) +{ + register const struct nd_opt_hdr *op; + register const struct nd_opt_hdr *opl; /* why there's no struct? */ + register const struct nd_opt_prefix_info *opp; + register const struct icmp6_opts_redirect *opr; + register const struct nd_opt_mtu *opm; + register const u_char *ep; + int opts_len; +#if 0 + register const struct ip6_hdr *ip; + register const char *str; + register const struct ip6_hdr *oip; + register const struct udphdr *ouh; + register int hlen, dport; + char buf[256]; +#endif + +#if 0 +#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc +#endif +#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return + + op = (struct nd_opt_hdr *)bp; +#if 0 + ip = (struct ip6_hdr *)bp2; + oip = &dp->icmp6_ip6; + str = buf; +#endif + /* 'ep' points to the end of avaible data. */ + ep = snapend; + + ECHECK(op->nd_opt_len); + if (resid <= 0) + return; + switch (op->nd_opt_type) { + case ND_OPT_SOURCE_LINKADDR: + opl = (struct nd_opt_hdr *)op; +#if 1 + if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) + goto trunc; +#else + TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); +#endif + printf("(src lladdr: %s", + etheraddr_string((u_char *)(opl + 1))); + if (opl->nd_opt_len != 1) + printf("!"); + printf(")"); + icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), + resid - (op->nd_opt_len << 3)); + break; + case ND_OPT_TARGET_LINKADDR: + opl = (struct nd_opt_hdr *)op; +#if 1 + if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) + goto trunc; +#else + TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); +#endif + printf("(tgt lladdr: %s", + etheraddr_string((u_char *)(opl + 1))); + if (opl->nd_opt_len != 1) + printf("!"); + printf(")"); + icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), + resid - (op->nd_opt_len << 3)); + break; + case ND_OPT_PREFIX_INFORMATION: + opp = (struct nd_opt_prefix_info *)op; + TCHECK(opp->nd_opt_pi_prefix); + printf("(prefix info: "); + if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) + printf("L"); + if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) + printf("A"); + if (opp->nd_opt_pi_flags_reserved) + printf(" "); + printf("valid_ltime="); + if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U) + printf("infinity"); + else { + printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time)); + } + printf(", "); + printf("preffered_ltime="); + if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U) + printf("infinity"); + else { + printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)); + } + printf(", "); + printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), + opp->nd_opt_pi_prefix_len); + if (opp->nd_opt_pi_len != 4) + printf("!"); + printf(")"); + icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), + resid - (op->nd_opt_len << 3)); + break; + case ND_OPT_REDIRECTED_HEADER: + opr = (struct icmp6_opts_redirect *)op; + printf("(redirect)"); + /* xxx */ + icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), + resid - (op->nd_opt_len << 3)); + break; + case ND_OPT_MTU: + opm = (struct nd_opt_mtu *)op; + TCHECK(opm->nd_opt_mtu_mtu); + printf("(mtu: "); + printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); + if (opm->nd_opt_mtu_len != 1) + printf("!"); + printf(")"); + icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), + resid - (op->nd_opt_len << 3)); + break; + default: + opts_len = op->nd_opt_len; + printf("(unknwon opt_type=%d, opt_len=%d)", + op->nd_opt_type, opts_len); + if (opts_len == 0) + opts_len = 1; /* XXX */ + icmp6_opt_print((const u_char *)op + (opts_len << 3), + resid - (opts_len << 3)); + break; + } + return; + trunc: + fputs("[ndp opt]", stdout); + return; +#if 0 +#undef TCHECK +#endif +#undef ECHECK +} + +void +mld6_print(register const u_char *bp) +{ + register struct mld6_hdr *mp = (struct mld6_hdr *)bp; + register const u_char *ep; + + /* 'ep' points to the end of avaible data. */ + ep = snapend; + + if ((u_char *)mp + sizeof(*mp) > ep) + return; + + printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay)); + printf("addr: %s", ip6addr_string(&mp->mld6_addr)); + + return; +} +#endif /* INET6 */ |