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 CksumType cksumType, CksumScope cksumScope) const
{ {
quint32 sum = 0; quint32 sum = 0;
quint16 cksum; quint32 cksum;
AbstractProtocol *p = prev; AbstractProtocol *p = prev;
Q_ASSERT(cksumType == CksumIpPseudo); Q_ASSERT(cksumType == CksumIpPseudo);
// We may have extension headers between us and the IP header - skip 'em
while (p) while (p)
{ {
cksum = p->protocolFrameCksum(streamIndex, cksumType); cksum = p->protocolFrameCksum(streamIndex, cksumType);
if (cksum <= 0xFFFF) // protocol has a valid pseudo cksum ie its IP
{
sum += (quint16) ~cksum; sum += (quint16) ~cksum;
qDebug("%s: sum = %u, cksum = %u", __FUNCTION__, sum, 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) if (cksumScope == CksumScopeAdjacentProtocol)
goto out; goto out;
}
p = p->prev; p = p->prev;
} }
if (parent) if (parent)

View File

@ -859,14 +859,18 @@ quint32 Ip4Protocol::protocolFrameCksum(int streamIndex,
sum += *((quint16*)(p + 14)); // src-ip lo sum += *((quint16*)(p + 14)); // src-ip lo
sum += *((quint16*)(p + 16)); // dst-ip hi sum += *((quint16*)(p + 16)); // dst-ip hi
sum += *((quint16*)(p + 18)); // dst-ip lo sum += *((quint16*)(p + 18)); // dst-ip lo
sum += qToBigEndian((quint16)
protocolFramePayloadSize(streamIndex)); // len // XXX: payload length and protocol are also part of the
sum += qToBigEndian((quint16) *(p + 9)); // proto // 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) while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16); sum = (sum & 0xFFFF) + (sum >> 16);
return ~qFromBigEndian((quint16)sum); return qFromBigEndian((quint16) ~sum);
} }
default: default:
break; break;

View File

@ -781,13 +781,18 @@ quint32 Ip6Protocol::protocolFrameCksum(int streamIndex,
// src-ip, dst-ip // src-ip, dst-ip
for (int i = 8; i < fv.size(); i+=2) for (int i = 8; i < fv.size(); i+=2)
sum += *((quint16*)(p + i)); 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) while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16); sum = (sum & 0xFFFF) + (sum >> 16);
return ~qFromBigEndian((quint16)sum); return qFromBigEndian((quint16) ~sum);
} }
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType); return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
} }