#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.8 2000-05-10 08:20:52 itojun Exp $";
+ "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.42 2000-12-13 07:57:05 itojun Exp $";
#endif
#ifdef HAVE_CONFIG_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 <netdb.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
+#include "ip6.h"
+#include "icmp6.h"
#include "interface.h"
#include "addrtoname.h"
+#include "udp.h"
+#include "ah.h"
+
void icmp6_opt_print(const u_char *, int);
void mld6_print(const u_char *);
-#ifdef HAVE_STRUCT_ICMP6_NODEINFO
+static struct udphdr *get_upperlayer(u_char *, int *);
+static void dnsname_print(const u_char *, const u_char *);
void icmp6_nodeinfo_print(int, const u_char *, const u_char *);
-#endif
+void icmp6_rrenum_print(int, const u_char *, const u_char *);
#ifndef abs
#define abs(a) ((0 < (a)) ? (a) : -(a))
#endif
-#ifndef HAVE_STRUCT_ICMP6_NODEINFO
-struct icmp6_nodeinfo {
- struct icmp6_hdr icmp6_ni_hdr;
- u_int8_t icmp6_ni_nonce[8];
- /* could be followed by reply data */
-};
-
-#define ni_type icmp6_ni_hdr.icmp6_type
-#define ni_code icmp6_ni_hdr.icmp6_code
-#define ni_cksum icmp6_ni_hdr.icmp6_cksum
-#define ni_qtype icmp6_ni_hdr.icmp6_data16[0]
-#define ni_flags icmp6_ni_hdr.icmp6_data16[1]
-#endif
-
-#ifndef ICMP6_NI_SUCCESS
-#define ICMP6_NI_SUCESS 0 /* node information successful reply */
-#define ICMP6_NI_REFUSED 1 /* node information request is refused */
-#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
-#endif
-
-#ifdef NI_QTYPE_NOOP
-#define NI_QTYPE_NOOP 0 /* NOOP */
-#define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */
-#define NI_QTYPE_FQDN 2 /* FQDN */
-#define NI_QTYPE_NODEADDR 3 /* Node Addresses. XXX: spec says 2, but it may be a typo... */
-#endif
-
-#ifndef ICMP6_NI_SUBJ_IPV6
-#define ICMP6_NI_SUBJ_IPV6 0 /* Query Subject is an IPv6 address */
-#define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */
-#define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */
-#endif
-
void
icmp6_print(register const u_char *bp, register const u_char *bp2)
{
register const char *str;
register const struct ip6_hdr *oip;
register const struct udphdr *ouh;
- register int hlen, dport;
+ register int dport;
register const u_char *ep;
char buf[256];
- int icmp6len;
- struct icmp6_nodeinfo *ni6;
+ int icmp6len, prot;
#if 0
#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
ip = (struct ip6_hdr *)bp2;
oip = (struct ip6_hdr *)(dp + 1);
str = buf;
- /* 'ep' points to the end of avaible data. */
+ /* 'ep' points to the end of available data. */
ep = snapend;
if (ip->ip6_plen)
icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
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));
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);
+ if ((ouh = get_upperlayer((u_char *)oip, &prot))
+ == NULL)
+ goto trunc;
+
dport = ntohs(ouh->uh_dport);
- switch (oip->ip6_nxt) {
+ switch (prot) {
case IPPROTO_TCP:
printf("icmp6: %s tcp port %s unreachable",
ip6addr_string(&oip->ip6_dst),
break;
#undef REDIRECTLEN
#undef RDR
-#ifndef ICMP6_ROUTER_RENUMBERING
-#define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */
-#endif
case ICMP6_ROUTER_RENUMBERING:
- switch (dp->icmp6_code) {
-#ifndef ICMP6_ROUTER_RENUMBERING_COMMAND
-#define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */
-#endif
- case ICMP6_ROUTER_RENUMBERING_COMMAND:
- printf("icmp6: router renum command");
- break;
-#ifndef ICMP6_ROUTER_RENUMBERING_RESULT
-#define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */
-#endif
- case ICMP6_ROUTER_RENUMBERING_RESULT:
- printf("icmp6: router renum result");
- break;
- default:
- printf("icmp6: router renum code-#%d", dp->icmp6_code);
- break;
- }
+ icmp6_rrenum_print(icmp6len, bp, ep);
break;
-#ifdef HAVE_STRUCT_ICMP6_NODEINFO
-#ifndef ICMP6_NI_QUERY
-#define ICMP6_NI_QUERY 139
-#endif
case ICMP6_NI_QUERY:
- icmp6_nodeinfo_print(icmp6len, bp, ep);
- break;
-#ifndef ICMP6_NI_REPLY
-#define ICMP6_NI_REPLY 140
-#endif
case ICMP6_NI_REPLY:
icmp6_nodeinfo_print(icmp6len, bp, ep);
break;
-#endif
default:
printf("icmp6: type-#%d", dp->icmp6_type);
break;
#endif
}
+static struct udphdr *
+get_upperlayer(register u_char *bp, int *prot)
+{
+ register const u_char *ep;
+ struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
+ struct udphdr *uh;
+ struct ip6_hbh *hbh;
+ struct ip6_frag *fragh;
+ struct ah *ah;
+ int nh, hlen;
+
+ /* 'ep' points to the end of available data. */
+ ep = snapend;
+
+ if (TTEST(ip6->ip6_nxt) == 0)
+ return NULL;
+
+ nh = ip6->ip6_nxt;
+ hlen = sizeof(struct ip6_hdr);
+
+ while (bp < snapend) {
+ bp += hlen;
+
+ switch(nh) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ uh = (struct udphdr *)bp;
+ if (TTEST(uh->uh_dport)) {
+ *prot = nh;
+ return(uh);
+ }
+ else
+ return(NULL);
+ /* NOTREACHED */
+
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_DSTOPTS:
+ case IPPROTO_ROUTING:
+ hbh = (struct ip6_hbh *)bp;
+ if (TTEST(hbh->ip6h_len) == 0)
+ return(NULL);
+ nh = hbh->ip6h_nxt;
+ hlen = (hbh->ip6h_len + 1) << 3;
+ break;
+
+ case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
+ fragh = (struct ip6_frag *)bp;
+ if (TTEST(fragh->ip6f_offlg) == 0)
+ return(NULL);
+ /* fragments with non-zero offset are meaningless */
+ if ((fragh->ip6f_offlg & IP6F_OFF_MASK) != 0)
+ return(NULL);
+ nh = fragh->ip6f_nxt;
+ hlen = sizeof(struct ip6_frag);
+ break;
+
+ case IPPROTO_AH:
+ ah = (struct ah *)bp;
+ if (TTEST(ah->ah_len) == 0)
+ return(NULL);
+ nh = ah->ah_nxt;
+ hlen = (ah->ah_len + 2) << 2;
+ break;
+
+ default: /* unknown or undecodable header */
+ *prot = nh; /* meaningless, but set here anyway */
+ return(NULL);
+ }
+ }
+
+ return(NULL); /* should be notreached, though */
+}
+
void
icmp6_opt_print(register const u_char *bp, int resid)
{
register const struct nd_opt_prefix_info *opp;
register const struct icmp6_opts_redirect *opr;
register const struct nd_opt_mtu *opm;
+ register const struct nd_opt_advint *opa;
register const u_char *ep;
int opts_len;
#if 0
oip = &dp->icmp6_ip6;
str = buf;
#endif
- /* 'ep' points to the end of avaible data. */
+ /* 'ep' points to the end of available data. */
ep = snapend;
ECHECK(op->nd_opt_len);
TCHECK(opp->nd_opt_pi_prefix);
printf("(prefix info: "); /*)*/
if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
- printf("L");
+ printf("L");
if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
- printf("A");
+ printf("A");
+ if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER)
+ printf("R");
if (opp->nd_opt_pi_flags_reserved)
printf(" ");
printf("valid_ltime=");
icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
resid - (op->nd_opt_len << 3));
break;
+ case ND_OPT_ADVINT:
+ opa = (struct nd_opt_advint *)op;
+ TCHECK(opa->nd_opt_advint_advint);
+ printf("(advint: "); /*)*/
+ printf("advint=%u",
+ (u_int32_t)ntohl(opa->nd_opt_advint_advint));
+ /*(*/
+ 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)",
#undef ECHECK
}
-#if defined(HAVE_STRUCT_MLD6_HDR)
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' points to the end of available data. */
ep = snapend;
if ((u_char *)mp + sizeof(*mp) > ep)
printf("addr: %s", ip6addr_string(&mp->mld6_addr));
}
-#elif defined(HAVE_STRUCT_ICMP6_MLD)
-
-void
-mld6_print(register const u_char *bp)
+static void
+dnsname_print(const u_char *cp, const u_char *ep)
{
- register struct icmp6_mld *mp = (struct icmp6_mld *)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->icmp6m_hdr.icmp6_maxdelay));
- printf("addr: %s", ip6addr_string(&mp->icmp6m_group));
+ int i;
+
+ /* DNS name decoding - no decompression */
+ printf(", \"");
+ while (cp < ep) {
+ i = *cp++;
+ if (i) {
+ if (i > ep - cp) {
+ printf("???");
+ break;
+ }
+ while (i-- && cp < ep) {
+ safeputchar(*cp);
+ cp++;
+ }
+ if (cp + 1 < ep && *cp)
+ printf(".");
+ } else {
+ if (cp == ep) {
+ /* FQDN */
+ printf(".");
+ } else if (cp + 1 == ep && *cp == '\0') {
+ /* truncated */
+ } else {
+ /* invalid */
+ printf("???");
+ }
+ break;
+ }
+ }
+ printf("\"");
}
-#else
-
-#error unknown mld6 struct
-
-#endif
-
-#ifdef HAVE_STRUCT_ICMP6_NODEINFO
void
icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
{
-#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c)
struct icmp6_nodeinfo *ni6;
struct icmp6_hdr *dp;
const u_char *cp;
int siz, i;
+ int needcomma;
dp = (struct icmp6_hdr *)bp;
ni6 = (struct icmp6_nodeinfo *)bp;
break;
case ICMP6_NI_SUBJ_FQDN:
printf(", subject=DNS name");
- cp = (const u_char *)(ni6 + 1) + 4;
+ cp = (const u_char *)(ni6 + 1);
if (cp[0] == ep - cp - 1) {
/* icmp-name-lookup-03, pascal string */
if (vflag)
cp++;
printf(", \"");
while (cp < ep) {
- safeputc(*cp);
+ safeputchar(*cp);
cp++;
}
printf("\"");
- } else {
- /* DNS name decoding - no decompression */
- printf(", \"");
- while (cp < ep) {
- i = *cp++;
- while (i-- && cp < ep) {
- safeputc(*cp);
- cp++;
- }
- printf(".");
- }
- printf("\"");
- }
+ } else
+ dnsname_print(cp, ep);
break;
case ICMP6_NI_SUBJ_IPV4:
if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
break;
}
+ needcomma = 0;
+
ni6 = (struct icmp6_nodeinfo *)dp;
- printf("icmp6: node information query");
+ printf("icmp6: node information reply");
printf(" ("); /*)*/
switch (ni6->ni_code) {
- case ICMP6_NI_SUCESS:
+ case ICMP6_NI_SUCCESS:
+ if (vflag) {
+ printf("success");
+ needcomma++;
+ }
break;
case ICMP6_NI_REFUSED:
printf("refused");
+ needcomma++;
if (siz != sizeof(*ni6))
if (vflag)
printf(", invalid length");
break;
case ICMP6_NI_UNKNOWN:
printf("unknown");
+ needcomma++;
if (siz != sizeof(*ni6))
if (vflag)
printf(", invalid length");
break;
}
- if (ni6->ni_code != ICMP6_NI_SUCESS) {
+ if (ni6->ni_code != ICMP6_NI_SUCCESS) {
/*(*/
printf(")");
break;
switch (ntohs(ni6->ni_qtype)) {
case NI_QTYPE_NOOP:
+ if (needcomma)
+ printf(", ");
printf("noop");
if (siz != sizeof(*ni6))
if (vflag)
printf(", invalid length");
break;
case NI_QTYPE_SUPTYPES:
+ if (needcomma)
+ printf(", ");
printf("supported qtypes");
i = ntohs(ni6->ni_flags);
if (i)
printf(" [%s]", (i & 0x01) ? "C" : "");
break;
case NI_QTYPE_FQDN:
- if (vflag)
- printf("DNS name");
+ if (needcomma)
+ printf(", ");
+ printf("DNS name");
cp = (const u_char *)(ni6 + 1) + 4;
if (cp[0] == ep - cp - 1) {
/* icmp-name-lookup-03, pascal string */
cp++;
printf(", \"");
while (cp < ep) {
- safeputc(*cp);
+ safeputchar(*cp);
cp++;
}
printf("\"");
- } else {
- /* DNS name decoding - no decompression */
- printf(", \"");
- while (cp < ep) {
- i = *cp++;
- while (i-- && cp < ep) {
- safeputc(*cp);
- cp++;
- }
- printf(".");
- }
- printf("\"");
- }
+ } else
+ dnsname_print(cp, ep);
if ((ntohs(ni6->ni_flags) & 0x01) != 0)
printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
break;
case NI_QTYPE_NODEADDR:
+ if (needcomma)
+ printf(", ");
printf("node addresses");
- for (i = sizeof(*ni6);
- i < siz;
- i += sizeof(struct in6_addr)) {
+ i = sizeof(*ni6);
+ while (i < siz) {
+ if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz)
+ break;
printf(" %s", getname6(bp + i));
+ i += sizeof(struct in6_addr);
+ printf("(%d)", ntohl(*(int32_t *)(bp + i)));
+ i += sizeof(int32_t);
}
i = ni6->ni_flags;
if (!i)
(i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
break;
default:
+ if (needcomma)
+ printf(", ");
printf("unknown");
break;
}
trunc:
fputs("[|icmp6]", stdout);
-#undef safeputc
}
-#endif
+
+void
+icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
+{
+ struct icmp6_router_renum *rr6;
+ struct icmp6_hdr *dp;
+ size_t siz;
+ const char *cp;
+ struct rr_pco_match *match;
+ struct rr_pco_use *use;
+ char hbuf[NI_MAXHOST];
+ int n;
+
+ dp = (struct icmp6_hdr *)bp;
+ rr6 = (struct icmp6_router_renum *)bp;
+ siz = ep - bp;
+ cp = (const char *)(rr6 + 1);
+
+ TCHECK(rr6->rr_reserved);
+ switch (rr6->rr_code) {
+ case ICMP6_ROUTER_RENUMBERING_COMMAND:
+ printf("router renum: command");
+ break;
+ case ICMP6_ROUTER_RENUMBERING_RESULT:
+ printf("router renum: result");
+ break;
+ case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
+ printf("router renum: sequence number reset");
+ break;
+ default:
+ printf("router renum: code-#%d", rr6->rr_code);
+ break;
+ }
+
+ printf(", seq=%u", (u_int32_t)ntohl(rr6->rr_seqnum));
+
+ if (vflag) {
+#define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "")
+ printf("["); /*]*/
+ if (rr6->rr_flags) {
+ printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
+ F(ICMP6_RR_FLAGS_REQRESULT, "R"),
+ F(ICMP6_RR_FLAGS_ALLIF, "A"),
+ F(ICMP6_RR_FLAGS_SPECSITE, "S"),
+ F(ICMP6_RR_FLAGS_PREVDONE, "P"));
+ }
+ printf("seg=%u,", rr6->rr_segnum);
+ printf("maxdelay=%u", rr6->rr_maxdelay);
+ if (rr6->rr_reserved)
+ printf("rsvd=0x%x", (u_int16_t)ntohs(rr6->rr_reserved));
+ /*[*/
+ printf("]");
+#undef F
+ }
+
+ if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
+ match = (struct rr_pco_match *)cp;
+ cp = (const char *)(match + 1);
+
+ TCHECK(match->rpm_prefix);
+
+ if (vflag)
+ printf("\n\t");
+ else
+ printf(" ");
+ printf("match("); /*)*/
+ switch (match->rpm_code) {
+ case RPM_PCO_ADD: printf("add"); break;
+ case RPM_PCO_CHANGE: printf("change"); break;
+ case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
+ default: printf("#%u", match->rpm_code); break;
+ }
+
+ if (vflag) {
+ printf(",ord=%u", match->rpm_ordinal);
+ printf(",min=%u", match->rpm_minlen);
+ printf(",max=%u", match->rpm_maxlen);
+ }
+ if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
+ printf(",%s/%u", hbuf, match->rpm_matchlen);
+ else
+ printf(",?/%u", match->rpm_matchlen);
+ /*(*/
+ printf(")");
+
+ n = match->rpm_len - 3;
+ if (n % 4)
+ goto trunc;
+ n /= 4;
+ while (n-- > 0) {
+ use = (struct rr_pco_use *)cp;
+ cp = (const char *)(use + 1);
+
+ TCHECK(use->rpu_prefix);
+
+ if (vflag)
+ printf("\n\t");
+ else
+ printf(" ");
+ printf("use("); /*)*/
+ if (use->rpu_flags) {
+#define F(x, y) ((use->rpu_flags) & (x) ? (y) : "")
+ printf("%s%s,",
+ F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
+ F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
+#undef F
+ }
+ if (vflag) {
+ printf("mask=0x%x,", use->rpu_ramask);
+ printf("raflags=0x%x,", use->rpu_raflags);
+ if (~use->rpu_vltime == 0)
+ printf("vltime=infty,");
+ else
+ printf("vltime=%u,",
+ (u_int32_t)ntohl(use->rpu_vltime));
+ if (~use->rpu_pltime == 0)
+ printf("pltime=infty,");
+ else
+ printf("pltime=%u,",
+ (u_int32_t)ntohl(use->rpu_pltime));
+ }
+ if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
+ sizeof(hbuf)))
+ printf("%s/%u/%u", hbuf, use->rpu_uselen,
+ use->rpu_keeplen);
+ else
+ printf("?/%u/%u", use->rpu_uselen,
+ use->rpu_keeplen);
+ /*(*/
+ printf(")");
+ }
+ }
+
+ return;
+
+trunc:
+ fputs("[|icmp6]", stdout);
+}
#endif /* INET6 */