Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/RadiusLayer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "Layer.h"
4
#include "TLVData.h"
5
6
/// @file
7
8
/// @namespace pcpp
9
/// @brief The main namespace for the PcapPlusPlus lib
10
namespace pcpp
11
{
12
  /// @struct radius_header
13
  /// Represents a RADIUS protocol header
14
#pragma pack(push, 1)
15
  struct radius_header
16
  {
17
    /// RADIUS message code
18
    uint8_t code;
19
    /// RADIUS message ID
20
    uint8_t id;
21
    /// RADIUS message length
22
    uint16_t length;
23
    /// Used to authenticate the reply from the RADIUS server and to encrypt passwords
24
    uint8_t authenticator[16];
25
  };
26
#pragma pack(pop)
27
  static_assert(sizeof(radius_header) == 20, "radius_header size is not 20 bytes");
28
29
  /// @class RadiusAttribute
30
  /// A wrapper class for RADIUS attributes. This class does not create or modify RADIUS attribute records, but rather
31
  /// serves as a wrapper and provides useful methods for retrieving data from them
32
  class RadiusAttribute : public TLVRecord<uint8_t, uint8_t>
33
  {
34
  public:
35
    /// A c'tor for this class that gets a pointer to the attribute raw data (byte array)
36
    /// @param[in] attrRawData A pointer to the attribute raw data
37
0
    explicit RadiusAttribute(uint8_t* attrRawData) : TLVRecord(attrRawData)
38
0
    {}
39
40
    /// A d'tor for this class, currently does nothing
41
    ~RadiusAttribute() override = default;
42
43
    // implement abstract methods
44
45
    size_t getTotalSize() const override
46
0
    {
47
0
      if (m_Data == nullptr)
48
0
        return 0;
49
50
0
      return static_cast<size_t>(m_Data->recordLen);
51
0
    }
52
53
    size_t getDataSize() const override
54
0
    {
55
0
      if (m_Data == nullptr)
56
0
        return 0;
57
58
0
      return static_cast<size_t>(m_Data->recordLen) - 2 * sizeof(uint8_t);
59
0
    }
60
  };
61
62
  /// @class RadiusAttributeBuilder
63
  /// A class for building RADIUS attributes. This builder receives the attribute parameters in its c'tor,
64
  /// builds the RADIUS attribute raw buffer and provides a build() method to get a RadiusAttribute object out of it
65
  class RadiusAttributeBuilder : public TLVRecordBuilder
66
  {
67
  public:
68
    /// A c'tor for building RADIUS attributes which their value is a byte array. The RadiusAttribute object can
69
    /// later be retrieved by calling build()
70
    /// @param[in] attrType RADIUS attribute type
71
    /// @param[in] attrValue A buffer containing the attribute value. This buffer is read-only and isn't modified in
72
    /// any way
73
    /// @param[in] attrValueLen Attribute value length in bytes
74
    RadiusAttributeBuilder(uint8_t attrType, const uint8_t* attrValue, uint8_t attrValueLen)
75
        : TLVRecordBuilder(attrType, attrValue, attrValueLen)
76
0
    {}
77
78
    /// A c'tor for building RADIUS attributes which have a 1-byte value. The RadiusAttribute object can later be
79
    /// retrieved by calling build()
80
    /// @param[in] attrType RADIUS attribute type
81
    /// @param[in] attrValue A 1-byte attribute value
82
    RadiusAttributeBuilder(uint8_t attrType, uint8_t attrValue) : TLVRecordBuilder(attrType, attrValue)
83
0
    {}
84
85
    /// A c'tor for building RADIUS attributes which have a 2-byte value. The RadiusAttribute object can later be
86
    /// retrieved by calling build()
87
    /// @param[in] attrType RADIUS attribute type
88
    /// @param[in] attrValue A 2-byte attribute value
89
    RadiusAttributeBuilder(uint8_t attrType, uint16_t attrValue) : TLVRecordBuilder(attrType, attrValue)
90
0
    {}
91
92
    /// A c'tor for building RADIUS attributes which have a 4-byte value. The RadiusAttribute object can later be
93
    /// retrieved by calling build()
94
    /// @param[in] attrType RADIUS attribute type
95
    /// @param[in] attrValue A 4-byte attribute value
96
    RadiusAttributeBuilder(uint8_t attrType, uint32_t attrValue) : TLVRecordBuilder(attrType, attrValue)
97
0
    {}
98
99
    /// A c'tor for building RADIUS attributes which have an IPv4Address value. The RadiusAttribute object can later
100
    /// be retrieved by calling build()
101
    /// @param[in] attrType RADIUS attribute type
102
    /// @param[in] attrValue The IPv4 address attribute value
103
    RadiusAttributeBuilder(uint8_t attrType, const IPv4Address& attrValue) : TLVRecordBuilder(attrType, attrValue)
104
0
    {}
105
106
    /// A c'tor for building RADIUS attributes which have a string value. The RadiusAttribute object can later be
107
    /// retrieved by calling build()
108
    /// @param[in] attrType RADIUS attribute type
109
    /// @param[in] attrValue The string attribute value
110
    RadiusAttributeBuilder(uint8_t attrType, const std::string& attrValue) : TLVRecordBuilder(attrType, attrValue)
111
0
    {}
112
113
    /// A copy c'tor which copies all the data from another instance of RadiusAttributeBuilder
114
    /// @param[in] other The instance to copy from
115
    RadiusAttributeBuilder(const RadiusAttributeBuilder& other) : TLVRecordBuilder(other)
116
0
    {}
117
118
    /// Assignment operator that copies all data from another instance of RadiusAttributeBuilder
119
    /// @param[in] other The instance to assign from
120
    RadiusAttributeBuilder& operator=(const RadiusAttributeBuilder& other)
121
0
    {
122
0
      TLVRecordBuilder::operator=(other);
123
0
      return *this;
124
0
    }
125
126
    /// Build the RadiusAttribute object out of the parameters defined in the c'tor
127
    /// @return The RadiusAttribute object
128
    RadiusAttribute build() const;
129
  };
130
131
  /// @class RadiusLayer
132
  /// Represents a RADIUS (Remote Authentication Dial-In User Service) protocol layer
133
  class RadiusLayer : public Layer
134
  {
135
  private:
136
    TLVRecordReader<RadiusAttribute> m_AttributeReader;
137
138
    uint8_t* getAttributesBasePtr() const
139
0
    {
140
0
      return m_Data + sizeof(radius_header);
141
0
    }
142
143
    RadiusAttribute addAttrAt(const RadiusAttributeBuilder& attrBuilder, int offset);
144
145
  public:
146
    /// A constructor that creates the layer from an existing packet raw data
147
    /// @param[in] data A pointer to the raw data
148
    /// @param[in] dataLen Size of the data in bytes
149
    /// @param[in] prevLayer A pointer to the previous layer
150
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
151
    RadiusLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
152
5.12k
        : Layer(data, dataLen, prevLayer, packet, Radius)
153
5.12k
    {}
154
155
    /// A constructor that creates a new layer from scratch
156
    /// @param[in] code The RADIUS message code
157
    /// @param[in] id The RADIUS message ID
158
    /// @param[in] authenticator A pointer to a byte array containing the authenticator value
159
    /// @param[in] authenticatorArrSize The authenticator byte array size. A valid size of the authenticator field
160
    /// is 16 bytes. If the provided size is less than that then the byte array will be copied to the packet but the
161
    /// missing bytes will stay zero. If the size is more than 16 bytes, only the first 16 bytes will be copied to
162
    /// the packet
163
    RadiusLayer(uint8_t code, uint8_t id, const uint8_t* authenticator, uint8_t authenticatorArrSize);
164
165
    /// A constructor that creates a new layer from scratch
166
    /// @param[in] code The RADIUS message code
167
    /// @param[in] id The RADIUS message ID
168
    /// @param[in] authenticator A hex string representing the authenticator value. A valid size of the
169
    /// authenticator field is 16 bytes. If the hex string represents an array that is smaller than this then the
170
    /// missing bytes in the packet's authenticator field will stay zero. If the hex string represents an array that
171
    /// is larger than 16 bytes, only the first 16 bytes will be copied to the packet
172
    RadiusLayer(uint8_t code, uint8_t id, const std::string& authenticator);
173
174
    /// A d'tor for this layer, currently does nothing
175
5.12k
    ~RadiusLayer() override = default;
176
177
    /// Get a pointer to the RADIUS header. Notice this points directly to the data, so every change will change the
178
    /// actual packet data
179
    /// @return A pointer to the radius_header object
180
    radius_header* getRadiusHeader() const
181
10.2k
    {
182
10.2k
      return reinterpret_cast<radius_header*>(m_Data);
183
10.2k
    }
184
185
    /// @return A hex string representation of the radius_header#authenticator byte array value
186
    std::string getAuthenticatorValue() const;
187
188
    /// Setter for radius_header#authenticator
189
    /// @param[in] authValue A hex string representing the requested authenticator value
190
    void setAuthenticatorValue(const std::string& authValue);
191
192
    /// A static method that returns the RADIUS message string for a give message code. For example: the string
193
    /// "Access-Request" will be returned for code 1
194
    /// @param[in] radiusMessageCode RADIUS message code
195
    /// @return RADIUS message string
196
    static std::string getRadiusMessageString(uint8_t radiusMessageCode);
197
198
    /// @return The first RADIUS attribute in the packet. If there are no attributes the returned value will contain
199
    /// a logical null (RadiusAttribute#isNull() == true)
200
    RadiusAttribute getFirstAttribute() const;
201
202
    /// Get the RADIUS attribute that comes after a given attribute. If the given attribute was the last one, the
203
    /// returned value will contain a logical null (RadiusAttribute#isNull() == true)
204
    /// @param[in] attr A given attribute
205
    /// @return A RadiusAttribute object containing the attribute data that comes next, or logical null if the
206
    /// given attribute: (1) was the last one; (2) contains a logical null or (3) doesn't belong to this packet
207
    RadiusAttribute getNextAttribute(RadiusAttribute& attr) const;
208
209
    /// Get a RADIUS attribute by attribute type
210
    /// @param[in] attrType RADIUS attribute type
211
    /// @return A RadiusAttribute object containing the first attribute data that matches this type, or logical
212
    /// null (RadiusAttribute#isNull() == true) if no such attribute found
213
    RadiusAttribute getAttribute(uint8_t attrType) const;
214
215
    /// @return The number of RADIUS attributes in the packet
216
    size_t getAttributeCount() const;
217
218
    /// Add a new RADIUS attribute at the end of the layer
219
    /// @param[in] attrBuilder A RadiusAttributeBuilder object that contains the requested attribute data to add
220
    /// @return A RadiusAttribute object containing the newly added RADIUS attribute data or logical null
221
    /// (RadiusAttribute#isNull() == true) if addition failed
222
    RadiusAttribute addAttribute(const RadiusAttributeBuilder& attrBuilder);
223
224
    /// Add a new RADIUS attribute after an existing one
225
    /// @param[in] attrBuilder A RadiusAttributeBuilder object that contains the requested attribute data to add
226
    /// @param[in] prevAttrType The RADIUS attribute which the newly added attribute will come after
227
    /// @return A RadiusAttribute object containing the newly added RADIUS attribute data or logical null
228
    /// (RadiusAttribute#isNull() == true) if addition failed
229
    RadiusAttribute addAttributeAfter(const RadiusAttributeBuilder& attrBuilder, uint8_t prevAttrType);
230
231
    /// Remove an existing RADIUS attribute from the layer
232
    /// @param[in] attrType The RADIUS attribute type to remove
233
    /// @return True if the RADIUS attribute was successfully removed or false if type wasn't found or if removal
234
    /// failed
235
    bool removeAttribute(uint8_t attrType);
236
237
    /// Remove all RADIUS attributes in this layer
238
    /// @return True if all attributes were successfully removed or false if removal failed for some reason
239
    bool removeAllAttributes();
240
241
    /// The static method makes validation of UDP data
242
    /// @param[in] udpData The pointer to the UDP payload data. It points to the first byte of RADIUS header.
243
    /// @param[in] udpDataLen The payload data size
244
    /// @return True if the data is valid and can represent the RADIUS packet
245
    static bool isDataValid(const uint8_t* udpData, size_t udpDataLen);
246
247
    /// A static method that checks whether the port is considered as RADIUS
248
    /// @param[in] port The port number to be checked
249
    static inline bool isRadiusPort(uint16_t port);
250
251
    // implement abstract methods
252
253
    /// @return The size written in radius_header#length
254
    size_t getHeaderLen() const override;
255
256
    /// Does nothing for this layer, RADIUS is always last
257
    void parseNextLayer() override
258
5.12k
    {}
259
260
    /// Calculate and store the value of radius_header#length according to the layer size
261
    void computeCalculateFields() override;
262
263
    std::string toString() const override;
264
265
    OsiModelLayer getOsiModelLayer() const override
266
1.02k
    {
267
1.02k
      return OsiModelApplicationLayer;
268
1.02k
    }
269
  };
270
271
  // implementation of inline methods
272
273
  bool RadiusLayer::isRadiusPort(uint16_t port)
274
98.4k
  {
275
98.4k
    switch (port)
276
98.4k
    {
277
4.92k
    case 1812:
278
5.25k
    case 1813:
279
5.25k
    case 3799:
280
5.25k
      return true;
281
93.1k
    default:
282
93.1k
      return false;
283
98.4k
    }
284
98.4k
  }  // isRadiusPort
285
286
}  // namespace pcpp