Skip to content

Commit

Permalink
Add S7COMM protocol (#1185)
Browse files Browse the repository at this point in the history
  • Loading branch information
wivien19 authored Nov 6, 2023
1 parent 7323fb6 commit f6c8acc
Show file tree
Hide file tree
Showing 15 changed files with 464 additions and 13 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 = 0x10000000000000;

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

#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 protocolId;
/** message type */
uint8_t msgType;
/** redundancy identification (reserved) */
uint16_t reserved;
/** protocol data unit reference */
uint16_t pduRef;
/** parameter length */
uint16_t paramLength;
/** data length */
uint16_t dataLength;
} s7commhdr;
#pragma pack(pop)

/**
* @struct s7comm_ack_data_hdr
* Represents a S7COMM protocol header with Ack-Data header
*/
#pragma pack(push, 1)
struct s7comm_ack_data_hdr : s7commhdr
{
/** error class */
uint8_t errorClass;
/** error code */
uint8_t errorCode;
};
#pragma pack(pop)

/**
* @class S7CommParameter
* Represents a S7COMM (S7 Communication) protocol Parameter
*/
class S7CommParameter
{
friend class S7CommLayer;

public:
S7CommParameter() {}

virtual ~S7CommParameter() {}

/**
* @return The data of the Parameter
*/
uint8_t *getData() const { return m_Data; }
/**
* @return The length of the Parameter data
*/
size_t getDataLength() const { return m_DataLen; }

private:
S7CommParameter(uint8_t *data, size_t dataLen) : m_Data(data), m_DataLen(dataLen) {}
uint8_t *m_Data;
size_t m_DataLen;
};
/**
* @class S7CommLayer
* Represents a S7COMM (S7 Communication) protocol
*/
class S7CommLayer : public Layer
{
public:
/**
* A constructor that allocates a new S7comm header
* @param[in] msgType The general type of the message
* @param[in] pduRef Link responses to their requests
* @param[in] paramLength The length of the parameter field
* @param[in] dataLength The length of the data field
* @param[in] errorClass The value of the error class
* @param[in] errorCode The value of the error code
*/
S7CommLayer(uint8_t msgType, uint16_t pduRef, uint16_t paramLength, uint16_t dataLength, uint8_t errorClass = 0,
uint8_t errorCode = 0);

/**
* 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;
m_Parameter = nullptr;
}

virtual ~S7CommLayer()
{
if (m_Parameter)
delete m_Parameter;
}

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

/**
* @return S7comm message type
*/
uint8_t getMsgType() 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;

/**
* @return S7comm error code
*/
uint8_t getErrorCode() const;

/**
* @return S7comm error class
*/
uint8_t getErrorClass() const;

/**
* @return S7comm parameter
*/
const S7CommParameter *getParameter();

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

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

/**
* Set the value of the error code
* @param[in] errorCode The value of the error code
*/
void setErrorCode(uint8_t errorCode) const;
/**
* Set the value of the error class
* @param[in] errorClass The value of the error class
*/
void setErrorClass(uint8_t errorClass) const;

/**
* @return Size of S7CommLayer
*/
size_t getHeaderLen() const override { return m_DataLen; }

/**
* Does nothing for this layer (S7CommLayer is always last)
*/
void computeCalculateFields() override {}

/**
* Does nothing for this layer (S7CommLayer is always last)
*/
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 override;

OsiModelLayer getOsiModelLayer() const override { return OsiModelApplicationLayer; }

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

s7comm_ack_data_hdr *getS7commAckDataHeader() const
{
if (getS7commHeader()->msgType == 0x03)
{
return (s7comm_ack_data_hdr *)m_Data;
}
return nullptr;
}

size_t getS7commHeaderLength() const;

S7CommParameter *m_Parameter;
};

} // namespace pcpp

#endif // PACKETPP_S7COMM_LAYER
13 changes: 7 additions & 6 deletions Packet++/src/CotpLayer.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "../header/CotpLayer.h"
#include "EndianPortable.h"
#include "S7CommLayer.h"
#include <PayloadLayer.h>
#include <cstring>
#include <iostream>
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
Loading

0 comments on commit f6c8acc

Please sign in to comment.