]> 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 1b47c89c6f9663c0351f53fe5ccac8f2a74e6666..2eab0ac706896e2bcfd84106310478ff1a4c5b89 100644 (file)
@@ -20,8 +20,8 @@
  */
 
 #ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.52 2001-06-01 04:08:57 itojun 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
@@ -30,26 +30,18 @@ static const char rcsid[] =
 
 #ifdef INET6
 
-#include <ctype.h>
-
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-
-#include <netinet/in.h>
-
-#include <arpa/inet.h>
+#include <tcpdump-stdinc.h>
 
 #include <stdio.h>
-#include <netdb.h>
+#include <string.h>
 
 #include "ip6.h"
 #include "icmp6.h"
+#include "ipproto.h"
 
 #include "interface.h"
 #include "addrtoname.h"
+#include "extract.h"
 
 #include "udp.h"
 #include "ah.h"
@@ -57,20 +49,29 @@ static const char rcsid[] =
 static const char *get_rtpref(u_int);
 static const char *get_lifetime(u_int32_t);
 static void print_lladdr(const u_char *, size_t);
-void icmp6_opt_print(const u_char *, int);
-void mld6_print(const u_char *);
-static struct udphdr *get_upperlayer(u_char *, int *);
+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 *);
-void icmp6_nodeinfo_print(int, const u_char *, const u_char *);
-void icmp6_rrenum_print(int, const u_char *, const u_char *);
+static void icmp6_nodeinfo_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
 
-#ifndef ND_RA_FLAG_RTPREF_MASK
-#define ND_RA_FLAG_RTPREF_MASK 0x18
-#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)
@@ -113,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;
@@ -124,11 +168,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
        int dport;
        const u_char *ep;
        char buf[256];
-       int icmp6len, prot;
-
-#if 0
-#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
-#endif
+       u_int prot;
 
        dp = (struct icmp6_hdr *)bp;
        ip = (struct ip6_hdr *)bp2;
@@ -136,19 +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 = (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);
+       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);
@@ -175,7 +217,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                            == NULL)
                                goto trunc;
 
-                       dport = ntohs(ouh->uh_dport);
+                       dport = EXTRACT_16BITS(&ouh->uh_dport);
                        switch (prot) {
                        case IPPROTO_TCP:
                                printf("icmp6: %s tcp port %s unreachable",
@@ -203,7 +245,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                break;
        case ICMP6_PACKET_TOO_BIG:
                TCHECK(dp->icmp6_mtu);
-               printf("icmp6: too big %u", (u_int32_t)ntohl(dp->icmp6_mtu));
+               printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu));
                break;
        case ICMP6_TIME_EXCEEDED:
                TCHECK(oip->ip6_dst);
@@ -226,15 +268,15 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                switch (dp->icmp6_code) {
                case ICMP6_PARAMPROB_HEADER:
                        printf("icmp6: parameter problem errorneous - octet %u",
-                               (u_int32_t)ntohl(dp->icmp6_pptr));
+                               EXTRACT_32BITS(&dp->icmp6_pptr));
                        break;
                case ICMP6_PARAMPROB_NEXTHEADER:
                        printf("icmp6: parameter problem next header - octet %u",
-                               (u_int32_t)ntohl(dp->icmp6_pptr));
+                               EXTRACT_32BITS(&dp->icmp6_pptr));
                        break;
                case ICMP6_PARAMPROB_OPTION:
                        printf("icmp6: parameter problem option - octet %u",
-                               (u_int32_t)ntohl(dp->icmp6_pptr));
+                               EXTRACT_32BITS(&dp->icmp6_pptr));
                        break;
                default:
                        printf("icmp6: parameter problem code-#%d",
@@ -243,14 +285,23 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                }
                break;
        case ICMP6_ECHO_REQUEST:
-               printf("icmp6: echo request");
-               break;
        case ICMP6_ECHO_REPLY:
-               printf("icmp6: echo reply");
+               TCHECK(dp->icmp6_seq);
+               printf("icmp6: echo %s seq %u",
+                       dp->icmp6_type == ICMP6_ECHO_REQUEST ?
+                       "request" : "reply",
+                       EXTRACT_16BITS(&dp->icmp6_seq));
                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 ");
@@ -265,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:
@@ -280,10 +331,7 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                                printf("M");
                        if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
                                printf("O");
-#ifndef ND_RA_FLAG_HA
-#define ND_RA_FLAG_HA  0x20
-#endif
-                       if (p->nd_ra_flags_reserved & ND_RA_FLAG_HA)
+                       if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)
                                printf("H");
 
                        if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK)
@@ -293,14 +341,14 @@ icmp6_print(const u_char *bp, const u_char *bp2)
                        printf("pref=%s, ",
                            get_rtpref(p->nd_ra_flags_reserved));
 
-                       printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
+                       printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime));
                        printf("reachable_time=%u, ",
-                               (u_int32_t)ntohl(p->nd_ra_reachable));
+                               EXTRACT_32BITS(&p->nd_ra_reachable));
                        printf("retrans_time=%u)",
-                               (u_int32_t)ntohl(p->nd_ra_retransmit));
+                               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:
@@ -313,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;
@@ -345,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
                }
            }
@@ -355,22 +403,81 @@ 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");
+               if (vflag) {
+                       TCHECK(dp->icmp6_data16[0]);
+                       printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+               }
+               break;
+       case ICMP6_HADISCOV_REPLY:
+               printf("icmp6: ha discovery reply");
+               if (vflag) {
+                       struct in6_addr *in6;
+                       u_char *cp;
+
+                       TCHECK(dp->icmp6_data16[0]);
+                       printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+                       cp = (u_char *)dp + length;
+                       in6 = (struct in6_addr *)(dp + 1);
+                       for (; (u_char *)in6 < cp; in6++) {
+                               TCHECK(*in6);
+                               printf(", %s", ip6addr_string(in6));
+                       }
+                       printf(")");
+               }
+               break;
+       case ICMP6_MOBILEPREFIX_SOLICIT:
+               printf("icmp6: mobile router solicitation");
+               if (vflag) {
+                       TCHECK(dp->icmp6_data16[0]);
+                       printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+               }
+               break;
+       case ICMP6_MOBILEPREFIX_ADVERT:
+               printf("icmp6: mobile router advertisement");
+               if (vflag) {
+                       TCHECK(dp->icmp6_data16[0]);
+                       printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+                       if (dp->icmp6_data16[1] & 0xc0)
+                               printf(" ");
+                       if (dp->icmp6_data16[1] & 0x80)
+                               printf("M");
+                       if (dp->icmp6_data16[1] & 0x40)
+                               printf("O");
+                       printf(")");
+#define MPADVLEN 8
+                       icmp6_opt_print((const u_char *)dp + MPADVLEN,
+                                       length - MPADVLEN);
+               }
                break;
        default:
                printf("icmp6: type-#%d", dp->icmp6_type);
@@ -379,13 +486,10 @@ icmp6_print(const u_char *bp, const u_char *bp2)
        return;
 trunc:
        fputs("[|icmp6]", stdout);
-#if 0
-#undef TCHECK
-#endif
 }
 
 static struct udphdr *
-get_upperlayer(u_char *bp, int *prot)
+get_upperlayer(u_char *bp, u_int *prot)
 {
        const u_char *ep;
        struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
@@ -393,12 +497,13 @@ get_upperlayer(u_char *bp, int *prot)
        struct ip6_hbh *hbh;
        struct ip6_frag *fragh;
        struct ah *ah;
-       int nh, hlen;
+       u_int nh;
+       int hlen;
 
        /* 'ep' points to the end of available data. */
        ep = snapend;
 
-       if (TTEST(ip6->ip6_nxt) == 0)
+       if (!TTEST(ip6->ip6_nxt))
                return NULL;
 
        nh = ip6->ip6_nxt;
@@ -423,7 +528,7 @@ get_upperlayer(u_char *bp, int *prot)
                case IPPROTO_DSTOPTS:
                case IPPROTO_ROUTING:
                        hbh = (struct ip6_hbh *)bp;
-                       if (TTEST(hbh->ip6h_len) == 0)
+                       if (!TTEST(hbh->ip6h_len))
                                return(NULL);
                        nh = hbh->ip6h_nxt;
                        hlen = (hbh->ip6h_len + 1) << 3;
@@ -431,10 +536,10 @@ get_upperlayer(u_char *bp, int *prot)
 
                case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
                        fragh = (struct ip6_frag *)bp;
-                       if (TTEST(fragh->ip6f_offlg) == 0)
+                       if (!TTEST(fragh->ip6f_offlg))
                                return(NULL);
                        /* fragments with non-zero offset are meaningless */
-                       if ((fragh->ip6f_offlg & IP6F_OFF_MASK) != 0)
+                       if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
                                return(NULL);
                        nh = fragh->ip6f_nxt;
                        hlen = sizeof(struct ip6_frag);
@@ -442,7 +547,7 @@ get_upperlayer(u_char *bp, int *prot)
 
                case IPPROTO_AH:
                        ah = (struct ah *)bp;
-                       if (TTEST(ah->ah_len) == 0)
+                       if (!TTEST(ah->ah_len))
                                return(NULL);
                        nh = ah->ah_nxt;
                        hlen = (ah->ah_len + 2) << 2;
@@ -457,7 +562,7 @@ get_upperlayer(u_char *bp, int *prot)
        return(NULL);           /* should be notreached, though */
 }
 
-void
+static void
 icmp6_opt_print(const u_char *bp, int resid)
 {
        const struct nd_opt_hdr *op;
@@ -466,6 +571,7 @@ icmp6_opt_print(const u_char *bp, int resid)
        const struct icmp6_opts_redirect *opr;
        const struct nd_opt_mtu *opm;
        const struct nd_opt_advinterval *opa;
+       const struct nd_opt_homeagent_info *oph;
        const struct nd_opt_route_info *opri;
        const u_char *cp, *ep;
        struct in6_addr in6, *in6p;
@@ -524,9 +630,9 @@ icmp6_opt_print(const u_char *bp, int resid)
                        if (opp->nd_opt_pi_flags_reserved)
                                printf(" ");
                        printf("valid_ltime=%s,",
-                           get_lifetime((u_int32_t)ntohl(opp->nd_opt_pi_valid_time)));
+                           get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
                        printf("preferred_ltime=%s,",
-                           get_lifetime((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)));
+                           get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
                        printf("prefix=%s/%d",
                            ip6addr_string(&opp->nd_opt_pi_prefix),
                            opp->nd_opt_pi_prefix_len);
@@ -550,7 +656,7 @@ icmp6_opt_print(const u_char *bp, int resid)
                                printf(")");
                                break;
                        }
-                       printf(" mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
+                       printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu));
                        if (opm->nd_opt_mtu_len != 1)
                                printf("!");
                        printf(")");
@@ -560,10 +666,18 @@ icmp6_opt_print(const u_char *bp, int resid)
                        TCHECK(opa->nd_opt_adv_interval);
                        printf("(advint:");     /*)*/
                        printf(" advint=%u",
-                           (u_int32_t)ntohl(opa->nd_opt_adv_interval));
+                           EXTRACT_32BITS(&opa->nd_opt_adv_interval));
                        /*(*/
                        printf(")");
-                       break;                
+                       break;
+               case ND_OPT_HOMEAGENT_INFO:
+                       oph = (struct nd_opt_homeagent_info *)op;
+                       TCHECK(oph->nd_opt_hai_lifetime);
+                       printf("(ha info:");    /*)*/
+                       printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference));
+                       printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
+                       printf(")");
+                       break;
                case ND_OPT_ROUTE_INFO:
                        opri = (struct nd_opt_route_info *)op;
                        TCHECK(opri->nd_opt_rti_lifetime);
@@ -588,12 +702,12 @@ icmp6_opt_print(const u_char *bp, int resid)
                            opri->nd_opt_rti_prefixlen);
                        printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
                        printf(", lifetime=%s",
-                           get_lifetime((u_int32_t)ntohl(opri->nd_opt_rti_lifetime)));
+                           get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
                        /*(*/
                        printf(")");
                        break;
                default:
-                       printf("(unknwon opt_type=%d, opt_len=%d)",
+                       printf("(unknown opt_type=%d, opt_len=%d)",
                               op->nd_opt_type, op->nd_opt_len);
                        break;
                }
@@ -609,7 +723,7 @@ icmp6_opt_print(const u_char *bp, int resid)
 #undef ECHECK
 }
 
-void
+static void
 mld6_print(const u_char *bp)
 {
        struct mld6_hdr *mp = (struct mld6_hdr *)bp;
@@ -621,11 +735,131 @@ mld6_print(const u_char *bp)
        if ((u_char *)mp + sizeof(*mp) > ep)
                return;
 
-       printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
+       printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
        printf("addr: %s", ip6addr_string(&mp->mld6_addr));
 }
 
 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;
@@ -661,15 +895,17 @@ dnsname_print(const u_char *cp, const u_char *ep)
        printf("\"");
 }
 
-void
-icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
+static void
+icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
 {
        struct icmp6_nodeinfo *ni6;
        struct icmp6_hdr *dp;
        const u_char *cp;
-       int siz, i;
+       size_t siz, i;
        int needcomma;
 
+       if (ep < bp)
+               return;
        dp = (struct icmp6_hdr *)bp;
        ni6 = (struct icmp6_nodeinfo *)bp;
        siz = ep - bp;
@@ -686,13 +922,13 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                TCHECK2(*dp, sizeof(*ni6));
                ni6 = (struct icmp6_nodeinfo *)dp;
                printf(" (");   /*)*/
-               switch (ntohs(ni6->ni_qtype)) {
+               switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
                case NI_QTYPE_NOOP:
                        printf("noop");
                        break;
                case NI_QTYPE_SUPTYPES:
                        printf("supported qtypes");
-                       i = ntohs(ni6->ni_flags);
+                       i = EXTRACT_16BITS(&ni6->ni_flags);
                        if (i)
                                printf(" [%s]", (i & 0x01) ? "C" : "");
                        break;
@@ -828,7 +1064,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                        break;
                }
 
-               switch (ntohs(ni6->ni_qtype)) {
+               switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
                case NI_QTYPE_NOOP:
                        if (needcomma)
                                printf(", ");
@@ -841,7 +1077,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                        if (needcomma)
                                printf(", ");
                        printf("supported qtypes");
-                       i = ntohs(ni6->ni_flags);
+                       i = EXTRACT_16BITS(&ni6->ni_flags);
                        if (i)
                                printf(" [%s]", (i & 0x01) ? "C" : "");
                        break;
@@ -863,7 +1099,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                                printf("\"");
                        } else
                                dnsname_print(cp, ep);
-                       if ((ntohs(ni6->ni_flags) & 0x01) != 0)
+                       if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
                                printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
                        break;
                case NI_QTYPE_NODEADDR:
@@ -876,7 +1112,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                                        break;
                                printf(" %s", getname6(bp + i));
                                i += sizeof(struct in6_addr);
-                               printf("(%d)", (int32_t)ntohl(*(int32_t *)(bp + i)));
+                               printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
                                i += sizeof(int32_t);
                        }
                        i = ni6->ni_flags;
@@ -908,8 +1144,8 @@ trunc:
        fputs("[|icmp6]", stdout);
 }
 
-void
-icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
+static void
+icmp6_rrenum_print(const u_char *bp, const u_char *ep)
 {
        struct icmp6_router_renum *rr6;
        struct icmp6_hdr *dp;
@@ -920,6 +1156,8 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
        char hbuf[NI_MAXHOST];
        int n;
 
+       if (ep < bp)
+               return;
        dp = (struct icmp6_hdr *)bp;
        rr6 = (struct icmp6_router_renum *)bp;
        siz = ep - bp;
@@ -941,7 +1179,7 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
                break;
        }
 
-       printf(", seq=%u", (u_int32_t)ntohl(rr6->rr_seqnum));
+       printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
 
        if (vflag) {
 #define F(x, y)        ((rr6->rr_flags) & (x) ? (y) : "")
@@ -956,7 +1194,7 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
                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("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
                /*[*/
                printf("]");
 #undef F
@@ -1021,12 +1259,12 @@ icmp6_rrenum_print(int icmp6len, const u_char *bp, const u_char *ep)
                                        printf("vltime=infty,");
                                else
                                        printf("vltime=%u,",
-                                           (u_int32_t)ntohl(use->rpu_vltime));
+                                           EXTRACT_32BITS(&use->rpu_vltime));
                                if (~use->rpu_pltime == 0)
                                        printf("pltime=infty,");
                                else
                                        printf("pltime=%u,",
-                                           (u_int32_t)ntohl(use->rpu_pltime));
+                                           EXTRACT_32BITS(&use->rpu_pltime));
                        }
                        if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
                            sizeof(hbuf)))