#ifndef PACKETPP_RADIUS_LAYER #define PACKETPP_RADIUS_LAYER #include "Layer.h" #include "TLVData.h" /// @file /** * \namespace pcpp * \brief The main namespace for the PcapPlusPlus lib */ namespace pcpp { /** * @struct radius_header * Represents a RADIUS protocol header */ #pragma pack(push, 1) struct radius_header { /** RADIUS message code */ uint8_t code; /** RADIUS message ID */ uint8_t id; /** RADIUS message length */ uint16_t length; /** Used to authenticate the reply from the RADIUS server and to encrypt passwords */ uint8_t authenticator[16]; }; #pragma pack(pop) /** * @class RadiusAttribute * A wrapper class for RADIUS attributes. This class does not create or modify RADIUS attribute records, but rather * serves as a wrapper and provides useful methods for retrieving data from them */ class RadiusAttribute : public TLVRecord { public: /** * A c'tor for this class that gets a pointer to the attribute raw data (byte array) * @param[in] attrRawData A pointer to the attribute raw data */ explicit RadiusAttribute(uint8_t* attrRawData) : TLVRecord(attrRawData) { } /** * A d'tor for this class, currently does nothing */ virtual ~RadiusAttribute() { } // implement abstract methods size_t getTotalSize() const { if (m_Data == nullptr) return 0; return (size_t)m_Data->recordLen; } size_t getDataSize() const { if (m_Data == nullptr) return 0; return (size_t)m_Data->recordLen - 2*sizeof(uint8_t); } }; /** * @class RadiusAttributeBuilder * A class for building RADIUS attributes. This builder receives the attribute parameters in its c'tor, * builds the RADIUS attribute raw buffer and provides a build() method to get a RadiusAttribute object out of it */ class RadiusAttributeBuilder : public TLVRecordBuilder { public: /** * A c'tor for building RADIUS attributes which their value is a byte array. The RadiusAttribute object can later * be retrieved by calling build() * @param[in] attrType RADIUS attribute type * @param[in] attrValue A buffer containing the attribute value. This buffer is read-only and isn't modified in any way * @param[in] attrValueLen Attribute value length in bytes */ RadiusAttributeBuilder(uint8_t attrType, const uint8_t* attrValue, uint8_t attrValueLen) : TLVRecordBuilder(attrType, attrValue, attrValueLen) { } /** * A c'tor for building RADIUS attributes which have a 1-byte value. The RadiusAttribute object can later be retrieved * by calling build() * @param[in] attrType RADIUS attribute type * @param[in] attrValue A 1-byte attribute value */ RadiusAttributeBuilder(uint8_t attrType, uint8_t attrValue) : TLVRecordBuilder(attrType, attrValue) { } /** * A c'tor for building RADIUS attributes which have a 2-byte value. The RadiusAttribute object can later be retrieved * by calling build() * @param[in] attrType RADIUS attribute type * @param[in] attrValue A 2-byte attribute value */ RadiusAttributeBuilder(uint8_t attrType, uint16_t attrValue) : TLVRecordBuilder(attrType, attrValue) { } /** * A c'tor for building RADIUS attributes which have a 4-byte value. The RadiusAttribute object can later be retrieved * by calling build() * @param[in] attrType RADIUS attribute type * @param[in] attrValue A 4-byte attribute value */ RadiusAttributeBuilder(uint8_t attrType, uint32_t attrValue) : TLVRecordBuilder(attrType, attrValue) { } /** * A c'tor for building RADIUS attributes which have an IPv4Address value. The RadiusAttribute object can later be * retrieved by calling build() * @param[in] attrType RADIUS attribute type * @param[in] attrValue The IPv4 address attribute value */ RadiusAttributeBuilder(uint8_t attrType, const IPv4Address& attrValue) : TLVRecordBuilder(attrType, attrValue) { } /** * A c'tor for building RADIUS attributes which have a string value. The RadiusAttribute object can later be retrieved * by calling build() * @param[in] attrType RADIUS attribute type * @param[in] attrValue The string attribute value */ RadiusAttributeBuilder(uint8_t attrType, const std::string& attrValue) : TLVRecordBuilder(attrType, attrValue) { } /** * A copy c'tor which copies all the data from another instance of RadiusAttributeBuilder * @param[in] other The instance to copy from */ RadiusAttributeBuilder(const RadiusAttributeBuilder& other) : TLVRecordBuilder(other) { } /** * Assignment operator that copies all data from another instance of RadiusAttributeBuilder * @param[in] other The instance to assign from */ RadiusAttributeBuilder& operator=(const RadiusAttributeBuilder& other) { TLVRecordBuilder::operator=(other); return *this; } /** * Build the RadiusAttribute object out of the parameters defined in the c'tor * @return The RadiusAttribute object */ RadiusAttribute build() const; }; /** * @class RadiusLayer * Represents a RADIUS (Remote Authentication Dial-In User Service) protocol layer */ class RadiusLayer : public Layer { private: TLVRecordReader m_AttributeReader; uint8_t* getAttributesBasePtr() const { return m_Data + sizeof(radius_header); } RadiusAttribute addAttrAt(const RadiusAttributeBuilder& attrBuilder, int offset); 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 */ RadiusLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = Radius; } /** * A constructor that creates a new layer from scratch * @param[in] code The RADIUS message code * @param[in] id The RADIUS message ID * @param[in] authenticator A pointer to a byte array containing the authenticator value * @param[in] authenticatorArrSize The authenticator byte array size. A valid size of the authenticator field is * 16 bytes. If the provided size is less than that then the byte array will be copied to the packet but the missing * bytes will stay zero. If the size is more than 16 bytes, only the first 16 bytes will be copied to the packet */ RadiusLayer(uint8_t code, uint8_t id, const uint8_t* authenticator, uint8_t authenticatorArrSize); /** * A constructor that creates a new layer from scratch * @param[in] code The RADIUS message code * @param[in] id The RADIUS message ID * @param[in] authenticator A hex string representing the authenticator value. A valid size of the authenticator * field is 16 bytes. If the hex string represents an array that is smaller than this then the missing bytes in the * packet's authenticator field will stay zero. If the hex string represents an array that is larger than 16 bytes, * only the first 16 bytes will be copied to the packet */ RadiusLayer(uint8_t code, uint8_t id, const std::string &authenticator); /** * A d'tor for this layer, currently does nothing */ ~RadiusLayer() {} /** * Get a pointer to the RADIUS header. Notice this points directly to the data, so every change will change the actual packet data * @return A pointer to the radius_header object */ radius_header* getRadiusHeader() const { return (radius_header*)m_Data; } /** * @return A hex string representation of the radius_header#authenticator byte array value */ std::string getAuthenticatorValue() const; /** * Setter for radius_header#authenticator * @param[in] authValue A hex string representing the requested authenticator value */ void setAuthenticatorValue(const std::string& authValue); /** * A static method that returns the RADIUS message string for a give message code. For example: the string * "Access-Request" will be returned for code 1 * @param[in] radiusMessageCode RADIUS message code * @return RADIUS message string */ static std::string getRadiusMessageString(uint8_t radiusMessageCode); /** * @return The first RADIUS attribute in the packet. If there are no attributes the returned value will contain * a logical NULL (RadiusAttribute#isNull() == true) */ RadiusAttribute getFirstAttribute() const; /** * Get the RADIUS attribute that comes after a given attribute. If the given attribute was the last one, the * returned value will contain a logical NULL (RadiusAttribute#isNull() == true) * @param[in] attr A given attribute * @return A RadiusAttribute object containing the attribute data that comes next, or logical NULL if the given * attribute: (1) was the last one; (2) contains a logical NULL or (3) doesn't belong to this packet */ RadiusAttribute getNextAttribute(RadiusAttribute& attr) const; /** * Get a RADIUS attribute by attribute type * @param[in] attrType RADIUS attribute type * @return A RadiusAttribute object containing the first attribute data that matches this type, or logical NULL * (RadiusAttribute#isNull() == true) if no such attribute found */ RadiusAttribute getAttribute(uint8_t attrType) const; /** * @return The number of RADIUS attributes in the packet */ size_t getAttributeCount() const; /** * Add a new RADIUS attribute at the end of the layer * @param[in] attrBuilder A RadiusAttributeBuilder object that contains the requested attribute data to add * @return A RadiusAttribute object containing the newly added RADIUS attribute data or logical NULL * (RadiusAttribute#isNull() == true) if addition failed */ RadiusAttribute addAttribute(const RadiusAttributeBuilder& attrBuilder); /** * Add a new RADIUS attribute after an existing one * @param[in] attrBuilder A RadiusAttributeBuilder object that contains the requested attribute data to add * @param[in] prevAttrType The RADIUS attribute which the newly added attribute will come after * @return A RadiusAttribute object containing the newly added RADIUS attribute data or logical NULL * (RadiusAttribute#isNull() == true) if addition failed */ RadiusAttribute addAttributeAfter(const RadiusAttributeBuilder& attrBuilder, uint8_t prevAttrType); /** * Remove an existing RADIUS attribute from the layer * @param[in] attrType The RADIUS attribute type to remove * @return True if the RADIUS attribute was successfully removed or false if type wasn't found or if removal failed */ bool removeAttribute(uint8_t attrType); /** * Remove all RADIUS attributes in this layer * @return True if all attributes were successfully removed or false if removal failed for some reason */ bool removeAllAttributes(); /** * The static method makes validation of UDP data * @param[in] udpData The pointer to the UDP payload data. It points to the first byte of RADIUS header. * @param[in] udpDataLen The payload data size * @return True if the data is valid and can represent the RADIUS packet */ static bool isDataValid(const uint8_t* udpData, size_t udpDataLen); /** * A static method that checks whether the port is considered as RADIUS * @param[in] port The port number to be checked */ static inline bool isRadiusPort(uint16_t port); // implement abstract methods /** * @return The size written in radius_header#length */ size_t getHeaderLen() const; /** * Does nothing for this layer, RADIUS is always last */ void parseNextLayer() {} /** * Calculate and store the value of radius_header#length according to the layer size */ void computeCalculateFields(); std::string toString() const; OsiModelLayer getOsiModelLayer() const { return OsiModelApplicationLayer; } }; // implementation of inline methods bool RadiusLayer::isRadiusPort(uint16_t port) { switch (port) { case 1812: case 1813: case 3799: return true; default: return false; } } // isRadiusPort } // namespace pcpp #endif // PACKETPP_RADIUS_LAYER