Coverage Report

Created: 2024-02-25 06:29

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