libraries/pcappp/include/pcapplusplus/GreLayer.h

427 lines
15 KiB
C++

#ifndef PACKETPP_GRE_LAYER
#define PACKETPP_GRE_LAYER
#include "Layer.h"
/// @file
/**
* \namespace pcpp
* \brief The main namespace for the PcapPlusPlus lib
*/
namespace pcpp
{
/**
* @struct gre_basic_header
* Represents GRE basic protocol header (common for GREv0 and GREv1)
*/
#pragma pack(push, 1)
struct gre_basic_header
{
#if (BYTE_ORDER == LITTLE_ENDIAN)
/** Number of additional encapsulations which are permitted. 0 is the default value */
uint8_t recursionControl:3,
/** Strict source routing bit (GRE v0 only) */
strictSourceRouteBit:1,
/** Set if sequence number exists */
sequenceNumBit:1,
/** Set if key exists */
keyBit:1,
/** Set if routing exists (GRE v0 only) */
routingBit:1,
/** Set if checksum exists (GRE v0 only) */
checksumBit:1;
#else
/** Set if checksum exists (GRE v0 only) */
uint8_t checksumBit:1,
/** Set if routing exists (GRE v0 only) */
routingBit:1,
/** Set if key exists */
keyBit:1,
/** Set if sequence number exists */
sequenceNumBit:1,
/** Strict source routing bit (GRE v0 only) */
strictSourceRouteBit:1,
/** Number of additional encapsulations which are permitted. 0 is the default value */
recursionControl:3;
#endif
#if (BYTE_ORDER == LITTLE_ENDIAN)
/** GRE version - can be 0 or 1 */
uint8_t version:3,
/** Reserved */
flags:4,
/** Set if acknowledgment number is set (GRE v1 only) */
ackSequenceNumBit:1;
#else
/** Set if acknowledgment number is set (GRE v1 only) */
uint8_t ackSequenceNumBit:1,
/** Reserved */
flags:4,
/** GRE version - can be 0 or 1 */
version:3;
#endif
/** Protocol type of the next layer */
uint16_t protocol;
};
#pragma pack(pop)
/**
* @struct gre1_header
* Represents GREv1 protocol header
*/
#pragma pack(push, 1)
struct gre1_header : gre_basic_header
{
/** Size of the payload not including the GRE header */
uint16_t payloadLength;
/** Contains the Peer's Call ID for the session to which this packet belongs */
uint16_t callID;
};
#pragma pack(pop)
/**
* @struct ppp_pptp_header
* Represents PPP layer that comes after GREv1 as part of PPTP protocol
*/
#pragma pack(push, 1)
struct ppp_pptp_header
{
/** Broadcast address */
uint8_t address;
/** Control byte */
uint8_t control;
/** Protocol type of the next layer (see PPP_* macros at PPPoELayer.h) */
uint16_t protocol;
};
#pragma pack(pop)
/**
* @class GreLayer
* Abstract base class for GRE layers (GREv0Layer and GREv1Layer). Cannot be instantiated and contains common logic for derived classes
*/
class GreLayer : public Layer
{
public:
virtual ~GreLayer() {}
/**
* A static method that determines the GRE version of GRE layer raw data by looking at the gre_basic_header#version
* field
* @param[in] greData GRE layer raw data
* @param[in] greDataLen Size of raw data
* @return ::GREv0 or ::GREv1 values if raw data is GREv0 or GREv1 (accordingly) or ::UnknownProtocol otherwise
*/
static ProtocolType getGREVersion(uint8_t* greData, size_t greDataLen);
/**
* Get sequence number value if field exists in layer
* @param[out] seqNumber The returned sequence number value if exists in layer. Else remain unchanged
* @return True if sequence number field exists in layer. In this case seqNumber will be filled with the value.
* Or false if sequence number field doesn't exist in layer
*/
bool getSequenceNumber(uint32_t& seqNumber) const;
/**
* Set sequence number value. If field already exists (gre_basic_header#sequenceNumBit is set) then only the new
* value is set. If field doesn't exist it will be added to the layer, gre_basic_header#sequenceNumBit will be set
* and the new value will be set
* @param[in] seqNumber The sequence number value to set
* @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
*/
bool setSequenceNumber(uint32_t seqNumber);
/**
* Unset sequence number and remove it from the layer
* @return True if managed to unset successfully or false (and error log) if sequence number wasn't set in the first
* place or if didn't manage to remove it from the layer
*/
bool unsetSequenceNumber();
// implement abstract methods
/**
* Currently identifies the following next layers:
* IPv4Layer, IPv6Layer, VlanLayer, MplsLayer, PPP_PPTPLayer, EthLayer, EthDot3Layer
* Otherwise sets PayloadLayer
*/
void parseNextLayer();
/**
* @return Size of GRE header (may change if optional fields are added or removed)
*/
size_t getHeaderLen() const;
OsiModelLayer getOsiModelLayer() const { return OsiModelNetworkLayer; }
protected:
GreLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet) { }
GreLayer() {}
enum GreField
{
GreChecksumOrRouting = 0,
GreKey = 1,
GreSeq = 2,
GreAck = 3
};
uint8_t* getFieldValue(GreField field, bool returnOffsetEvenIfFieldMissing) const;
void computeCalculateFieldsInner();
};
/**
* @class GREv0Layer
* Represents a GRE version 0 protocol. Limitation: currently this layer doesn't support GRE routing information parsing
* and editing. So if a GREv0 packet includes routing information it won't be parse correctly. I didn't add it because
* of lack of time, but if you need it please tell me and I'll add it
*/
class GREv0Layer : public GreLayer
{
public:
/** A constructor that creates the layer from an existing packet raw data
* @param[in] data A pointer to the raw data
* @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
*/
GREv0Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : GreLayer(data, dataLen, prevLayer, packet) { m_Protocol = GREv0; }
/**
* A constructor that creates a new GREv0 header and allocates the data
*/
GREv0Layer();
virtual ~GREv0Layer() {}
/**
* Get a pointer to the basic GRE header containing only non-optional fields. Notice this points directly to the data,
* so every change will change the actual packet data. Also please notice that changing the set bits
* (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit, gre_basic_header#routingBit,
* gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using the proper set or unset methods (such
* as setChecksum(), unsetChecksum(), etc.) may result to wrong calculation of header length and really weird bugs.
* Please avoid doing so
* @return A pointer to the gre_basic_header
*/
gre_basic_header* getGreHeader() const { return (gre_basic_header*)m_Data; }
/**
* Get checksum value if field exists in layer
* @param[out] checksum The returned checksum value if exists in layer. Else remain unchanged
* @return True if checksum field exists in layer. In this case checksum parameter will be filled with the value.
* Or false if checksum field doesn't exist in layer
*/
bool getChecksum(uint16_t& checksum);
/**
* Set checksum value. If checksum or offset fields already exist (gre_basic_header#checksumBit or gre_basic_header#routingBit are set)
* then only the new value is set. If both fields don't exist a new 4-byte value will be added to the layer,
* gre_basic_header#checksumBit will be set (gre_basic_header#routingBit will remain unset), the new checksum value
* will be set and offset value will be set to 0. The reason both fields are added is that GREv0 protocol states
* both of them or none of them should exist on packet (even if only one of the bits are set)
* @param[in] checksum The checksum value to set
* @return True if managed to set the value/s successfully, or false otherwise (if couldn't extend the layer)
*/
bool setChecksum(uint16_t checksum);
/**
* Unset checksum and possibly remove it from the layer. It will be removed from the layer only if gre_basic_header#routingBit
* is not set as well. Otherwise checksum field will remain on packet with value of 0
* @return True if managed to unset successfully or false (and error log) if checksum wasn't set in the first
* place or if didn't manage to remove it from the layer
*/
bool unsetChecksum();
/**
* Get offset value if field exists in layer. Notice there is no setOffset() method as GRE routing information isn't
* supported yet (see comment on class description)
* @param[out] offset The returned offset value if exists in layer. Else remain unchanged
* @return True if offset field exists in layer. In this case offset parameter will be filled with the value.
* Or false if offset field doesn't exist in layer
*/
bool getOffset(uint16_t& offset) const;
/**
* Get key value if field exists in layer
* @param[out] key The returned key value if exists in layer. Else remain unchanged
* @return True if key field exists in layer. In this case key parameter will be filled with the value.
* Or false if key field doesn't exist in layer
*/
bool getKey(uint32_t& key) const;
/**
* Set key value. If field already exists (gre_basic_header#keyBit is set) then only the new value is set.
* If field doesn't exist it will be added to the layer, gre_basic_header#keyBit will be set
* and the new value will be set
* @param[in] key The key value to set
* @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
*/
bool setKey(uint32_t key);
/**
* Unset key and remove it from the layer
* @return True if managed to unset successfully or false (and error log) if key wasn't set in the first
* place or if didn't manage to remove it from the layer
*/
bool unsetKey();
// implement abstract methods
/**
* Calculate the following fields:
* - gre_basic_header#protocol
* - GRE checksum field (if exists in packet)
*/
void computeCalculateFields();
std::string toString() const;
};
/**
* @class GREv1Layer
* Represents a GRE version 1 protocol
*/
class GREv1Layer : public GreLayer
{
public:
/** A constructor that creates the layer from an existing packet raw data
* @param[in] data A pointer to the raw data
* @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
*/
GREv1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : GreLayer(data, dataLen, prevLayer, packet) { m_Protocol = GREv1; }
/**
* A constructor that creates a new GREv1 header and allocates the data
* @param[in] callID The call ID to set
*/
GREv1Layer(uint16_t callID);
virtual ~GREv1Layer() {}
/**
* Get a pointer to the basic GREv1 header containing all non-optional fields. Notice this points directly to the data, so every change will change the actual
* packet data. Also please notice that changing the set bits (gre_basic_header#strictSourceRouteBit, gre_basic_header#sequenceNumBit, gre_basic_header#keyBit,
* gre_basic_header#routingBit, gre_basic_header#checksumBit, gre_basic_header#ackSequenceNumBit) without using the proper set or unset methods
* (such as setAcknowledgmentNum(), unsetSequenceNumber(), etc.) may result to wrong calculation of header length or illegal GREv1 packet and
* to some really weird bugs. Please avoid doing so
* @return A pointer to the gre1_header
*/
gre1_header* getGreHeader() const { return (gre1_header*)m_Data; }
/**
* Get acknowledgment (ack) number value if field exists in layer
* @param[out] ackNum The returned ack number value if exists in layer. Else remain unchanged
* @return True if ack number field exists in layer. In this case ackNum will be filled with the value.
* Or false if ack number field doesn't exist in layer
*/
bool getAcknowledgmentNum(uint32_t& ackNum) const;
/**
* Set acknowledgment (ack) number value. If field already exists (gre_basic_header#ackSequenceNumBit is set)
* then only the new value is set. If field doesn't exist it will be added to the layer,
* gre_basic_header#ackSequenceNumBit will be set and the new value will be set
* @param[in] ackNum The ack number value to set
* @return True if managed to set the value successfully, or false otherwise (if couldn't extend the layer)
*/
bool setAcknowledgmentNum(uint32_t ackNum);
/**
* Unset acknowledgment (ack) number and remove it from the layer
* @return True if managed to unset successfully or false (and error log) if ack number wasn't set in the first
* place or if didn't manage to remove it from the layer
*/
bool unsetAcknowledgmentNum();
// implement abstract methods
/**
* Calculate the following fields:
* - gre1_header#payloadLength
* - gre_basic_header#protocol
*/
void computeCalculateFields();
std::string toString() const;
};
/**
* @class PPP_PPTPLayer
* Represent a PPP (point-to-point) protocol header that comes after GREv1 header, as part of PPTP - Point-to-Point Tunneling Protocol
*/
class PPP_PPTPLayer : public Layer
{
public:
/**
* 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 ppp_pptp_header)
* @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
*/
PPP_PPTPLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = PPP_PPTP; }
/**
* A constructor that allocates a new PPP-PPTP header
* @param[in] address Address field
* @param[in] control Control field
*/
PPP_PPTPLayer(uint8_t address, uint8_t control);
~PPP_PPTPLayer() {}
/**
* Get a pointer to the PPP-PPTP header. Notice this points directly to the data, so every change will change the actual packet data
* @return A pointer to the @ref ppp_pptp_header
*/
ppp_pptp_header* getPPP_PPTPHeader() const { return (ppp_pptp_header*)m_Data; }
// implement abstract methods
/**
* Currently identifies the following next layers: IPv4Layer, IPv6Layer. Otherwise sets PayloadLayer
*/
void parseNextLayer();
/**
* @return The size of @ref ppp_pptp_header
*/
size_t getHeaderLen() const { return sizeof(ppp_pptp_header); }
/**
* Calculate the following fields:
* - ppp_pptp_header#protocol
*/
void computeCalculateFields();
std::string toString() const { return "PPP for PPTP Layer"; }
OsiModelLayer getOsiModelLayer() const { return OsiModelSesionLayer; }
};
} // namespace pcpp
#endif /* PACKETPP_GRE_LAYER */