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:
parent
4924d7fe60
commit
488a2ea730
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user