#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 */ explicit 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 */