Calculate L4 checksum offset for TTag packets

This commit is contained in:
Srivats P 2023-04-11 18:09:14 +05:30
parent 70b5e60440
commit c2967b663d
4 changed files with 233 additions and 2 deletions

View File

@ -113,6 +113,7 @@ SOURCES += \
udp.cpp \
textproto.cpp \
hexdump.cpp \
packet.cpp \
payload.cpp \
sample.cpp \
sign.cpp \

117
common/packet.cpp Normal file
View File

@ -0,0 +1,117 @@
/*
Copyright (C) 2023 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include "packet.h"
using namespace Packet;
quint16 Packet::l4ChecksumOffset(const uchar *pktData, int pktLen)
{
Parser parser(pktData, pktLen);
quint16 offset = kEthTypeOffset;
// Skip VLANs, if any
quint16 ethType = parser.field16(offset);
if (!parser.ok()) return 0;
// TODO: support 802.3 frames
if (ethType <= 1500)
return 0;
while (kVlanEthTypes.contains(ethType)) {
offset += kVlanTagSize;
ethType = parser.field16(offset);
if (!parser.ok()) return 0;
}
offset += kEthTypeSize;
// XXX: offset now points to Eth payload
// Skip MPLS tags, if any
if (ethType == kMplsEthType) {
while (1) {
quint32 mplsTag = parser.field32(offset);
if (!parser.ok()) return 0;
offset += kMplsTagSize;
if (mplsTag & 0x100) { // BOS bit
quint32 nextWord = parser.field32(offset);
if (!parser.ok()) return 0;
if (nextWord == 0) { // PW Control Word
offset += kMplsTagSize;
ethType = 0;
break;
}
quint8 firstPayloadNibble = nextWord >> 28;
if (firstPayloadNibble == 0x4)
ethType = kIp4EthType;
else if (firstPayloadNibble == 0x6)
ethType = kIp6EthType;
else
ethType = 0;
break;
}
}
}
quint8 ipProto = 0;
if (ethType == kIp4EthType) {
ipProto = parser.field8(offset + kIp4ProtocolOffset);
if (!parser.ok()) return 0;
quint8 ipHdrLen = parser.field8(offset) & 0x0F;
if (!parser.ok()) return 0;
offset += 4*ipHdrLen;
} else if (ethType == kIp6EthType) {
ipProto = parser.field8(offset + kIp6NextHeaderOffset);
if (!parser.ok()) return 0;
offset += kIp6HeaderSize;
// XXX: offset now points to IPv6 payload
// Skip IPv6 extension headers, if any
while (kIp6ExtensionHeaders.contains(ipProto)) {
ipProto = parser.field8(offset + kIp6ExtNextHeaderOffset);
if (!parser.ok()) return 0;
quint16 extHdrLen = parser.field8(offset + kIp6ExtLengthOffset);
offset += 8 + 8*extHdrLen;
}
} else {
// Non-IP
// TODO: support MPLS PW with Eth payload
return 0;
}
// XXX: offset now points to IP payload
if (ipProto == kIpProtoTcp) {
parser.field16(offset + kTcpChecksumOffset);
if (!parser.ok()) return 0;
return offset + kTcpChecksumOffset;
} else if (ipProto == kIpProtoUdp) {
parser.field16(offset + kUdpChecksumOffset);
if (!parser.ok()) return 0;
return offset + kUdpChecksumOffset;
}
// No L4
return 0;
}

112
common/packet.h Normal file
View File

@ -0,0 +1,112 @@
/*
Copyright (C) 2023 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef _PACKET_H
#define _PACKET_H
#include <QSet>
#include <QtGlobal>
namespace Packet {
class Parser {
public:
Parser(const uchar *data, int length)
: pktData_(data), pktLen_(length) {}
quint8 field8(int offset) {
if (offset >= pktLen_) {
ok_ = false;
return 0;
}
ok_ = true;
return pktData_[offset];
}
quint16 field16(int offset) {
if (offset + 1 >= pktLen_) {
ok_ = false;
return 0;
}
ok_ = true;
return pktData_[offset] << 8
| pktData_[offset+1];
}
quint32 field32(int offset) {
if (offset + 3 >= pktLen_) {
ok_ = false;
return 0;
}
ok_ = true;
return pktData_[offset] << 24
| pktData_[offset+1] << 16
| pktData_[offset+2] << 8
| pktData_[offset+3];
}
bool ok() {
return ok_;
}
private:
const uchar *pktData_;
int pktLen_;
bool ok_{false};
};
quint16 l4ChecksumOffset(const uchar *pktData, int pktLen);
//
// Constants
//
// Ethernet
const quint16 kEthTypeOffset = 12;
const quint16 kEthTypeSize = 2;
const quint16 kIp4EthType = 0x0800;
const quint16 kIp6EthType = 0x86dd;
const quint16 kMplsEthType = 0x8847;
const QSet<quint16> kVlanEthTypes = {0x8100, 0x9100, 0x88a8};
// VLAN
const quint16 kVlanTagSize = 4;
// MPLS
const quint16 kMplsTagSize = 4;
// IPv4
const quint16 kIp4ProtocolOffset = 9;
// IPv6
const quint16 kIp6HeaderSize = 40;
const quint16 kIp6NextHeaderOffset = 6;
// IPv6 Extension Header
const quint16 kIp6ExtNextHeaderOffset = 0;
const quint16 kIp6ExtLengthOffset = 1;
// IPv4/IPv6 Proto/NextHeader values
const quint8 kIpProtoTcp = 6;
const quint8 kIpProtoUdp = 17;
const QSet<quint8> kIp6ExtensionHeaders = {0, 60, 43, 44, 51, 50, 60, 135}; // FIXME: use names
// TCP
const quint16 kTcpChecksumOffset = 16;
// UDP
const quint16 kUdpChecksumOffset = 6;
};
#endif

View File

@ -20,8 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#ifndef _PACKET_SEQUENCE_H
#define _PACKET_SEQUENCE_H
#include "pcapextra.h"
#include "../common/packet.h"
#include "../common/sign.h"
#include "pcapextra.h"
#include "streamstats.h"
class PacketSequence
@ -72,7 +73,7 @@ public:
}
}
if (trackGuidStats_ && (packets_ == 1)) // first packet of seq
ttagL4CksumOffset_ = 40; // FIXME
ttagL4CksumOffset_ = Packet::l4ChecksumOffset(pktData, pktHeader->caplen);
return ret;
}
pcap_send_queue *sendQueue_;