Coverage Report

Created: 2023-01-17 06:15

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