This introduces support for variable-length checksum in DCCP, as it is specified in section 9 of RFC 4340.
Previously tcpdump was only able to validate full-coverage checksums, this patch verifies checksums in accordance with the CsCov header field (sec. 5.3). The patch has been tested and verified on DCCPv4 and DCCPv6 connections, checksums were manually validated, and traces can be supplied. In addition, the patch also * removes reduplicated code in dccp6_cksum (which just repeated the code of in_cksum) * fixes a bug in dccp.h -- the fields of CCVAL and CSCOV were swapped (cf. section 5.1 of RFC 4340) * fixes a typo in the display of incorrect checksums (these were printed as `cksum xDEAD (incorrect (-> xBEEF)', it now will print `cksum xDEAD (incorrect -> xBEEF)' I would like to see this merged as a Linux kernel patch already exists for DCCP partial checksum coverage support. Regards Gerrit Renker dccp.h | 4 ++-- print-dccp.c | 34 ++++++++++++++++------------------ 2 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/dccp.h b/dccp.h index 1afa8c0..8585060 100644 --- a/dccp.h +++ b/dccp.h @@ -36,8 +36,8 @@ struct dccp_hdr { } dccph_xtrs; }; -#define DCCPH_CCVAL(dh) (((dh)->dccph_ccval_cscov) & 0x0F) -#define DCCPH_CSCOV(dh) (((dh)->dccph_ccval_cscov >> 4) & 0x0F) +#define DCCPH_CCVAL(dh) (((dh)->dccph_ccval_cscov >> 4) & 0xF) +#define DCCPH_CSCOV(dh) (((dh)->dccph_ccval_cscov) & 0xF) #define DCCPH_X(dh) ((dh)->dccph_xtrs.dccph_xtr & 1) #define DCCPH_TYPE(dh) (((dh)->dccph_xtrs.dccph_xtr >> 1) & 0xF) diff --git a/print-dccp.c b/print-dccp.c index e6bfca6..d19c500 100644 --- a/print-dccp.c +++ b/print-dccp.c @@ -60,9 +60,20 @@ static const char *dccp_feature_nums[] = "check data checksum", }; +static inline int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len) +{ + int cov; + + if (DCCPH_CSCOV(dh) == 0) + return len; + cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(u_int32_t); + return (cov > len)? len : cov; +} + static int dccp_cksum(const struct ip *ip, const struct dccp_hdr *dh, u_int len) { + int cov = dccp_csum_coverage(dh, len); union phu { struct phdr { u_int32_t src; @@ -86,15 +97,15 @@ static int dccp_cksum(const struct ip *i phu.ph.dst = ip_finddst(ip); sp = &phu.pa[0]; - return in_cksum((u_short *)dh, len, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]); + return in_cksum((u_short *)dh, cov, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]); } #ifdef INET6 static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len) { size_t i; - const u_int16_t *sp; - u_int32_t sum; + u_int32_t sum = 0; + int cov = dccp_csum_coverage(dh, len); union { struct { struct in6_addr ph_src; @@ -113,23 +124,10 @@ static int dccp6_cksum(const struct ip6_ phu.ph.ph_len = htonl(len); phu.ph.ph_nxt = IPPROTO_DCCP; - sum = 0; for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) sum += phu.pa[i]; - sp = (const u_int16_t *)dh; - - 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); + return in_cksum((u_short *)dh, cov, sum); } #endif @@ -288,7 +286,7 @@ #ifdef INET6 dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum); printf("cksum 0x%04x", dccp_sum); if (sum != 0) { - (void)printf(" (incorrect (-> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum)); + (void)printf(" (incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum)); } else (void)printf(" (correct), "); }
- This is the tcpdump-workers list. Visit https://cod.sandelman.ca/ to unsubscribe.