Attached are patches for the latest automatic build
of wireshark and for tcpdump (3.9.5), to support
validation of variable length checksums (RFC 4340, sec. 9).
I have submitted them to the respective lists, but it may
take some time until they surface.
A kernel patch is on its way, I am just waiting to make
sure I got it correct.
There is also a ttcp_dccp variant with support for variable
length checksums, I hope to finalise this some time when
finally the socket API is a bit cleaner.
Gerrit
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), ");
}
--- wireshark-0.99.4-SVN-19738/epan/dissectors/packet-dcp.c.orig 2006-10-30 14:52:53.000000000 +0000
+++ wireshark-0.99.4-SVN-19738/epan/dissectors/packet-dcp.c 2006-10-30 14:53:02.000000000 +0000
@@ -541,6 +541,16 @@
} /* end while() */
}
+/* compute DCCP checksum coverage according to RFC 4340, section 9 */
+static inline guint dccp_csum_coverage(const e_dcphdr *dcph, guint len)
+{
+ guint cov;
+
+ if (dcph->cscov == 0)
+ return len;
+ cov = (dcph->data_offset + dcph->cscov - 1) * sizeof(guint32);
+ return (cov > len)? len : cov;
+}
static void dissect_dcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
@@ -595,7 +605,8 @@
/* DBG("dcph->data_offset: %d\n", dcph->data_offset); */
dcph->cscov=tvb_get_guint8(tvb, offset+5)&0x0F;
/* DBG("dcph->cscov: %d\n", dcph->cscov); */
- dcph->ccval=tvb_get_guint8(tvb, offset+5)&0xF0;
+ dcph->ccval=tvb_get_guint8(tvb, offset+5) &0xF0;
+ dcph->ccval >>= 4;
/* DBG("dcph->ccval: %d\n", dcph->ccval); */
dcph->checksum=tvb_get_ntohs(tvb, offset+6);
/* DBG("dcph->checksum: %d\n", dcph->checksum); */
@@ -662,15 +673,11 @@
proto_tree_add_uint(dcp_tree, hf_dcp_ccval, tvb, offset + 5, 1, dcph->ccval);
proto_tree_add_uint(dcp_tree, hf_dcp_cscov, tvb, offset + 5, 1, dcph->cscov);
- /* checksum analisys taken from packet-udp */
+ /* checksum analysis taken from packet-udp (difference: mandatory checksums in DCCP) */
reported_len = tvb_reported_length(tvb);
len = tvb_length(tvb);
- if (dcph->checksum == 0) {
- /* No checksum supplied in the packet */
- proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,
- offset + 6, 2, dcph->checksum, "0x%04x (none)", dcph->checksum);
- } else if (!pinfo->fragmented && len >= reported_len) {
+ if (!pinfo->fragmented && len >= reported_len) {
/* The packet isn't part of a fragmented datagram and isn't
truncated, so we can checksum it.
@@ -703,7 +710,7 @@
break;
}
cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len);
- cksum_vec[3].len = reported_len;
+ cksum_vec[3].len = dccp_csum_coverage(dcph, reported_len);
computed_cksum = in_cksum(&cksum_vec[0], 4);
if (computed_cksum == 0) {
proto_tree_add_uint_format_value(dcp_tree, hf_dcp_checksum, tvb,