summaryrefslogtreecommitdiffstats
path: root/usr.sbin/tcpdump/print-icmp6.c
diff options
context:
space:
mode:
authorjsg <jsg@openbsd.org>2010-04-06 16:01:57 +0000
committerjsg <jsg@openbsd.org>2010-04-06 16:01:57 +0000
commitacb63ff2e1f4fe8746769e153e472054575a19ca (patch)
tree46ca37b80f3342f96a944b29c5e64ec351f5a17c /usr.sbin/tcpdump/print-icmp6.c
parentA fix for the PCI-X check so that this is only tested on controllers (diff)
downloadwireguard-openbsd-acb63ff2e1f4fe8746769e153e472054575a19ca.tar.xz
wireguard-openbsd-acb63ff2e1f4fe8746769e153e472054575a19ca.zip
Add support for decoding MLDv2 initially from tcpdump.org via FreeBSD,
cleaned up to be less gross after some suggestions from stsp. ok stsp@
Diffstat (limited to 'usr.sbin/tcpdump/print-icmp6.c')
-rw-r--r--usr.sbin/tcpdump/print-icmp6.c196
1 files changed, 193 insertions, 3 deletions
diff --git a/usr.sbin/tcpdump/print-icmp6.c b/usr.sbin/tcpdump/print-icmp6.c
index 2d5803a2d16..dffec6c35cf 100644
--- a/usr.sbin/tcpdump/print-icmp6.c
+++ b/usr.sbin/tcpdump/print-icmp6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: print-icmp6.c,v 1.7 2009/10/27 23:59:55 deraadt Exp $ */
+/* $OpenBSD: print-icmp6.c,v 1.8 2010/04/06 16:01:57 jsg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
@@ -48,15 +48,52 @@
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
+#include <netinet6/mld6.h>
#include "interface.h"
#include "addrtoname.h"
void icmp6_opt_print(const u_char *, int);
void mld6_print(const u_char *);
+void mldv2_query_print(const u_char *, u_int);
+void mldv2_report_print(const u_char *, u_int);
+
+/* mldv2 report types */
+static struct tok mldv2report2str[] = {
+ { 1, "is_in" },
+ { 2, "is_ex" },
+ { 3, "to_in" },
+ { 4, "to_ex" },
+ { 5, "allow" },
+ { 6, "block" },
+ { 0, NULL }
+};
+
+#define MLDV2_QUERY_QRV 24
+#define MLDV2_QUERY_QQIC 25
+#define MLDV2_QUERY_NSRCS 26
+#define MLDV2_QUERY_SRC0 28
+
+#define MLDV2_QUERY_QRV_SFLAG (1 << 3)
+
+#define MLD_V1_QUERY_MINLEN 24
+
+#define MLDV2_REPORT_GROUP0 8
+
+#define MLDV2_REPORT_MINLEN 8
+#define MLDV2_REPORT_MINGRPLEN 20
+
+#define MLDV2_RGROUP_NSRCS 2
+#define MLDV2_RGROUP_MADDR 4
+
+#define MLDV2_MRC_FLOAT (1 << 15)
+#define MLDV2_MRD(mant, exp) ((mant | 0x1000) << (exp + 3))
+
+#define MLDV2_QQIC_FLOAT (1 << 7)
+#define MLDV2_QQI(mant, exp) ((mant | 0x10) << (exp + 3))
void
-icmp6_print(register const u_char *bp, register const u_char *bp2)
+icmp6_print(const u_char *bp, u_int length, const u_char *bp2)
{
register const struct icmp6_hdr *dp;
register const struct ip6_hdr *ip;
@@ -196,7 +233,14 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
break;
case ICMP6_MEMBERSHIP_QUERY:
printf("icmp6: multicast listener query ");
- mld6_print((const u_char *)dp);
+ if (length == MLD_V1_QUERY_MINLEN) {
+ mld6_print((const u_char *)dp);
+ } else if (length >= MLD_V2_QUERY_MINLEN) {
+ printf("v2 ");
+ mldv2_query_print((const u_char *)dp, length);
+ } else {
+ printf("unknown-version (len %u) ", length);
+ }
break;
case ICMP6_MEMBERSHIP_REPORT:
printf("icmp6: multicast listener report ");
@@ -397,6 +441,10 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
break;
}
#endif /*ICMP6_WRUREPLY*/
+ case MLDV2_LISTENER_REPORT:
+ printf("multicast listener report v2");
+ mldv2_report_print((const u_char *) dp, length);
+ break;
default:
printf("icmp6: type-#%d", dp->icmp6_type);
break;
@@ -569,4 +617,146 @@ mld6_print(register const u_char *bp)
return;
}
+
+void
+mldv2_report_print(const u_char *bp, u_int len)
+{
+ struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
+ u_int group, nsrcs, ngroups;
+ u_int i, j;
+
+ if (len < MLDV2_REPORT_MINLEN) {
+ printf(" [invalid len %d]", len);
+ return;
+ }
+
+ TCHECK(icp->icmp6_data16[1]);
+ ngroups = ntohs(icp->icmp6_data16[1]);
+ printf(", %d group record(s)", ngroups);
+ if (vflag > 0) {
+ /* Print the group records */
+ group = MLDV2_REPORT_GROUP0;
+ for (i = 0; i < ngroups; i++) {
+ /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
+ if (len < group + MLDV2_REPORT_MINGRPLEN) {
+ printf(" [invalid number of groups]");
+ return;
+ }
+ TCHECK2(bp[group + MLDV2_RGROUP_MADDR],
+ sizeof(struct in6_addr));
+ printf(" [gaddr %s",
+ ip6addr_string(&bp[group + MLDV2_RGROUP_MADDR]));
+ printf(" %s", tok2str(mldv2report2str,
+ " [v2-report-#%d]", bp[group]));
+ nsrcs = (bp[group + MLDV2_RGROUP_NSRCS] << 8) +
+ bp[group + MLDV2_RGROUP_NSRCS + 1];
+ /* Check the number of sources and print them */
+ if (len < group + MLDV2_REPORT_MINGRPLEN +
+ (nsrcs * sizeof(struct in6_addr))) {
+ printf(" [invalid number of sources %d]", nsrcs);
+ return;
+ }
+ if (vflag == 1)
+ printf(", %d source(s)", nsrcs);
+ else {
+ /* Print the sources */
+ (void)printf(" {");
+ for (j = 0; j < nsrcs; j++) {
+ TCHECK2(bp[group +
+ MLDV2_REPORT_MINGRPLEN +
+ j * sizeof(struct in6_addr)],
+ sizeof(struct in6_addr));
+ printf(" %s", ip6addr_string(&bp[group +
+ MLDV2_REPORT_MINGRPLEN + j *
+ sizeof(struct in6_addr)]));
+ }
+ (void)printf(" }");
+ }
+ /* Next group record */
+ group += MLDV2_REPORT_MINGRPLEN + nsrcs *
+ sizeof(struct in6_addr);
+ printf("]");
+ }
+ }
+ return;
+trunc:
+ (void)printf("[|icmp6]");
+ return;
+}
+
+void
+mldv2_query_print(const u_char *bp, u_int len)
+{
+ struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
+ u_int mrc, qqic;
+ int mrd, qqi;
+ int mant, exp;
+ u_int nsrcs;
+ u_int i;
+
+ if (len < MLD_V2_QUERY_MINLEN) {
+ printf(" [invalid len %d]", len);
+ return;
+ }
+ TCHECK(icp->icmp6_data16[0]);
+ mrc = ntohs(icp->icmp6_data16[0]);
+ if (mrc & MLDV2_MRC_FLOAT) {
+ mant = MLD_MRC_MANT(mrc);
+ exp = MLD_MRC_EXP(mrc);
+ mrd = MLDV2_MRD(mant, exp);
+ } else {
+ mrd = mrc;
+ }
+ if (vflag) {
+ (void)printf(" [max resp delay=%d]", mrd);
+ }
+ TCHECK2(bp[8], sizeof(struct in6_addr));
+ printf(" [gaddr %s", ip6addr_string(&bp[8]));
+
+ if (vflag) {
+ TCHECK(bp[MLDV2_QUERY_QQIC]);
+ if (bp[MLDV2_QUERY_QRV] & MLDV2_QUERY_QRV_SFLAG) {
+ printf(" sflag");
+ }
+ if (MLD_QRV(bp[MLDV2_QUERY_QRV])) {
+ printf(" robustness=%d", MLD_QRV(bp[MLDV2_QUERY_QRV]));
+ }
+ qqic = bp[MLDV2_QUERY_QQIC];
+ if (qqic & MLDV2_QQIC_FLOAT) {
+ mant = MLD_QQIC_MANT(qqic);
+ exp = MLD_QQIC_EXP(qqic);
+ qqi = MLDV2_QQI(mant, exp);
+ } else {
+ qqi = bp[MLDV2_QUERY_QQIC];
+ }
+ printf(" qqi=%d", qqi);
+ }
+
+ TCHECK2(bp[MLDV2_QUERY_NSRCS], 2);
+ nsrcs = ntohs(*(u_short *)&bp[MLDV2_QUERY_NSRCS]);
+ if (nsrcs > 0) {
+ if (len < MLD_V2_QUERY_MINLEN + nsrcs * sizeof(struct in6_addr))
+ printf(" [invalid number of sources]");
+ else if (vflag > 1) {
+ printf(" {");
+ for (i = 0; i < nsrcs; i++) {
+ TCHECK2(bp[MLDV2_QUERY_SRC0 + i *
+ sizeof(struct in6_addr)],
+ sizeof(struct in6_addr));
+ printf(" %s",
+ ip6addr_string(&bp[MLDV2_QUERY_SRC0 + i *
+ sizeof(struct in6_addr)]));
+ }
+ printf(" }");
+ } else
+ printf(", %d source(s)", nsrcs);
+ }
+ printf("]");
+ return;
+trunc:
+ (void)printf("[|icmp6]");
+ return;
+}
+
+
#endif /* INET6 */