X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/c25493a5b51c8d891282ff7456643036ecff133b..ffa1470e5c7ff0e50028d085a481dc797b0b51ed:/print-icmp6.c diff --git a/print-icmp6.c b/print-icmp6.c index 485d0bbe..5bf0f7e1 100644 --- a/print-icmp6.c +++ b/print-icmp6.c @@ -20,8 +20,8 @@ */ #ifndef lint -static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.21 2000-08-30 14:28:44 itojun Exp $"; +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.79.2.6 2005-09-05 09:29:28 guy Exp $"; #endif #ifdef HAVE_CONFIG_H @@ -30,191 +30,316 @@ static const char rcsid[] = #ifdef INET6 -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include #include - -#include -#include +#include #include "interface.h" #include "addrtoname.h" +#include "extract.h" + +#include "ip6.h" +#include "icmp6.h" +#include "ipproto.h" -void icmp6_opt_print(const u_char *, int); -void mld6_print(const u_char *); -#ifdef HAVE_STRUCT_ICMP6_NODEINFO +#include "udp.h" +#include "ah.h" + +static const char *get_rtpref(u_int); +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 *); -void icmp6_nodeinfo_print(int, const u_char *, const u_char *); -#endif +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 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 */ +static struct tok icmp6_type_values[] = { + { ICMP6_DST_UNREACH, "destination unreachable"}, + { ICMP6_PACKET_TOO_BIG, "packet too big"}, + { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, + { ICMP6_PARAM_PROB, "parameter problem"}, + { ICMP6_ECHO_REQUEST, "echo request"}, + { ICMP6_ECHO_REPLY, "echo reply"}, + { MLD6_LISTENER_QUERY, "multicast listener query"}, + { MLD6_LISTENER_REPORT, "multicast listener report"}, + { MLD6_LISTENER_DONE, "multicast listener done"}, + { ND_ROUTER_SOLICIT, "router solicitation"}, + { ND_ROUTER_ADVERT, "router advertisement"}, + { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, + { ND_NEIGHBOR_ADVERT, "neighbor advertisement"}, + { ND_REDIRECT, "redirect"}, + { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, + { IND_SOLICIT, "inverse neighbor solicitation"}, + { IND_ADVERT, "inverse neighbor advertisement"}, + { MLDV2_LISTENER_REPORT, "multicast listener report v2"}, + { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, + { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, + { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, + { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, + { ICMP6_WRUREQUEST, "who-are-you request"}, + { ICMP6_WRUREPLY, "who-are-you reply"}, + { ICMP6_NI_QUERY, "node information query"}, + { ICMP6_NI_REPLY, "node information reply"}, + { MLD6_MTRACE, "mtrace message"}, + { MLD6_MTRACE_RESP, "mtrace response"}, + { 0, NULL } }; -#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 +static struct tok icmp6_dst_unreach_code_values[] = { + { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, + { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, + { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, + { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, + { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, + { 0, NULL } +}; -/* cope with past KAME typo - shipped with freebsd4[01] and openbsd27 */ -#if defined(ICMP6_NI_SUCESS) && !defined(ICMP6_NI_SUCCESS) -#define ICMP6_NI_SUCCESS ICMP6_NI_SUCESS -#endif -#ifndef ICMP6_NI_SUCCESS -#define ICMP6_NI_SUCCESS 0 /* node information successful reply */ -#define ICMP6_NI_REFUSED 1 /* node information request is refused */ -#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */ -#endif +static struct tok icmp6_opt_pi_flag_values[] = { + { ND_OPT_PI_FLAG_ONLINK, "onlink" }, + { ND_OPT_PI_FLAG_AUTO, "auto" }, + { ND_OPT_PI_FLAG_ROUTER, "router" }, + { 0, NULL } +}; -#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 +static struct tok icmp6_opt_ra_flag_values[] = { + { ND_RA_FLAG_MANAGED, "managed" }, + { ND_RA_FLAG_OTHER, "other stateful"}, + { ND_RA_FLAG_HOME_AGENT, "home agent"}, + { 0, NULL } +}; -#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 +static struct tok icmp6_nd_na_flag_values[] = { + { ND_NA_FLAG_ROUTER, "router" }, + { ND_NA_FLAG_SOLICITED, "solicited" }, + { ND_NA_FLAG_OVERRIDE, "override" }, + { 0, NULL } +}; + + +static struct tok icmp6_opt_values[] = { + { ND_OPT_SOURCE_LINKADDR, "source link-address"}, + { ND_OPT_TARGET_LINKADDR, "destination link-address"}, + { ND_OPT_PREFIX_INFORMATION, "prefix info"}, + { ND_OPT_REDIRECTED_HEADER, "redirected header"}, + { ND_OPT_MTU, "mtu"}, + { ND_OPT_ADVINTERVAL, "advertisement interval"}, + { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, + { ND_OPT_ROUTE_INFO, "route info"}, + { 0, NULL } +}; + +/* 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) +{ + static const char *rtpref_str[] = { + "medium", /* 00 */ + "high", /* 01 */ + "rsv", /* 10 */ + "low" /* 11 */ + }; + + return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; +} + +static const char * +get_lifetime(u_int32_t v) +{ + static char buf[20]; + + if (v == (u_int32_t)~0UL) + return "infinity"; + else { + snprintf(buf, sizeof(buf), "%u", v); + return buf; + } +} + +static void +print_lladdr(const u_int8_t *p, size_t l) +{ + const u_int8_t *ep, *q; + + q = p; + ep = p + l; + while (l > 0 && q < ep) { + if (q > p) + printf(":"); + printf("%02x", *q++); + 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(register const u_char *bp, register const u_char *bp2) +icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented) { 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 const u_char *ep; - char buf[256]; - int icmp6len; - -#if 0 -#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc -#endif + const struct ip6_hdr *ip; + const struct ip6_hdr *oip; + const struct udphdr *ouh; + int dport; + const u_char *ep; + u_int prot; dp = (struct icmp6_hdr *)bp; 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) - - (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] "); + } + } + + printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); + + /* display cosmetics: print the packet length for printer that use the vflag now */ + if (vflag && (dp->icmp6_type == + ND_ROUTER_SOLICIT || + ND_ROUTER_ADVERT || + ND_NEIGHBOR_ADVERT || + ND_NEIGHBOR_SOLICIT || + ND_REDIRECT || + ICMP6_HADISCOV_REPLY || + ICMP6_MOBILEPREFIX_ADVERT )) + printf(", length %u", length); + switch (dp->icmp6_type) { case ICMP6_DST_UNREACH: TCHECK(oip->ip6_dst); + printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); switch (dp->icmp6_code) { - case ICMP6_DST_UNREACH_NOROUTE: - printf("icmp6: %s unreachable route", - ip6addr_string(&oip->ip6_dst)); - break; + + case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ case ICMP6_DST_UNREACH_ADMIN: - printf("icmp6: %s unreachable prohibited", - ip6addr_string(&oip->ip6_dst)); - break; -#ifdef ICMP6_DST_UNREACH_BEYONDSCOPE + case ICMP6_DST_UNREACH_ADDR: + printf(" %s",ip6addr_string(&oip->ip6_dst)); + break; case ICMP6_DST_UNREACH_BEYONDSCOPE: -#else - case ICMP6_DST_UNREACH_NOTNEIGHBOR: -#endif - printf("icmp6: %s beyond scope of source address %s", + printf(" %s, source address %s", ip6addr_string(&oip->ip6_dst), ip6addr_string(&oip->ip6_src)); break; - case ICMP6_DST_UNREACH_ADDR: - printf("icmp6: %s unreachable address", - 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); - dport = ntohs(ouh->uh_dport); - switch (oip->ip6_nxt) { + if ((ouh = get_upperlayer((u_char *)oip, &prot)) + == NULL) + goto trunc; + + dport = EXTRACT_16BITS(&ouh->uh_dport); + switch (prot) { case IPPROTO_TCP: - printf("icmp6: %s tcp port %s unreachable", + printf(", %s tcp port %s", ip6addr_string(&oip->ip6_dst), tcpport_string(dport)); break; case IPPROTO_UDP: - printf("icmp6: %s udp port %s unreachable", + printf(", %s udp port %s", ip6addr_string(&oip->ip6_dst), udpport_string(dport)); break; default: - printf("icmp6: %s protocol %d port %d unreachable", + printf(", %s protocol %d port %d unreachable", ip6addr_string(&oip->ip6_dst), oip->ip6_nxt, dport); break; } break; default: - printf("icmp6: %s unreachable code-#%d", - ip6addr_string(&oip->ip6_dst), - dp->icmp6_code); - break; + if (vflag <= 1) { + print_unknown_data(bp,"\n\t",length); + return; + } + break; } break; case ICMP6_PACKET_TOO_BIG: TCHECK(dp->icmp6_mtu); - printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu)); + printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); break; case ICMP6_TIME_EXCEEDED: TCHECK(oip->ip6_dst); switch (dp->icmp6_code) { case ICMP6_TIME_EXCEED_TRANSIT: - printf("icmp6: time exceeded in-transit for %s", + printf(" for %s", ip6addr_string(&oip->ip6_dst)); break; case ICMP6_TIME_EXCEED_REASSEMBLY: - printf("icmp6: ip6 reassembly time exceeded"); + printf(" (reassembly)"); break; default: - printf("icmp6: time exceeded code-#%d", - dp->icmp6_code); + printf(", unknown code (%u)", dp->icmp6_code); break; } break; @@ -222,78 +347,66 @@ icmp6_print(register const u_char *bp, register const u_char *bp2) TCHECK(oip->ip6_dst); switch (dp->icmp6_code) { case ICMP6_PARAMPROB_HEADER: - printf("icmp6: parameter problem errorneous - octet %u\n", - (u_int32_t)ntohl(dp->icmp6_pptr)); + printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); break; case ICMP6_PARAMPROB_NEXTHEADER: - printf("icmp6: parameter problem next header - octet %u\n", - (u_int32_t)ntohl(dp->icmp6_pptr)); + printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); break; case ICMP6_PARAMPROB_OPTION: - printf("icmp6: parameter problem option - octet %u\n", - (u_int32_t)ntohl(dp->icmp6_pptr)); + printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); break; default: - printf("icmp6: parameter problem code-#%d", + printf(", code-#%d", dp->icmp6_code); break; } break; case ICMP6_ECHO_REQUEST: - printf("icmp6: echo request"); - break; case ICMP6_ECHO_REPLY: - printf("icmp6: echo reply"); + TCHECK(dp->icmp6_seq); + printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); break; -#if defined(HAVE_STRUCT_MLD6_HDR) || defined(HAVE_STRUCT_ICMP6_MLD) 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 %u) ", length); + } break; case ICMP6_MEMBERSHIP_REPORT: - printf("icmp6: multicast listener report "); mld6_print((const u_char *)dp); break; case ICMP6_MEMBERSHIP_REDUCTION: - printf("icmp6: multicast listener done "); mld6_print((const u_char *)dp); break; -#endif case ND_ROUTER_SOLICIT: - printf("icmp6: router solicitation "); - if (vflag) { #define RTSOLLEN 8 + if (vflag) { icmp6_opt_print((const u_char *)dp + RTSOLLEN, - icmp6len - RTSOLLEN); + length - RTSOLLEN); } break; case ND_ROUTER_ADVERT: - printf("icmp6: router advertisement"); +#define RTADVLEN 16 if (vflag) { struct nd_router_advert *p; p = (struct nd_router_advert *)dp; TCHECK(p->nd_ra_retransmit); - printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); - if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) - 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) - printf("H"); - if (p->nd_ra_flags_reserved != 0) - printf(" "); - printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime)); - printf("reachable_time=%u, ", - (u_int32_t)ntohl(p->nd_ra_reachable)); - printf("retrans_time=%u)", - (u_int32_t)ntohl(p->nd_ra_retransmit)); -#define RTADVLEN 16 + printf("\n\thop limit %u, Flags [%s]" \ + ", pref %s, router lifetime %us, reachable time %us, retrans time %us", + (u_int)p->nd_ra_curhoplimit, + bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), + get_rtpref(p->nd_ra_flags_reserved), + EXTRACT_16BITS(&p->nd_ra_router_lifetime), + EXTRACT_32BITS(&p->nd_ra_reachable), + EXTRACT_32BITS(&p->nd_ra_retransmit)); + icmp6_opt_print((const u_char *)dp + RTADVLEN, - icmp6len - RTADVLEN); + length - RTADVLEN); } break; case ND_NEIGHBOR_SOLICIT: @@ -301,12 +414,11 @@ icmp6_print(register const u_char *bp, register const u_char *bp2) struct nd_neighbor_solicit *p; p = (struct nd_neighbor_solicit *)dp; TCHECK(p->nd_ns_target); - printf("icmp6: neighbor sol: who has %s", - ip6addr_string(&p->nd_ns_target)); + printf(", who has %s", ip6addr_string(&p->nd_ns_target)); if (vflag) { #define NDSOLLEN 24 icmp6_opt_print((const u_char *)dp + NDSOLLEN, - icmp6len - NDSOLLEN); + length - NDSOLLEN); } } break; @@ -316,29 +428,16 @@ icmp6_print(register const u_char *bp, register const u_char *bp2) p = (struct nd_neighbor_advert *)dp; TCHECK(p->nd_na_target); - printf("icmp6: neighbor adv: tgt is %s", + printf(", tgt is %s", ip6addr_string(&p->nd_na_target)); if (vflag) { -#define ND_NA_FLAG_ALL \ - (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) - /* we don't need ntohl() here. see advanced-api-04. */ - if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { -#undef ND_NA_FLAG_ALL - u_int32_t flags; - - flags = p->nd_na_flags_reserved; - printf("("); - if (flags & ND_NA_FLAG_ROUTER) - printf("R"); - if (flags & ND_NA_FLAG_SOLICITED) - printf("S"); - if (flags & ND_NA_FLAG_OVERRIDE) - printf("O"); - printf(")"); - } + printf(", Flags [%s]", + bittok2str(icmp6_nd_na_flag_values, + "none", + EXTRACT_32BITS(&p->nd_na_flags_reserved))); #define NDADVLEN 24 icmp6_opt_print((const u_char *)dp + NDADVLEN, - icmp6len - NDADVLEN); + length - NDADVLEN); #undef NDADVLEN } } @@ -346,241 +445,425 @@ icmp6_print(register const u_char *bp, register const u_char *bp2) case ND_REDIRECT: #define RDR(i) ((struct nd_redirect *)(i)) TCHECK(RDR(dp)->nd_rd_dst); - printf("icmp6: redirect %s", - getname6((const u_char *)&RDR(dp)->nd_rd_dst)); + printf(", %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 -#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(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); + icmp6_nodeinfo_print(length, bp, ep); break; -#endif - default: - printf("icmp6: type-#%d", dp->icmp6_type); + case IND_SOLICIT: + case IND_ADVERT: break; - } + case ICMP6_V2_MEMBERSHIP_REPORT: + mldv2_report_print((const u_char *) dp, length); + break; + case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ + case ICMP6_HADISCOV_REQUEST: + TCHECK(dp->icmp6_data16[0]); + printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); + break; + case ICMP6_HADISCOV_REPLY: + if (vflag) { + struct in6_addr *in6; + u_char *cp; + + TCHECK(dp->icmp6_data16[0]); + printf(", id 0x%04x", 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)); + } + } + break; + case ICMP6_MOBILEPREFIX_ADVERT: + if (vflag) { + TCHECK(dp->icmp6_data16[0]); + printf(", id 0x%04x", 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"); +#define MPADVLEN 8 + icmp6_opt_print((const u_char *)dp + MPADVLEN, + length - MPADVLEN); + } + break; + default: + printf(", length %u", length); + if (vflag <= 1) + print_unknown_data(bp,"\n\t", length); + return; + } + if (!vflag) + printf(", length %u", length); return; trunc: fputs("[|icmp6]", stdout); -#if 0 -#undef TCHECK -#endif } -void -icmp6_opt_print(register const u_char *bp, int resid) +static struct udphdr * +get_upperlayer(u_char *bp, u_int *prot) { - register const struct nd_opt_hdr *op; - register const struct nd_opt_hdr *opl; /* why there's no struct? */ - register const struct nd_opt_prefix_info *opp; - register const struct icmp6_opts_redirect *opr; - register const struct nd_opt_mtu *opm; - register const u_char *ep; - int opts_len; -#if 0 - 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; - char buf[256]; -#endif + 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; + u_int nh; + int hlen; + + /* 'ep' points to the end of available data. */ + ep = snapend; + + if (!TTEST(ip6->ip6_nxt)) + return NULL; + + nh = ip6->ip6_nxt; + hlen = sizeof(struct ip6_hdr); + + while (bp < ep) { + 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)) + 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)) + return(NULL); + /* fragments with non-zero offset are meaningless */ + if ((EXTRACT_16BITS(&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)) + 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 */ +} + +static void +icmp6_opt_print(const u_char *bp, int resid) +{ + const struct nd_opt_hdr *op; + const struct nd_opt_hdr *opl; /* why there's no struct? */ + const struct nd_opt_prefix_info *opp; + 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; + size_t l; #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return - op = (struct nd_opt_hdr *)bp; -#if 0 - ip = (struct ip6_hdr *)bp2; - oip = &dp->icmp6_ip6; - str = buf; -#endif - /* 'ep' points to the end of avaible data. */ + cp = bp; + /* 'ep' points to the end of available data. */ ep = snapend; - ECHECK(op->nd_opt_len); - if (resid <= 0) - return; - switch (op->nd_opt_type) { - case ND_OPT_SOURCE_LINKADDR: - opl = (struct nd_opt_hdr *)op; -#if 1 - if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) + while (cp < ep) { + op = (struct nd_opt_hdr *)cp; + + ECHECK(op->nd_opt_len); + if (resid <= 0) + return; + if (op->nd_opt_len == 0) goto trunc; -#else - TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); -#endif - printf("(src lladdr: %s", /*)*/ - etheraddr_string((u_char *)(opl + 1))); - if (opl->nd_opt_len != 1) - printf("!"); - /*(*/ - printf(")"); - icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), - resid - (op->nd_opt_len << 3)); - break; - case ND_OPT_TARGET_LINKADDR: - opl = (struct nd_opt_hdr *)op; -#if 1 - if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) + if (cp + (op->nd_opt_len << 3) > ep) goto trunc; -#else - TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); -#endif - printf("(tgt lladdr: %s", /*)*/ - etheraddr_string((u_char *)(opl + 1))); - if (opl->nd_opt_len != 1) - printf("!"); - /*(*/ - printf(")"); - icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), - resid - (op->nd_opt_len << 3)); - break; - case ND_OPT_PREFIX_INFORMATION: - opp = (struct nd_opt_prefix_info *)op; - TCHECK(opp->nd_opt_pi_prefix); - printf("(prefix info: "); /*)*/ - if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) - printf("L"); - if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) - printf("A"); - if (opp->nd_opt_pi_flags_reserved) - printf(" "); - printf("valid_ltime="); - if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U) - printf("infinity"); - else { - printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time)); - } - printf(", "); - printf("preffered_ltime="); - if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U) - printf("infinity"); - else { - printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)); + + printf("\n\t %s option (%u), length %u (%u): ", + tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), + op->nd_opt_type, + op->nd_opt_len << 3, + op->nd_opt_len); + + switch (op->nd_opt_type) { + case ND_OPT_SOURCE_LINKADDR: + opl = (struct nd_opt_hdr *)op; + l = (op->nd_opt_len << 3) - 2; + print_lladdr(cp + 2, l); + break; + case ND_OPT_TARGET_LINKADDR: + opl = (struct nd_opt_hdr *)op; + l = (op->nd_opt_len << 3) - 2; + print_lladdr(cp + 2, l); + break; + case ND_OPT_PREFIX_INFORMATION: + opp = (struct nd_opt_prefix_info *)op; + TCHECK(opp->nd_opt_pi_prefix); + printf("%s/%u%s, Flags [%s], valid time %ss", + ip6addr_string(&opp->nd_opt_pi_prefix), + opp->nd_opt_pi_prefix_len, + (op->nd_opt_len != 4) ? "badlen" : "", + bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), + get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); + printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); + break; + case ND_OPT_REDIRECTED_HEADER: + opr = (struct icmp6_opts_redirect *)op; + print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); + /* xxx */ + break; + case ND_OPT_MTU: + opm = (struct nd_opt_mtu *)op; + TCHECK(opm->nd_opt_mtu_mtu); + printf(" %u%s", + EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), + (op->nd_opt_len != 1) ? "bad option length" : "" ); + break; + case ND_OPT_ADVINTERVAL: + opa = (struct nd_opt_advinterval *)op; + TCHECK(opa->nd_opt_adv_interval); + printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); + break; + case ND_OPT_HOMEAGENT_INFO: + oph = (struct nd_opt_homeagent_info *)op; + TCHECK(oph->nd_opt_hai_lifetime); + printf(" preference %u, lifetime %u", + EXTRACT_16BITS(&oph->nd_opt_hai_preference), + EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); + break; + case ND_OPT_ROUTE_INFO: + opri = (struct nd_opt_route_info *)op; + TCHECK(opri->nd_opt_rti_lifetime); + memset(&in6, 0, sizeof(in6)); + in6p = (struct in6_addr *)(opri + 1); + switch (op->nd_opt_len) { + case 1: + break; + case 2: + TCHECK2(*in6p, 8); + memcpy(&in6, opri + 1, 8); + break; + case 3: + TCHECK(*in6p); + memcpy(&in6, opri + 1, sizeof(in6)); + break; + default: + goto trunc; + } + printf(" %s/%u", ip6addr_string(&in6), + opri->nd_opt_rti_prefixlen); + printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); + printf(", lifetime=%s", + get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); + break; + default: + if (vflag <= 1) { + print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ + return; + } + break; } - printf(", "); - printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), - opp->nd_opt_pi_prefix_len); - if (opp->nd_opt_pi_len != 4) - printf("!"); - /*(*/ - printf(")"); - icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), - resid - (op->nd_opt_len << 3)); - break; - case ND_OPT_REDIRECTED_HEADER: - opr = (struct icmp6_opts_redirect *)op; - printf("(redirect)"); - /* xxx */ - icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), - resid - (op->nd_opt_len << 3)); - break; - case ND_OPT_MTU: - opm = (struct nd_opt_mtu *)op; - TCHECK(opm->nd_opt_mtu_mtu); - printf("(mtu: "); /*)*/ - printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); - if (opm->nd_opt_mtu_len != 1) - printf("!"); - 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)", - op->nd_opt_type, opts_len); - if (opts_len == 0) - opts_len = 1; /* XXX */ - icmp6_opt_print((const u_char *)op + (opts_len << 3), - resid - (opts_len << 3)); - break; + /* do we want to see an additional hexdump ? */ + if (vflag> 1) + print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ + + cp += op->nd_opt_len << 3; + resid -= op->nd_opt_len << 3; } return; + trunc: fputs("[ndp opt]", stdout); return; #undef ECHECK } -#if defined(HAVE_STRUCT_MLD6_HDR) -void -mld6_print(register const u_char *bp) +static void +mld6_print(const u_char *bp) { - register struct mld6_hdr *mp = (struct mld6_hdr *)bp; - register const u_char *ep; + struct mld6_hdr *mp = (struct mld6_hdr *)bp; + 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) 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)); } -#elif defined(HAVE_STRUCT_ICMP6_MLD) - -void -mld6_print(register const u_char *bp) +static void +mldv2_report_print(const u_char *bp, u_int len) { - register struct icmp6_mld *mp = (struct icmp6_mld *)bp; - register const u_char *ep; + struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; + u_int group, nsrcs, ngroups; + u_int i, j; - /* 'ep' points to the end of avaible data. */ - ep = snapend; + /* Minimum len is 8 */ + if (len < 8) { + printf(" [invalid len %d]", len); + return; + } - if ((u_char *)mp + sizeof(*mp) > ep) + 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; - - printf("max resp delay: %d ", ntohs(mp->icmp6m_hdr.icmp6_maxdelay)); - printf("addr: %s", ip6addr_string(&mp->icmp6m_group)); + } + TCHECK2(bp[group + 4], sizeof(struct in6_addr)); + 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 * 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 + 20 + j * sizeof(struct in6_addr)], + sizeof(struct in6_addr)); + printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); + } + (void)printf(" }"); + } + /* Next group record */ + group += 20 + nsrcs * sizeof(struct in6_addr); + printf("]"); + } + } + return; +trunc: + (void)printf("[|icmp6]"); + return; } -#endif - -#ifdef HAVE_STRUCT_ICMP6_NODEINFO 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); + } + TCHECK2(bp[8], sizeof(struct in6_addr)); + 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); + } + + TCHECK2(bp[26], 2); + nsrcs = ntohs(*(u_short *)&bp[26]); + if (nsrcs > 0) { + if (len < 28 + nsrcs * sizeof(struct in6_addr)) + printf(" [invalid number of sources]"); + else if (vflag > 1) { + printf(" {"); + for (i = 0; i < nsrcs; i++) { + TCHECK2(bp[28 + i * sizeof(struct in6_addr)], + sizeof(struct in6_addr)); + printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); + } + 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; @@ -616,15 +899,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; @@ -633,21 +918,21 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) case ICMP6_NI_QUERY: if (siz == sizeof(*dp) + 4) { /* KAME who-are-you */ - printf("icmp6: who-are-you request"); + printf(" who-are-you request"); break; } - printf("icmp6: node information query"); + printf(" node information query"); 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; @@ -752,7 +1037,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) needcomma = 0; ni6 = (struct icmp6_nodeinfo *)dp; - printf("icmp6: node information reply"); + printf(" node information reply"); printf(" ("); /*)*/ switch (ni6->ni_code) { case ICMP6_NI_SUCCESS: @@ -783,7 +1068,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(", "); @@ -796,7 +1081,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; @@ -818,7 +1103,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: @@ -831,7 +1116,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)", ntohl(*(int32_t *)(bp + i))); + printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); i += sizeof(int32_t); } i = ni6->ni_flags; @@ -862,6 +1147,141 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) trunc: fputs("[|icmp6]", stdout); } -#endif + +static void +icmp6_rrenum_print(const u_char *bp, const u_char *ep) +{ + struct icmp6_router_renum *rr6; + const char *cp; + struct rr_pco_match *match; + struct rr_pco_use *use; + char hbuf[NI_MAXHOST]; + int n; + + if (ep < bp) + return; + rr6 = (struct icmp6_router_renum *)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", EXTRACT_32BITS(&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_FORCEAPPLY, "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", EXTRACT_16BITS(&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 > 1) + 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 > 1) + 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,", + EXTRACT_32BITS(&use->rpu_vltime)); + if (~use->rpu_pltime == 0) + printf("pltime=infty,"); + else + printf("pltime=%u,", + EXTRACT_32BITS(&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 */