Skip to content

Commit

Permalink
create S7COMM protocol and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wivien19 committed Aug 21, 2023
1 parent aa4e62d commit 6791f63
Show file tree
Hide file tree
Showing 12 changed files with 308 additions and 7 deletions.
2 changes: 2 additions & 0 deletions Packet++/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ add_library(
src/PPPoELayer.cpp
src/RadiusLayer.cpp
src/RawPacket.cpp
src/S7commLayer.cpp
src/SdpLayer.cpp
src/SingleCommandTextProtocol.cpp
src/SipLayer.cpp
Expand Down Expand Up @@ -103,6 +104,7 @@ set(public_headers
header/ProtocolType.h
header/RadiusLayer.h
header/RawPacket.h
header/S7commLayer.h
header/SdpLayer.h
header/SingleCommandTextProtocol.h
header/SipLayer.h
Expand Down
2 changes: 1 addition & 1 deletion Packet++/header/CotpLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ namespace pcpp
void computeCalculateFields() override {}

/**
* Currently parses the rest of the packet as a generic payload (PayloadLayer)
* Currently parses the rest of the packet as a S7COMM or generic payload (PayloadLayer)
*/
void parseNextLayer() override;

Expand Down
5 changes: 5 additions & 0 deletions Packet++/header/ProtocolType.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ namespace pcpp
*/
const ProtocolType SLL2 = 0x8000000000000;

/**
* S7COMM protocol
*/
const ProtocolType S7COMM = 0x9000000000000;

/**
* An enum representing OSI model layers
*/
Expand Down
149 changes: 149 additions & 0 deletions Packet++/header/S7commLayer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#ifndef PCAPPLUSPLUS_S7COMMLAYER_H
#define PCAPPLUSPLUS_S7COMMLAYER_H

#include "EthLayer.h"
#include "Layer.h"

namespace pcpp
{
/**
* @struct s7commhdr
* Represents a S7COMM protocol header
*/
#pragma pack(push, 1)
typedef struct
{
/** protocol id */
uint8_t protocol_id;
/** message type */
uint8_t msg_type;
/** redundancy identification (reserved) */
uint16_t reserved;
/** protocol data unit reference */
uint16_t pdu_ref;
/** parameter length */
uint16_t param_length;
/** data length */
uint16_t data_length;
} s7commhdr;
#pragma pack(pop)

/**
* @class S7commLayer
* Represents a S7COMM (S7 Communication7) protocol
*/
class S7commLayer : public Layer
{
public:
/**
* A constructor that allocates a new S7comm header
* @param[in] msg_type The general type of the message
* @param[in] pdu_ref Link responses to their requests
* @param[in] param_length The length of the parameter field
* @param[in] data_length The length of the data field
*/
S7commLayer(uint8_t msg_type, uint16_t pdu_ref, uint16_t param_length, uint16_t data_length);

/**
* A constructor that creates the layer from an existing packet raw data
* @param[in] data A pointer to the raw data (will be casted to @ref s7commhdr)
* @param[in] dataLen Size of the data in bytes
* @param[in] prevLayer A pointer to the previous layer
* @param[in] packet A pointer to the Packet instance where layer will be stored in
*/
S7commLayer(uint8_t *data, size_t dataLen, Layer *prevLayer, Packet *packet)
: Layer(data, dataLen, prevLayer, packet)
{
m_Protocol = S7COMM;
}

virtual ~S7commLayer() {}

/**
* @return S7comm protocol id
*/
uint8_t getProtocolId() const;

/**
* @return S7comm message type
*/
uint8_t getMsgType() const;

/**
* @return S7comm reserved
*/
uint16_t getReserved() const;

/**
* @return S7comm PDU ref
*/
uint16_t getPduRef() const;

/**
* @return S7comm parameter length
*/
uint16_t getParamLength() const;

/**
* @return S7comm data length
*/
uint16_t getDataLength() const;

/**
* Set the value of the message type
* @param[in] msg_type The value of the message type
*/
void setMsgType(uint8_t msg_type) const;

/**
* Set the value of the PDU ref
* @param[in] pdu_ref The value of the PDU ref
*/
void setPduRef(uint16_t pdu_ref) const;

/**
* Set the value of the parameter length
* @param[in] param_length The value of the parameter length
*/
void setParamLength(uint16_t param_length) const;

/**
* Set the value of the data length
* @param[in] data_length The value of the data length
*/
void setDataLength(uint16_t data_length) const;

/**
* @return Size of @ref s7commhdr
*/
size_t getHeaderLen() const override { return sizeof(s7commhdr); }

/**
* Does nothing for this layer
*/
void computeCalculateFields() override {}

/**
* Does nothing for this layer
*/
void parseNextLayer() override {}

/**
* A static method that takes a byte array and detects whether it is a S7COMM
* @param[in] data A byte array
* @param[in] dataSize The byte array size (in bytes)
* @return True if the data looks like a valid S7COMM layer
*/
static bool isDataValid(const uint8_t *data, size_t dataSize);

std::string toString() const;

OsiModelLayer getOsiModelLayer() const override { return OsiModelApplicationLayer; }


private:
s7commhdr *getS7commHeader() const { return (s7commhdr *)m_Data; }
};

} // namespace pcpp
#endif // PCAPPLUSPLUS_S7COMMLAYER_H
13 changes: 7 additions & 6 deletions Packet++/src/CotpLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <cstring>
#include <iostream>
#include <sstream>
#include "S7commLayer.h"

namespace pcpp
{
Expand All @@ -21,10 +22,7 @@ namespace pcpp
m_Protocol = COTP;
}

std::string CotpLayer::toString() const
{
return "Cotp Layer";
}
std::string CotpLayer::toString() const { return "Cotp Layer"; }

uint8_t CotpLayer::getLength() const { return getCotpHeader()->length; }

Expand All @@ -43,7 +41,7 @@ namespace pcpp
if (!data || dataSize < sizeof(cotphdr))
return false;

return data[1] == 0xf0 && data[0] == 2;
return data[1] == 0xf0 && data[0] == 2;
}

void CotpLayer::parseNextLayer()
Expand All @@ -55,6 +53,9 @@ namespace pcpp
uint8_t *payload = m_Data + headerLen;
size_t payloadLen = m_DataLen - headerLen;

m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
if (S7commLayer::isDataValid(payload, payloadLen))
m_NextLayer = new S7commLayer(payload, payloadLen, this, m_Packet);
else
m_NextLayer = new PayloadLayer(payload, payloadLen, this, m_Packet);
}
} // namespace pcpp
93 changes: 93 additions & 0 deletions Packet++/src/S7commLayer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "EndianPortable.h"
#include "TpktLayer.h"

#include <iostream>
#include "TcpLayer.h"
#include "S7commLayer.h"

#include <cstring>
#include <sstream>

namespace pcpp {

S7commLayer::S7commLayer(uint8_t msg_type, uint16_t pdu_ref,
uint16_t param_length, uint16_t data_length) {
const size_t headerLen = sizeof(s7commhdr);
m_DataLen = headerLen;
m_Data = new uint8_t[headerLen];
memset(m_Data, 0, headerLen);
s7commhdr *s7commHdr = (s7commhdr *) m_Data;
s7commHdr->protocol_id = 0x32;
s7commHdr->msg_type = msg_type;
s7commHdr->reserved = 0x0000;
s7commHdr->pdu_ref = htobe16(pdu_ref);
s7commHdr->param_length = htobe16(param_length);
s7commHdr->data_length = htobe16(data_length);
m_Protocol = S7COMM;
}

std::string S7commLayer::toString() const {
std::ostringstream msgTypeStream;
msgTypeStream << getMsgType();
std::ostringstream pduRefStream;
pduRefStream << getPduRef();
std::ostringstream paramLengthStream;
paramLengthStream << getParamLength();
std::ostringstream dataLengthStream;
dataLengthStream << getDataLength();

return "S7comm Layer, msg_type: " + msgTypeStream.str() +
", pdu_ref: " + pduRefStream.str() +
", param_length: " + paramLengthStream.str() +
", data_length: " + dataLengthStream.str();

}

bool S7commLayer::isDataValid(const uint8_t *data, size_t dataSize)
{
if (!data || dataSize < sizeof(s7commhdr))
return false;

return data[0] == 0x32;
}

uint8_t S7commLayer::getProtocolId() const {
return getS7commHeader()->protocol_id;
}

uint8_t S7commLayer::getMsgType() const {
return getS7commHeader()->msg_type;
}

uint16_t S7commLayer::getReserved() const {
return htobe16(getS7commHeader()->reserved);
}

uint16_t S7commLayer::getParamLength() const {
return htobe16(getS7commHeader()->param_length);
}

uint16_t S7commLayer::getPduRef() const {
return htobe16(getS7commHeader()->pdu_ref);;
}

uint16_t S7commLayer::getDataLength() const {
return htobe16(getS7commHeader()->data_length);
}

void S7commLayer::setMsgType(uint8_t msg_type) const {
getS7commHeader()->msg_type = msg_type;
}

void S7commLayer::setParamLength(uint16_t param_length) const {
getS7commHeader()->param_length = htobe16(param_length);
}

void S7commLayer::setPduRef(uint16_t pdu_ref) const {
getS7commHeader()->pdu_ref = htobe16(pdu_ref);
}

void S7commLayer::setDataLength(uint16_t data_length) const {
getS7commHeader()->data_length = htobe16(data_length);
}
} // namespace pcpp
1 change: 1 addition & 0 deletions Tests/Packet++Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ add_executable(
Tests/PacketUtilsTests.cpp
Tests/PPPoETests.cpp
Tests/RadiusTests.cpp
Tests/S7commTests.cpp
Tests/SipSdpTests.cpp
Tests/Sll2Tests.cpp
Tests/SllNullLoopbackTests.cpp
Expand Down
1 change: 1 addition & 0 deletions Tests/Packet++Test/PacketExamples/S7comm.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
005056b837d1000e8cd0f9cb0800450001190fc400001e0676970a4900d30a4900200066f0480072171153f0fa9950181000bc050000030000f102f08032070000fd0b000c00d4000112081284010100000000ff0900d000a000000014000a4302ff68c70000000814771421090815333765641381fe64c77200000814771421090815333765544301ff46c7720000081477142109081533375274430eff23000000000000000021073117382880074546ff32c0c08ffe0000000021073117382409174300fff3000000000000000021073117382409176522ff030000000100018ffe21073117382409174580fff200000002000000002107302334535946494eff8fc00000000000000021073023345359264302ff68c7000000001477142104271604011663
Binary file added Tests/Packet++Test/PacketExamples/s7comm.pcap
Binary file not shown.
3 changes: 3 additions & 0 deletions Tests/Packet++Test/TestDefinition.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,6 @@ PTF_TEST_CASE(VrrpCreateAndEditTest);

//Implemented in CotpTests.cpp
PTF_TEST_CASE(CotpLayerTest);

//Implemented in S7commTests.cpp
PTF_TEST_CASE(S7commLayerTest);
44 changes: 44 additions & 0 deletions Tests/Packet++Test/Tests/S7commTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "../TestDefinition.h"
#include "../Utils/TestUtils.h"
#include "EndianPortable.h"
#include "Packet.h"
#include "S7commLayer.h"
#include <stdio.h>

PTF_TEST_CASE(S7commLayerTest) {
timeval time;
gettimeofday(&time, NULL);

READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/S7comm.dat");

pcpp::Packet S7commLayerTest(&rawPacket1);
PTF_ASSERT_TRUE(S7commLayerTest.isPacketOfType(pcpp::S7COMM));
auto *s7commLayer = S7commLayerTest.getLayerOfType<pcpp::S7commLayer>();
PTF_ASSERT_NOT_NULL(s7commLayer);

PTF_ASSERT_EQUAL(s7commLayer->getProtocolId(), 0x32);
PTF_ASSERT_EQUAL(s7commLayer->getMsgType(), 0x07);
PTF_ASSERT_EQUAL(s7commLayer->getReserved(), htobe16(0));
PTF_ASSERT_EQUAL(s7commLayer->getPduRef(), 0xfd0b);
PTF_ASSERT_EQUAL(s7commLayer->getParamLength(), 12);
PTF_ASSERT_EQUAL(s7commLayer->getDataLength(), 212);

pcpp::S7commLayer newS7commPacket(0x09, 0xfd0c, 13, 213);

PTF_ASSERT_EQUAL(newS7commPacket.getMsgType(), 0x09);
PTF_ASSERT_EQUAL(newS7commPacket.getPduRef(), 0xfd0c);
PTF_ASSERT_EQUAL(newS7commPacket.getParamLength(), 13);
PTF_ASSERT_EQUAL(newS7commPacket.getDataLength(), 213);


newS7commPacket.setMsgType(0x06);
newS7commPacket.setPduRef(0xfd0a);
newS7commPacket.setParamLength(15);
newS7commPacket.setDataLength(215);

PTF_ASSERT_EQUAL(newS7commPacket.getMsgType(), 0x06);
PTF_ASSERT_EQUAL(newS7commPacket.getPduRef(), 0xfd0a);
PTF_ASSERT_EQUAL(newS7commPacket.getParamLength(), 15);
PTF_ASSERT_EQUAL(newS7commPacket.getDataLength(), 215);

} // S7commLayerTest
2 changes: 2 additions & 0 deletions Tests/Packet++Test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,5 +316,7 @@ int main(int argc, char* argv[])

PTF_RUN_TEST(CotpLayerTest, "cotp");

PTF_RUN_TEST(S7commLayerTest, "s7comm");

PTF_END_RUNNING_TESTS;
}

0 comments on commit 6791f63

Please sign in to comment.