Skip to content
This repository has been archived by the owner on Apr 14, 2024. It is now read-only.

Commit

Permalink
Bugfix: Fix incorrect cksums
Browse files Browse the repository at this point in the history
Presence of IPv6 Extension Headers was causing incorrect TCP/UDP/ICMP
cksums. Verified that with these changes, cksums are correct for all
combinations of L3 and L4 headers with/without options/extHdrs

Fixes #271
  • Loading branch information
pstavirs committed Sep 13, 2018
1 parent 4924d7f commit 488a2ea
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 12 deletions.
19 changes: 14 additions & 5 deletions common/abstractprotocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,18 +930,27 @@ quint32 AbstractProtocol::protocolFrameHeaderCksum(int streamIndex,
CksumType cksumType, CksumScope cksumScope) const
{
quint32 sum = 0;
quint16 cksum;
quint32 cksum;
AbstractProtocol *p = prev;

Q_ASSERT(cksumType == CksumIpPseudo);

// We may have extension headers between us and the IP header - skip 'em
while (p)
{
cksum = p->protocolFrameCksum(streamIndex, cksumType);
sum += (quint16) ~cksum;
qDebug("%s: sum = %u, cksum = %u", __FUNCTION__, sum, cksum);
if (cksumScope == CksumScopeAdjacentProtocol)
goto out;
if (cksum <= 0xFFFF) // protocol has a valid pseudo cksum ie its IP
{
sum += (quint16) ~cksum;
// Ip4/6Protocol::protocolFrameCksum(CksumIpPseudo) only
// counts the src/dst IP (see Note in there)
// Count the payload length and protocolId here
sum += protocolFrameSize() + protocolFramePayloadSize();
sum += protocolId(ProtocolIdIp);
qDebug("%s: sum = %x, cksum = %x", __FUNCTION__, sum, cksum);
if (cksumScope == CksumScopeAdjacentProtocol)
goto out;
}
p = p->prev;
}
if (parent)
Expand Down
12 changes: 8 additions & 4 deletions common/ip4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,14 +859,18 @@ quint32 Ip4Protocol::protocolFrameCksum(int streamIndex,
sum += *((quint16*)(p + 14)); // src-ip lo
sum += *((quint16*)(p + 16)); // dst-ip hi
sum += *((quint16*)(p + 18)); // dst-ip lo
sum += qToBigEndian((quint16)
protocolFramePayloadSize(streamIndex)); // len
sum += qToBigEndian((quint16) *(p + 9)); // proto

// XXX: payload length and protocol are also part of the
// pseudo cksum but for IPv6 we need to skip extension headers to
// get to them, so these two fields are counted in the
// pseudo cksum in AbstractProtocol::protocolFrameHeaderCksum()
// Although not needed for IPv4 case, we do the same for IPv4
// also, so that code there is common for IPv4 and IPv6

while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);

return ~qFromBigEndian((quint16)sum);
return qFromBigEndian((quint16) ~sum);
}
default:
break;
Expand Down
11 changes: 8 additions & 3 deletions common/ip6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,13 +781,18 @@ quint32 Ip6Protocol::protocolFrameCksum(int streamIndex,
// src-ip, dst-ip
for (int i = 8; i < fv.size(); i+=2)
sum += *((quint16*)(p + i));
sum += *((quint16*)(p + 4)); // payload len
sum += qToBigEndian((quint16) *(p + 6)); // proto

// XXX: payload length and protocol are also part of the
// pseudo cksum but we need to skip extension headers to
// get to them as per RFC 8200 Section 8.1
// Since we can't traverse beyond our immediate neighboring
// protocol from here, these two fields are counted in the
// pseudo cksum in AbstractProtocol::protocolFrameHeaderCksum()

while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);

return ~qFromBigEndian((quint16)sum);
return qFromBigEndian((quint16) ~sum);
}
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
}
Expand Down

0 comments on commit 488a2ea

Please sign in to comment.