Fix incorrect UDP/ICMP checksums

For UDP encaps like VxLAN or Geneve, which can contain IP as
payload, the UDP checksum was incorrect because when summing
UDP payload (i.e. IP), we skipped the IPv4 checksum field,
which should not be skipped in this case.

Similar issue, for ICMP with IP as payload, ICMP checksum was
incorrect.

Essentially, any protocol which checksums over its payload and
the payload contains protocols with checksum fields.
This commit is contained in:
Srivats P 2021-09-04 18:16:40 +05:30
parent 96b6424cae
commit a498dbf21a
9 changed files with 43 additions and 20 deletions

View File

@ -850,7 +850,7 @@ bool AbstractProtocol::protocolHasPayload() const
to prevent infinite recursion
*/
quint32 AbstractProtocol::protocolFrameCksum(int streamIndex,
CksumType cksumType) const
CksumType cksumType, CksumFlags cksumFlags) const
{
static int recursionCount = 0;
quint32 cksum = 0xFFFFFFFF;
@ -865,8 +865,10 @@ quint32 AbstractProtocol::protocolFrameCksum(int streamIndex,
QByteArray fv;
quint16 *ip;
quint32 len, sum = 0;
bool forCksum = cksumFlags.testFlag(IncludeCksumField) ?
false : true;
fv = protocolFrameValue(streamIndex, true);
fv = protocolFrameValue(streamIndex, forCksum);
ip = (quint16*) fv.constData();
len = fv.size();
@ -994,7 +996,7 @@ quint32 AbstractProtocol::protocolFramePayloadCksum(int streamIndex,
if (!p)
return 0xFFFF;
cksum = p->protocolFrameCksum(streamIndex, cksumType);
cksum = p->protocolFrameCksum(streamIndex, cksumType, IncludeCksumField);
sum = (quint16) ~cksum;
if (cksumScope == CksumScopeAdjacentProtocol)
goto out;
@ -1002,9 +1004,9 @@ quint32 AbstractProtocol::protocolFramePayloadCksum(int streamIndex,
p = p->next;
while (p)
{
cksum = p->protocolFrameCksum(streamIndex, cksumType, IncludeCksumField);
// when combining cksums, a non-first protocol starting at odd offset
// needs a byte swap (see RFC 1071 section(s) 2A, 2B)
cksum = p->protocolFrameCksum(streamIndex, cksumType);
if (p->protocolFrameOffset(streamIndex) & 0x1)
cksum = swap16(cksum);
sum += (quint16) ~cksum;

View File

@ -106,6 +106,12 @@ public:
CksumMax //!< Marker for number of cksum types
};
//! Flags affecting cksum calculation, can be OR'd
enum CksumFlag {
IncludeCksumField = 0x1, //!< Default: exclude cksum field(s)
};
Q_DECLARE_FLAGS(CksumFlags, CksumFlag); //!< \private abcd
//! Supported checksum scopes
enum CksumScope {
CksumScopeAdjacentProtocol, //!< Cksum only the adjacent protocol
@ -164,7 +170,7 @@ public:
bool protocolHasPayload() const;
virtual quint32 protocolFrameCksum(int streamIndex = 0,
CksumType cksumType = CksumIp) const;
CksumType cksumType = CksumIp, CksumFlags cksumFlags = 0) const;
quint32 protocolFrameHeaderCksum(int streamIndex = 0,
CksumType cksumType = CksumIp,
CksumScope cksumScope = CksumScopeAdjacentProtocol) const;

View File

@ -168,14 +168,16 @@ public:
}
virtual quint32 protocolFrameCksum(int streamIndex = 0,
CksumType cksumType = CksumIp) const
CksumType cksumType = CksumIp, CksumFlags cksumFlags = 0) const
{
// For a Pseudo IP cksum, we assume it is the succeeding protocol
// that is requesting it and hence return protoB's cksum;
if (cksumType == CksumIpPseudo)
return protoB->protocolFrameCksum(streamIndex, cksumType);
return protoB->protocolFrameCksum(
streamIndex,cksumType, cksumFlags);
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
return AbstractProtocol::protocolFrameCksum(
streamIndex, cksumType, cksumFlags);
}
#if 0
quint32 protocolFrameHeaderCksum(int streamIndex = 0,

View File

@ -845,7 +845,7 @@ int Ip4Protocol::protocolFrameVariableCount() const
}
quint32 Ip4Protocol::protocolFrameCksum(int streamIndex,
CksumType cksumType) const
CksumType cksumType, CksumFlags cksumFlags) const
{
switch (cksumType)
{
@ -876,7 +876,8 @@ quint32 Ip4Protocol::protocolFrameCksum(int streamIndex,
break;
}
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
return AbstractProtocol::protocolFrameCksum(
streamIndex, cksumType, cksumFlags);
}
bool Ip4Protocol::hasErrors(QStringList *errors) const

View File

@ -89,7 +89,7 @@ public:
virtual int protocolFrameVariableCount() const;
virtual quint32 protocolFrameCksum(int streamIndex = 0,
CksumType cksumType = CksumIp) const;
CksumType cksumType = CksumIp, CksumFlags cksumFlags = 0) const;
virtual bool hasErrors(QStringList *errors = nullptr) const;
private:

View File

@ -740,7 +740,7 @@ int Ip6Protocol::protocolFrameVariableCount() const
}
quint32 Ip6Protocol::protocolFrameCksum(int streamIndex,
CksumType cksumType) const
CksumType cksumType, CksumFlags cksumFlags) const
{
if (cksumType == CksumIpPseudo)
{
@ -764,7 +764,8 @@ quint32 Ip6Protocol::protocolFrameCksum(int streamIndex,
return qFromBigEndian((quint16) ~sum);
}
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
return AbstractProtocol::protocolFrameCksum(
streamIndex, cksumType, cksumFlags);
}
bool Ip6Protocol::hasErrors(QStringList *errors) const

View File

@ -103,7 +103,7 @@ public:
virtual int protocolFrameVariableCount() const;
virtual quint32 protocolFrameCksum(int streamIndex = 0,
CksumType cksumType = CksumIp) const;
CksumType cksumType = CksumIp, CksumFlags cksumFlags = 0) const;
virtual bool hasErrors(QStringList *errors = nullptr) const;
private:

View File

@ -225,7 +225,7 @@ int UserScriptProtocol::protocolFrameVariableCount() const
}
quint32 UserScriptProtocol::protocolFrameCksum(int streamIndex,
CksumType cksumType) const
CksumType cksumType, CksumFlags cksumFlags) const
{
QScriptValue userFunction;
QScriptValue userValue;
@ -243,9 +243,12 @@ quint32 UserScriptProtocol::protocolFrameCksum(int streamIndex,
Q_ASSERT(userFunction.isFunction());
userValue = userFunction.call(QScriptValue(),
QScriptValueList() << QScriptValue(&engine_, streamIndex)
<< QScriptValue(&engine_, cksumType));
userValue = userFunction.call(
QScriptValue(),
QScriptValueList()
<< QScriptValue(&engine_, streamIndex)
<< QScriptValue(&engine_, cksumType)
<< QScriptValue(&engine_, cksumFlags));
Q_ASSERT(userValue.isValid());
Q_ASSERT(userValue.isNumber());
@ -253,7 +256,8 @@ quint32 UserScriptProtocol::protocolFrameCksum(int streamIndex,
return userValue.toUInt32();
_do_default:
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
return AbstractProtocol::protocolFrameCksum(
streamIndex, cksumType, cksumFlags);
}
void UserScriptProtocol::evaluateUserScript() const

View File

@ -58,6 +58,13 @@ public:
CksumTcpUdp = AbstractProtocol::CksumTcpUdp
};
enum CksumFlag
{
IncludeCksumField = AbstractProtocol::IncludeCksumField
};
Q_DECLARE_FLAGS(CksumFlags, CksumFlag);
Q_FLAG(CksumFlags);
UserProtocol(AbstractProtocol *parent);
public slots:
@ -131,7 +138,7 @@ public:
virtual int protocolFrameVariableCount() const;
virtual quint32 protocolFrameCksum(int streamIndex = 0,
CksumType cksumType = CksumIp) const;
CksumType cksumType = CksumIp, CksumFlags cksumFlags = 0) const;
void evaluateUserScript() const;
bool isScriptValid() const;