]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-icmp6.c
When checking for pcap_if_t, add $V_INCLS to CFLAGS, so we look at the
[tcpdump] / print-icmp6.c
index ce7474f9fe27a2a297cb203e1a8e6cf5e8caed07..2eab0ac706896e2bcfd84106310478ff1a4c5b89 100644 (file)
@@ -20,8 +20,8 @@
  */
 
 #ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.69 2003-03-13 07:36:56 guy Exp $";
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.77 2004-06-16 00:06:28 guy Exp $";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -37,6 +37,7 @@ static const char rcsid[] =
 
 #include "ip6.h"
 #include "icmp6.h"
+#include "ipproto.h"
 
 #include "interface.h"
 #include "addrtoname.h"
@@ -50,15 +51,28 @@ static const char *get_lifetime(u_int32_t);
 static void print_lladdr(const u_char *, size_t);
 static void icmp6_opt_print(const u_char *, int);
 static void mld6_print(const u_char *);
+static void mldv2_report_print(const u_char *, u_int);
+static void mldv2_query_print(const u_char *, u_int);
 static struct udphdr *get_upperlayer(u_char *, u_int *);
 static void dnsname_print(const u_char *, const u_char *);
 static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
-static void icmp6_rrenum_print(u_int, const u_char *, const u_char *);
+static void icmp6_rrenum_print(const u_char *, const u_char *);
 
 #ifndef abs
 #define abs(a) ((0 < (a)) ? (a) : -(a))
 #endif
 
+/* 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 }
+};
+
 static const char *
 get_rtpref(u_int v)
 {
@@ -100,8 +114,51 @@ print_lladdr(const u_int8_t *p, size_t l)
        }
 }
 
+static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
+       u_int len)
+{
+       size_t i;
+       register const u_int16_t *sp;
+       u_int32_t sum;
+       union {
+               struct {
+                       struct in6_addr ph_src;
+                       struct in6_addr ph_dst;
+                       u_int32_t       ph_len;
+                       u_int8_t        ph_zero[3];
+                       u_int8_t        ph_nxt;
+               } ph;
+               u_int16_t pa[20];
+       } phu;
+
+       /* pseudo-header */
+       memset(&phu, 0, sizeof(phu));
+       phu.ph.ph_src = ip6->ip6_src;
+       phu.ph.ph_dst = ip6->ip6_dst;
+       phu.ph.ph_len = htonl(len);
+       phu.ph.ph_nxt = IPPROTO_ICMPV6;
+
+       sum = 0;
+       for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
+               sum += phu.pa[i];
+
+       sp = (const u_int16_t *)icp;
+
+       for (i = 0; i < (len & ~1); i += 2)
+               sum += *sp++;
+
+       if (len & 1)
+               sum += htons((*(const u_int8_t *)sp) << 8);
+
+       while (sum > 0xffff)
+               sum = (sum & 0xffff) + (sum >> 16);
+       sum = ~sum & 0xffff;
+
+       return (sum);
+}
+
 void
-icmp6_print(const u_char *bp, const u_char *bp2)
+icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
 {
        const struct icmp6_hdr *dp;
        const struct ip6_hdr *ip;
@@ -111,7 +168,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
        int dport;
        const u_char *ep;
        char buf[256];
-       u_int icmp6len, prot;
+       u_int prot;
 
        dp = (struct icmp6_hdr *)bp;
        ip = (struct ip6_hdr *)bp2;
@@ -119,13 +176,21 @@ icmp6_print(const u_char *bp, const u_char *bp2)
        str = buf;
        /* 'ep' points to the end of available data. */
        ep = snapend;
-       if (ip->ip6_plen)
-               icmp6len = (EXTRACT_16BITS(&ip->ip6_plen) + sizeof(struct ip6_hdr) -
-                           (bp - bp2));
-       else                    /* XXX: jumbo payload case... */
-               icmp6len = snapend - bp;
 
-       TCHECK(dp->icmp6_code);
+       TCHECK(dp->icmp6_cksum);
+
+       if (vflag && !fragmented) {
+               int sum = dp->icmp6_cksum;
+
+               if (TTEST2(bp[0], length)) {
+                       sum = icmp6_cksum(ip, dp, length);
+                       if (sum != 0)
+                               (void)printf("[bad icmp6 cksum %x!] ", sum);
+                       else
+                               (void)printf("[icmp6 sum ok] ");
+               }
+       }
+
        switch (dp->icmp6_type) {
        case ICMP6_DST_UNREACH:
                TCHECK(oip->ip6_dst);
@@ -229,7 +294,14 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                break;
        case ICMP6_MEMBERSHIP_QUERY:
                printf("icmp6: multicast listener query ");
-               mld6_print((const u_char *)dp);
+               if (length == MLD_MINLEN) {
+                       mld6_print((const u_char *)dp);
+               } else if (length >= MLDV2_MINLEN) {
+                       printf("v2 ");
+                       mldv2_query_print((const u_char *)dp, length);
+               } else {
+                       printf(" unknown-version(len=%d) ", length);
+               }
                break;
        case ICMP6_MEMBERSHIP_REPORT:
                printf("icmp6: multicast listener report ");
@@ -244,7 +316,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                if (vflag) {
 #define RTSOLLEN 8
                        icmp6_opt_print((const u_char *)dp + RTSOLLEN,
-                                       icmp6len - RTSOLLEN);
+                                       length - RTSOLLEN);
                }
                break;
        case ND_ROUTER_ADVERT:
@@ -276,7 +348,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                                EXTRACT_32BITS(&p->nd_ra_retransmit));
 #define RTADVLEN 16
                        icmp6_opt_print((const u_char *)dp + RTADVLEN,
-                                       icmp6len - RTADVLEN);
+                                       length - RTADVLEN);
                }
                break;
        case ND_NEIGHBOR_SOLICIT:
@@ -289,7 +361,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                if (vflag) {
 #define NDSOLLEN 24
                        icmp6_opt_print((const u_char *)dp + NDSOLLEN,
-                                       icmp6len - NDSOLLEN);
+                                       length - NDSOLLEN);
                }
            }
                break;
@@ -321,7 +393,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                        }
 #define NDADVLEN 24
                        icmp6_opt_print((const u_char *)dp + NDADVLEN,
-                                       icmp6len - NDADVLEN);
+                                       length - NDADVLEN);
 #undef NDADVLEN
                }
            }
@@ -331,22 +403,33 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                TCHECK(RDR(dp)->nd_rd_dst);
                printf("icmp6: redirect %s",
                    getname6((const u_char *)&RDR(dp)->nd_rd_dst));
+               TCHECK(RDR(dp)->nd_rd_target);
                printf(" to %s",
                    getname6((const u_char*)&RDR(dp)->nd_rd_target));
 #define REDIRECTLEN 40
                if (vflag) {
                        icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
-                                       icmp6len - REDIRECTLEN);
+                                       length - REDIRECTLEN);
                }
                break;
 #undef REDIRECTLEN
 #undef RDR
        case ICMP6_ROUTER_RENUMBERING:
-               icmp6_rrenum_print(icmp6len, bp, ep);
+               icmp6_rrenum_print(bp, ep);
                break;
        case ICMP6_NI_QUERY:
        case ICMP6_NI_REPLY:
-               icmp6_nodeinfo_print(icmp6len, bp, ep);
+               icmp6_nodeinfo_print(length, bp, ep);
+               break;
+       case IND_SOLICIT:
+               printf("icmp6: inverse neighbor solicitation");
+               break;
+       case IND_ADVERT:
+               printf("icmp6: inverse neighbor advertisement");
+               break;
+       case ICMP6_V2_MEMBERSHIP_REPORT:
+               printf("icmp6: multicast listener report v2 ");
+               mldv2_report_print((const u_char *) dp, length);
                break;
        case ICMP6_HADISCOV_REQUEST:
                printf("icmp6: ha discovery request");
@@ -363,7 +446,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
 
                        TCHECK(dp->icmp6_data16[0]);
                        printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
-                       cp = (u_char *)dp + icmp6len;
+                       cp = (u_char *)dp + length;
                        in6 = (struct in6_addr *)(dp + 1);
                        for (; (u_char *)in6 < cp; in6++) {
                                TCHECK(*in6);
@@ -393,7 +476,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                        printf(")");
 #define MPADVLEN 8
                        icmp6_opt_print((const u_char *)dp + MPADVLEN,
-                                       icmp6len - MPADVLEN);
+                                       length - MPADVLEN);
                }
                break;
        default:
@@ -657,6 +740,126 @@ mld6_print(const u_char *bp)
 }
 
 static 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;
+
+    /* Minimum len is 8 */
+    if (len < 8) {
+       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 = 8;
+        for (i = 0; i < ngroups; i++) {
+           /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
+           if (len < group + 20) {
+               printf(" [invalid number of groups]");
+               return;
+           }
+            TCHECK(bp[group + 4]);
+            printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
+           printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
+                                                               bp[group]));
+            nsrcs = (bp[group + 2] << 8) + bp[group + 3];
+           /* Check the number of sources and print them */
+           if (len < group + 20 + (nsrcs * 16)) {
+               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 + 20 + j * 16], 16);
+                   printf(" %s", ip6addr_string(&bp[group + 20 + j * 16]));
+               }
+                (void)printf(" }");
+            }
+           /* Next group record */
+            group += 20 + nsrcs * 16;
+           printf("]");
+        }
+    }
+    return;
+trunc:
+    (void)printf("[|icmp6]");
+    return;
+}
+
+static void
+mldv2_query_print(const u_char *bp, u_int len)
+{
+    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
+    u_int mrc;
+    int mrt, qqi;
+    u_int nsrcs;
+    register u_int i;
+
+    /* Minimum len is 28 */
+    if (len < 28) {
+       printf(" [invalid len %d]", len);
+       return;
+    }
+    TCHECK(icp->icmp6_data16[0]);
+    mrc = ntohs(icp->icmp6_data16[0]);
+    if (mrc < 32768) {
+       mrt = mrc;
+    } else {
+        mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
+    }
+    if (vflag) {
+       (void)printf(" [max resp delay=%d]", mrt);
+    }
+    printf(" [gaddr %s", ip6addr_string(&bp[8]));
+
+    if (vflag) {
+        TCHECK(bp[25]);
+       if (bp[24] & 0x08) {
+               printf(" sflag");
+       }
+       if (bp[24] & 0x07) {
+               printf(" robustness=%d", bp[24] & 0x07);
+       }
+       if (bp[25] < 128) {
+               qqi = bp[25];
+       } else {
+               qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
+       }
+       printf(" qqi=%d", qqi);
+    }
+
+    nsrcs = ntohs(*(u_short *)&bp[26]);
+    if (nsrcs > 0) {
+       if (len < 28 + nsrcs * 16)
+           printf(" [invalid number of sources]");
+       else if (vflag > 1) {
+           printf(" {");
+           for (i = 0; i < nsrcs; i++) {
+               TCHECK2(bp[28 + i * 16], 16);
+               printf(" %s", ip6addr_string(&bp[28 + i * 16]));
+           }
+           printf(" }");
+       } else
+           printf(", %d source(s)", nsrcs);
+    }
+    printf("]");
+    return;
+trunc:
+    (void)printf("[|icmp6]");
+    return;
+}
+
+void
 dnsname_print(const u_char *cp, const u_char *ep)
 {
        int i;
@@ -942,7 +1145,7 @@ trunc:
 }
 
 static void
-icmp6_rrenum_print(u_int icmp6len, const u_char *bp, const u_char *ep)
+icmp6_rrenum_print(const u_char *bp, const u_char *ep)
 {
        struct icmp6_router_renum *rr6;
        struct icmp6_hdr *dp;