Bugfix: Fix incorrect cksums

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
This commit is contained in:
Srivats P 2018-09-13 12:32:36 +05:30
parent 4924d7fe60
commit 488a2ea730
3 changed files with 30 additions and 12 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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);
}