X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/c243fe7be4358f1ff19e531855597b78643d2a26..fb8b947488c7f22b518de1df1a91e663dc7ab33c:/print-icmp6.c diff --git a/print-icmp6.c b/print-icmp6.c index 0829119e..2eab0ac7 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.68 2003-02-05 02:36:25 guy Exp $"; +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.77 2004-06-16 00:06:28 guy Exp $"; #endif #ifdef HAVE_CONFIG_H @@ -37,6 +37,7 @@ static const char rcsid[] = #include "ip6.h" #include "icmp6.h" +#include "ipproto.h" #include "interface.h" #include "addrtoname.h" @@ -50,15 +51,28 @@ static const char *get_lifetime(u_int32_t); static void print_lladdr(const u_char *, size_t); static void icmp6_opt_print(const u_char *, int); static void mld6_print(const u_char *); +static void mldv2_report_print(const u_char *, u_int); +static void mldv2_query_print(const u_char *, u_int); static struct udphdr *get_upperlayer(u_char *, u_int *); static void dnsname_print(const u_char *, const u_char *); static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); -static void icmp6_rrenum_print(u_int, const u_char *, const u_char *); +static void icmp6_rrenum_print(const u_char *, const u_char *); #ifndef abs #define abs(a) ((0 < (a)) ? (a) : -(a)) #endif +/* mldv2 report types */ +static struct tok mldv2report2str[] = { + { 1, "is_in" }, + { 2, "is_ex" }, + { 3, "to_in" }, + { 4, "to_ex" }, + { 5, "allow" }, + { 6, "block" }, + { 0, NULL } +}; + static const char * get_rtpref(u_int v) { @@ -100,8 +114,51 @@ print_lladdr(const u_int8_t *p, size_t l) } } +static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, + u_int len) +{ + size_t i; + register const u_int16_t *sp; + u_int32_t sum; + union { + struct { + struct in6_addr ph_src; + struct in6_addr ph_dst; + u_int32_t ph_len; + u_int8_t ph_zero[3]; + u_int8_t ph_nxt; + } ph; + u_int16_t pa[20]; + } phu; + + /* pseudo-header */ + memset(&phu, 0, sizeof(phu)); + phu.ph.ph_src = ip6->ip6_src; + phu.ph.ph_dst = ip6->ip6_dst; + phu.ph.ph_len = htonl(len); + phu.ph.ph_nxt = IPPROTO_ICMPV6; + + sum = 0; + for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) + sum += phu.pa[i]; + + sp = (const u_int16_t *)icp; + + for (i = 0; i < (len & ~1); i += 2) + sum += *sp++; + + if (len & 1) + sum += htons((*(const u_int8_t *)sp) << 8); + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + + return (sum); +} + void -icmp6_print(const u_char *bp, const u_char *bp2) +icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented) { const struct icmp6_hdr *dp; const struct ip6_hdr *ip; @@ -111,7 +168,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) int dport; const u_char *ep; char buf[256]; - u_int icmp6len, prot; + u_int prot; dp = (struct icmp6_hdr *)bp; ip = (struct ip6_hdr *)bp2; @@ -119,13 +176,21 @@ icmp6_print(const u_char *bp, const u_char *bp2) str = buf; /* 'ep' points to the end of available data. */ ep = snapend; - if (ip->ip6_plen) - icmp6len = (EXTRACT_16BITS(&ip->ip6_plen) + sizeof(struct ip6_hdr) - - (bp - bp2)); - else /* XXX: jumbo payload case... */ - icmp6len = snapend - bp; - TCHECK(dp->icmp6_code); + TCHECK(dp->icmp6_cksum); + + if (vflag && !fragmented) { + int sum = dp->icmp6_cksum; + + if (TTEST2(bp[0], length)) { + sum = icmp6_cksum(ip, dp, length); + if (sum != 0) + (void)printf("[bad icmp6 cksum %x!] ", sum); + else + (void)printf("[icmp6 sum ok] "); + } + } + switch (dp->icmp6_type) { case ICMP6_DST_UNREACH: TCHECK(oip->ip6_dst); @@ -220,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 "); @@ -242,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: @@ -274,7 +348,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) EXTRACT_32BITS(&p->nd_ra_retransmit)); #define RTADVLEN 16 icmp6_opt_print((const u_char *)dp + RTADVLEN, - icmp6len - RTADVLEN); + length - RTADVLEN); } break; case ND_NEIGHBOR_SOLICIT: @@ -287,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; @@ -319,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 } } @@ -329,22 +403,33 @@ icmp6_print(const u_char *bp, const u_char *bp2) TCHECK(RDR(dp)->nd_rd_dst); printf("icmp6: redirect %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); + TCHECK(RDR(dp)->nd_rd_target); printf(" to %s", getname6((const u_char*)&RDR(dp)->nd_rd_target)); #define REDIRECTLEN 40 if (vflag) { icmp6_opt_print((const u_char *)dp + REDIRECTLEN, - icmp6len - REDIRECTLEN); + length - REDIRECTLEN); } break; #undef REDIRECTLEN #undef RDR case ICMP6_ROUTER_RENUMBERING: - icmp6_rrenum_print(icmp6len, bp, ep); + icmp6_rrenum_print(bp, ep); break; case ICMP6_NI_QUERY: case ICMP6_NI_REPLY: - icmp6_nodeinfo_print(icmp6len, bp, ep); + icmp6_nodeinfo_print(length, bp, ep); + break; + case IND_SOLICIT: + printf("icmp6: inverse neighbor solicitation"); + break; + case IND_ADVERT: + printf("icmp6: inverse neighbor advertisement"); + break; + case ICMP6_V2_MEMBERSHIP_REPORT: + printf("icmp6: multicast listener report v2 "); + mldv2_report_print((const u_char *) dp, length); break; case ICMP6_HADISCOV_REQUEST: printf("icmp6: ha discovery request"); @@ -361,7 +446,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) TCHECK(dp->icmp6_data16[0]); printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0])); - cp = (u_char *)dp + icmp6len; + cp = (u_char *)dp + length; in6 = (struct in6_addr *)(dp + 1); for (; (u_char *)in6 < cp; in6++) { TCHECK(*in6); @@ -391,7 +476,7 @@ icmp6_print(const u_char *bp, const u_char *bp2) printf(")"); #define MPADVLEN 8 icmp6_opt_print((const u_char *)dp + MPADVLEN, - icmp6len - MPADVLEN); + length - MPADVLEN); } break; default: @@ -655,6 +740,126 @@ mld6_print(const u_char *bp) } static void +mldv2_report_print(const u_char *bp, u_int len) +{ + struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; + u_int group, nsrcs, ngroups; + u_int i, j; + + /* Minimum len is 8 */ + if (len < 8) { + printf(" [invalid len %d]", len); + return; + } + + TCHECK(icp->icmp6_data16[1]); + ngroups = ntohs(icp->icmp6_data16[1]); + printf(", %d group record(s)", ngroups); + if (vflag > 0) { + /* Print the group records */ + group = 8; + for (i = 0; i < ngroups; i++) { + /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ + if (len < group + 20) { + printf(" [invalid number of groups]"); + return; + } + TCHECK(bp[group + 4]); + printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); + printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", + bp[group])); + nsrcs = (bp[group + 2] << 8) + bp[group + 3]; + /* Check the number of sources and print them */ + if (len < group + 20 + (nsrcs * 16)) { + printf(" [invalid number of sources %d]", nsrcs); + return; + } + if (vflag == 1) + printf(", %d source(s)", nsrcs); + else { + /* Print the sources */ + (void)printf(" {"); + for (j = 0; j < nsrcs; j++) { + TCHECK2(bp[group + 20 + j * 16], 16); + printf(" %s", ip6addr_string(&bp[group + 20 + j * 16])); + } + (void)printf(" }"); + } + /* Next group record */ + group += 20 + nsrcs * 16; + printf("]"); + } + } + return; +trunc: + (void)printf("[|icmp6]"); + return; +} + +static void +mldv2_query_print(const u_char *bp, u_int len) +{ + struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; + u_int mrc; + int mrt, qqi; + u_int nsrcs; + register u_int i; + + /* Minimum len is 28 */ + if (len < 28) { + printf(" [invalid len %d]", len); + return; + } + TCHECK(icp->icmp6_data16[0]); + mrc = ntohs(icp->icmp6_data16[0]); + if (mrc < 32768) { + mrt = mrc; + } else { + mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); + } + if (vflag) { + (void)printf(" [max resp delay=%d]", mrt); + } + printf(" [gaddr %s", ip6addr_string(&bp[8])); + + if (vflag) { + TCHECK(bp[25]); + if (bp[24] & 0x08) { + printf(" sflag"); + } + if (bp[24] & 0x07) { + printf(" robustness=%d", bp[24] & 0x07); + } + if (bp[25] < 128) { + qqi = bp[25]; + } else { + qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); + } + printf(" qqi=%d", qqi); + } + + nsrcs = ntohs(*(u_short *)&bp[26]); + if (nsrcs > 0) { + if (len < 28 + nsrcs * 16) + printf(" [invalid number of sources]"); + else if (vflag > 1) { + printf(" {"); + for (i = 0; i < nsrcs; i++) { + TCHECK2(bp[28 + i * 16], 16); + printf(" %s", ip6addr_string(&bp[28 + i * 16])); + } + printf(" }"); + } else + printf(", %d source(s)", nsrcs); + } + printf("]"); + return; +trunc: + (void)printf("[|icmp6]"); + return; +} + +void dnsname_print(const u_char *cp, const u_char *ep) { int i; @@ -940,7 +1145,7 @@ trunc: } static void -icmp6_rrenum_print(u_int icmp6len, const u_char *bp, const u_char *ep) +icmp6_rrenum_print(const u_char *bp, const u_char *ep) { struct icmp6_router_renum *rr6; struct icmp6_hdr *dp;