summaryrefslogtreecommitdiff
path: root/usr.sbin/tcpdump/print-icmp6.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/tcpdump/print-icmp6.c')
-rw-r--r--usr.sbin/tcpdump/print-icmp6.c572
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 */