]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-icmp6.c
The stuff in the "linux-include" directory is no longer needed, as we no
[tcpdump] / print-icmp6.c
index b93abeb8a559450a2a69ae321eae65e9eca360a5..b3d8ef97e718aab5f192d8fcbaacd0dc47f48a0b 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.7 2000-04-28 11:46:12 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
@@ -37,43 +37,46 @@ static const char rcsid[] =
 #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 *);
+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 *);
+void icmp6_rrenum_print(int, const u_char *, const u_char *);
+
+#ifndef abs
+#define abs(a) ((0 < (a)) ? (a) : -(a))
+#endif
 
 void
 icmp6_print(register const u_char *bp, register const u_char *bp2)
 {
-       register const struct icmp6_hdr *dp;
+       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 int dport;
        register const u_char *ep;
        char buf[256];
-       int icmp6len;
+       int icmp6len, prot;
 
 #if 0
 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
@@ -83,7 +86,7 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
        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) -
@@ -110,11 +113,7 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
                        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));
@@ -124,11 +123,12 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
                               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),
@@ -292,148 +292,32 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
 #define NDADVLEN 24
                        icmp6_opt_print((const u_char *)dp + NDADVLEN,
                                        icmp6len - NDADVLEN);
+#undef 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);
+               printf("icmp6: redirect %s",
+                   getname6((const u_char *)&RDR(dp)->nd_rd_dst));
+               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);
                }
                break;
-       }
-#ifndef ICMP6_ROUTER_RENUMBERING
-#define ICMP6_ROUTER_RENUMBERING       138     /* router renumbering */
-#endif
+#undef REDIRECTLEN
+#undef RDR
        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;
-               }
-               break;
-#ifdef ICMP6_WRUREQUEST
-       case ICMP6_WRUREQUEST:  /*ICMP6_FQDN_QUERY*/
-           {
-               int siz;
-               siz = ep - (u_char *)(dp + 1);
-               if (icmp6len > ep - (u_char *)dp) {
-                       printf("[|icmp6: who-are-you/FQDN request]");
-                       break;
-               }
-               if (siz == 4)
-                       printf("icmp6: who-are-you request");
-               else {
-                       printf("icmp6: FQDN request");
-                       if (vflag && icmp6len == ep - (u_char *)dp) {
-                               if (siz < 8)
-                                       printf("?(icmp6_data %d bytes)", siz);
-                               else if (8 < siz)
-                                       printf("?(extra %d bytes)", siz - 8);
-                       }
-               }
+               icmp6_rrenum_print(icmp6len, bp, ep);
                break;
-           }
-#endif /*ICMP6_WRUREQUEST*/
-#ifdef ICMP6_WRUREPLY
-       case ICMP6_WRUREPLY:    /*ICMP6_FQDN_REPLY*/
-           {
-               enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN;
-               const u_char *buf;
-               const u_char *cp = NULL;
-               const char *modename = NULL;
-
-               buf = (u_char *)(dp + 1);
-
-               /* fair guess */
-               if (ep - buf > 12 && buf[12] == ep - buf - 13)
-                       mode = FQDN;
-               else if (dp->icmp6_code == 1)
-                       mode = FQDN;
-
-               /* wild guess */
-               if (mode == UNKNOWN && ep - buf > 4) {
-                       cp = buf + 4;
-                       while (cp < ep) {
-                               if (!isprint(*cp++))
-                                       mode = FQDN;
-                       }
-               }
-#ifndef abs
-#define abs(a) ((0 < (a)) ? (a) : -(a))
-#endif
-               if (mode == UNKNOWN && ep - buf > 12 &&
-                   2 < abs(buf[12] - (ep - buf - 13))) {
-                       mode = WRU;
-               }
-               if (mode == UNKNOWN)
-                       mode = FQDN;
-
-               if (mode == WRU) {
-                       if (ep - buf > 12 && buf[12] == ep - buf - 13)
-                               cp = buf + 4;
-                       else
-                               cp = ep + 1;    /*truncated*/
-                       modename = "icmp6: who-are-you reply";
-               } else if (mode == FQDN) {
-                       cp = buf + 13;
-                       modename = "icmp6: FQDN reply";
-               }
-               if (icmp6len > ep - (u_char *)dp) {
-                       printf("[|%s]", modename);
-                       break;
-               }
-               printf("%s", modename);
-               printf("(\"");  /*)*/
-               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(")");
+       case ICMP6_NI_QUERY:
+       case ICMP6_NI_REPLY:
+               icmp6_nodeinfo_print(icmp6len, bp, ep);
                break;
-           }
-#endif /*ICMP6_WRUREPLY*/
        default:
                printf("icmp6: type-#%d", dp->icmp6_type);
                break;
@@ -446,6 +330,79 @@ trunc:
 #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)
 {
@@ -454,6 +411,7 @@ 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
@@ -465,9 +423,6 @@ icmp6_opt_print(register const u_char *bp, int resid)
        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;
@@ -476,7 +431,7 @@ icmp6_opt_print(register const u_char *bp, int resid)
        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);
@@ -522,9 +477,11 @@ icmp6_opt_print(register const u_char *bp, int resid)
                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=");
@@ -568,6 +525,17 @@ icmp6_opt_print(register const u_char *bp, int resid)
                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)",
@@ -582,20 +550,16 @@ icmp6_opt_print(register const u_char *bp, int resid)
  trunc:
        fputs("[ndp opt]", stdout);
        return;
-#if 0
-#undef TCHECK
-#endif
 #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)
@@ -605,28 +569,425 @@ mld6_print(register const u_char *bp)
        printf("addr: %s", ip6addr_string(&mp->mld6_addr));
 }
 
-#elif defined(HAVE_STRUCT_ICMP6_MLD)
+static void
+dnsname_print(const u_char *cp, const u_char *ep)
+{
+       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("\"");
+}
 
 void
-mld6_print(register const u_char *bp)
+icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
 {
-       register struct icmp6_mld *mp = (struct icmp6_mld *)bp;
-       register const u_char *ep;
+       struct icmp6_nodeinfo *ni6;
+       struct icmp6_hdr *dp;
+       const u_char *cp;
+       int siz, i;
+       int needcomma;
 
-       /* 'ep' points to the end of avaible data. */
-       ep = snapend;
+       dp = (struct icmp6_hdr *)bp;
+       ni6 = (struct icmp6_nodeinfo *)bp;
+       siz = ep - bp;
 
-       if ((u_char *)mp + sizeof(*mp) > ep)
-               return;
+       switch (ni6->ni_type) {
+       case ICMP6_NI_QUERY:
+               if (siz == sizeof(*dp) + 4) {
+                       /* KAME who-are-you */
+                       printf("icmp6: who-are-you request");
+                       break;
+               }
+               printf("icmp6: node information query");
+
+               TCHECK2(*dp, sizeof(*ni6));
+               ni6 = (struct icmp6_nodeinfo *)dp;
+               printf(" (");   /*)*/
+               switch (ntohs(ni6->ni_qtype)) {
+               case NI_QTYPE_NOOP:
+                       printf("noop");
+                       break;
+               case NI_QTYPE_SUPTYPES:
+                       printf("supported qtypes");
+                       i = ntohs(ni6->ni_flags);
+                       if (i)
+                               printf(" [%s]", (i & 0x01) ? "C" : "");
+                       break;
+                       break;
+               case NI_QTYPE_FQDN:
+                       printf("DNS name");
+                       break;
+               case NI_QTYPE_NODEADDR:
+                       printf("node addresses");
+                       i = ni6->ni_flags;
+                       if (!i)
+                               break;
+                       /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */
+                       printf(" [%s%s%s%s%s%s]",
+                           (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
+                           (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
+                           (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
+                           (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
+                           (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
+                           (i & NI_NODEADDR_FLAG_ALL) ? "A" : "");
+                       break;
+               default:
+                       printf("unknown");
+                       break;
+               }
+
+               if (ni6->ni_qtype == NI_QTYPE_NOOP ||
+                   ni6->ni_qtype == NI_QTYPE_SUPTYPES) {
+                       if (siz != sizeof(*ni6))
+                               if (vflag)
+                                       printf(", invalid len");
+                       /*(*/
+                       printf(")");
+                       break;
+               }
+
+
+               /* XXX backward compat, icmp-name-lookup-03 */
+               if (siz == sizeof(*ni6)) {
+                       printf(", 03 draft");
+                       /*(*/
+                       printf(")");
+                       break;
+               }
+
+               switch (ni6->ni_code) {
+               case ICMP6_NI_SUBJ_IPV6:
+                       if (!TTEST2(*dp,
+                           sizeof(*ni6) + sizeof(struct in6_addr)))
+                               break;
+                       if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) {
+                               if (vflag)
+                                       printf(", invalid subject len");
+                               break;
+                       }
+                       printf(", subject=%s",
+                           getname6((const u_char *)(ni6 + 1)));
+                       break;
+               case ICMP6_NI_SUBJ_FQDN:
+                       printf(", subject=DNS name");
+                       cp = (const u_char *)(ni6 + 1);
+                       if (cp[0] == ep - cp - 1) {
+                               /* icmp-name-lookup-03, pascal string */
+                               if (vflag)
+                                       printf(", 03 draft");
+                               cp++;
+                               printf(", \"");
+                               while (cp < ep) {
+                                       safeputchar(*cp);
+                                       cp++;
+                               }
+                               printf("\"");
+                       } else
+                               dnsname_print(cp, ep);
+                       break;
+               case ICMP6_NI_SUBJ_IPV4:
+                       if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr)))
+                               break;
+                       if (siz != sizeof(*ni6) + sizeof(struct in_addr)) {
+                               if (vflag)
+                                       printf(", invalid subject len");
+                               break;
+                       }
+                       printf(", subject=%s",
+                           getname((const u_char *)(ni6 + 1)));
+                       break;
+               default:
+                       printf(", unknown subject");
+                       break;
+               }
+
+               /*(*/
+               printf(")");
+               break;
+
+       case ICMP6_NI_REPLY:
+               if (icmp6len > siz) {
+                       printf("[|icmp6: node information reply]");
+                       break;
+               }
+
+               needcomma = 0;
+
+               ni6 = (struct icmp6_nodeinfo *)dp;
+               printf("icmp6: node information reply");
+               printf(" (");   /*)*/
+               switch (ni6->ni_code) {
+               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_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 (needcomma)
+                               printf(", ");
+                       printf("DNS name");
+                       cp = (const u_char *)(ni6 + 1) + 4;
+                       if (cp[0] == ep - cp - 1) {
+                               /* icmp-name-lookup-03, pascal string */
+                               if (vflag)
+                                       printf(", 03 draft");
+                               cp++;
+                               printf(", \"");
+                               while (cp < ep) {
+                                       safeputchar(*cp);
+                                       cp++;
+                               }
+                               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");
+                       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)
+                               break;
+                       printf(" [%s%s%s%s%s%s%s]",
+                           (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "",
+                           (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "",
+                           (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "",
+                           (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "",
+                           (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "",
+                           (i & NI_NODEADDR_FLAG_ALL) ? "A" : "",
+                           (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : "");
+                       break;
+               default:
+                       if (needcomma)
+                               printf(", ");
+                       printf("unknown");
+                       break;
+               }
+
+               /*(*/
+               printf(")");
+               break;
+       }
+       return;
 
-       printf("max resp delay: %d ", ntohs(mp->icmp6m_hdr.icmp6_maxdelay));
-       printf("addr: %s", ip6addr_string(&mp->icmp6m_group));
+trunc:
+       fputs("[|icmp6]", stdout);
 }
 
-#else
+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;
+       }
 
-#error unknown mld6 struct
+       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
+       }
 
-#endif
+       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 */