Coverage Report

Created: 2024-02-25 06:29

/src/PcapPlusPlus/Packet++/header/DhcpLayer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "Layer.h"
4
#include "TLVData.h"
5
#include "IpAddress.h"
6
#include "MacAddress.h"
7
#include <string.h>
8
9
/// @file
10
11
/**
12
 * \namespace pcpp
13
 * \brief The main namespace for the PcapPlusPlus lib
14
 */
15
namespace pcpp
16
{
17
18
  /**
19
   * @struct dhcp_header
20
   * Represents a DHCP protocol header
21
   */
22
  #pragma pack(push, 1)
23
  struct dhcp_header
24
  {
25
    /** BootP opcode */
26
    uint8_t opCode;
27
    /** Hardware type, set to 1 (Ethernet) by default */
28
    uint8_t hardwareType;
29
    /** Hardware address length, set to 6 (MAC address length) by default */
30
    uint8_t hardwareAddressLength;
31
    /** Hop count */
32
    uint8_t hops;
33
    /** DHCP/BootP transaction ID */
34
    uint32_t transactionID;
35
    /** The elapsed time, in seconds since the client sent its first BOOTREQUEST message */
36
    uint16_t secondsElapsed;
37
    /** BootP flags */
38
    uint16_t flags;
39
    /** Client IPv4 address */
40
    uint32_t clientIpAddress;
41
    /** Your IPv4 address */
42
    uint32_t yourIpAddress;
43
    /** Server IPv4 address */
44
    uint32_t serverIpAddress;
45
    /** Gateway IPv4 address */
46
    uint32_t gatewayIpAddress;
47
    /** Client hardware address, by default contains the MAC address (only 6 first bytes are used) */
48
    uint8_t clientHardwareAddress[16];
49
    /** BootP server name */
50
    uint8_t serverName[64];
51
    /** BootP boot file name */
52
    uint8_t bootFilename[128];
53
    /** DHCP magic number (set to the default value of 0x63538263) */
54
    uint32_t magicNumber;
55
  };
56
  #pragma pack(pop)
57
58
59
  /**
60
   * BootP opcodes
61
   */
62
  enum BootpOpCodes
63
  {
64
    /** BootP request */
65
    DHCP_BOOTREQUEST = 1,
66
    /** BootP reply */
67
    DHCP_BOOTREPLY = 2
68
  };
69
70
  /**
71
   * DHCP message types
72
   */
73
  enum DhcpMessageType
74
  {
75
    /** Unknown message type */
76
    DHCP_UNKNOWN_MSG_TYPE = 0,
77
    /** Discover message type */
78
    DHCP_DISCOVER         = 1,
79
    /** Offer message type */
80
    DHCP_OFFER            = 2,
81
    /** Request message type */
82
    DHCP_REQUEST          = 3,
83
    /** Decline message type */
84
    DHCP_DECLINE          = 4,
85
    /** Acknowledge message type */
86
    DHCP_ACK              = 5,
87
    /** Non-acknowledge message type */
88
    DHCP_NAK              = 6,
89
    /** Release message type */
90
    DHCP_RELEASE          = 7,
91
    /** Inform message type */
92
    DHCP_INFORM           = 8
93
  };
94
95
  /**
96
   * DHCP option types.
97
   */
98
  enum DhcpOptionTypes
99
  {
100
    /** Unknown option type */
101
    DHCPOPT_UNKNOWN = -1,
102
    /** Pad */
103
    DHCPOPT_PAD = 0,
104
    /** Subnet Mask Value */
105
    DHCPOPT_SUBNET_MASK = 1,
106
    /** Time Offset in Seconds from UTC */
107
    DHCPOPT_TIME_OFFSET = 2,
108
    /** N/4 Router addresses */
109
    DHCPOPT_ROUTERS = 3,
110
    /** N/4 Timeserver addresses */
111
    DHCPOPT_TIME_SERVERS = 4,
112
    /** N/4 IEN-116 Server addresses */
113
    DHCPOPT_NAME_SERVERS = 5,
114
    /** N/4 DNS Server addresses */
115
    DHCPOPT_DOMAIN_NAME_SERVERS = 6,
116
    /** N/4 Logging Server addresses */
117
    DHCPOPT_LOG_SERVERS = 7,
118
    /** N/4 Quotes Server addresses */
119
    DHCPOPT_QUOTES_SERVERS = 8,
120
    /** N/4 Quotes Server addresses */
121
    DHCPOPT_LPR_SERVERS = 9,
122
    /** N/4 Quotes Server addresses */
123
    DHCPOPT_IMPRESS_SERVERS = 10,
124
    /** N/4 RLP Server addresses */
125
    DHCPOPT_RESOURCE_LOCATION_SERVERS = 11,
126
    /** Hostname string */
127
    DHCPOPT_HOST_NAME = 12,
128
    /** Size of boot file in 512 byte chunks */
129
    DHCPOPT_BOOT_SIZE = 13,
130
    /** Client to dump and name the file to dump it to */
131
    DHCPOPT_MERIT_DUMP = 14,
132
    /** The DNS domain name of the client */
133
    DHCPOPT_DOMAIN_NAME = 15,
134
    /** Swap Server address */
135
    DHCPOPT_SWAP_SERVER = 16,
136
    /** Path name for root disk */
137
    DHCPOPT_ROOT_PATH = 17,
138
    /** Path name for more BOOTP info */
139
    DHCPOPT_EXTENSIONS_PATH = 18,
140
    /** Enable/Disable IP Forwarding */
141
    DHCPOPT_IP_FORWARDING = 19,
142
    /** Enable/Disable Source Routing */
143
    DHCPOPT_NON_LOCAL_SOURCE_ROUTING = 20,
144
    /** Routing Policy Filters */
145
    DHCPOPT_POLICY_FILTER = 21,
146
    /** Max Datagram Reassembly Size */
147
    DHCPOPT_MAX_DGRAM_REASSEMBLY = 22,
148
    /** Default IP Time to Live */
149
    DEFAULT_IP_TTL = 23,
150
    /** Path MTU Aging Timeout */
151
    DHCPOPT_PATH_MTU_AGING_TIMEOUT = 24,
152
    /** Path MTU Plateau Table */
153
    PATH_MTU_PLATEAU_TABLE = 25,
154
    /** Interface MTU Size */
155
    DHCPOPT_INTERFACE_MTU = 26,
156
    /** All Subnets are Local */
157
    DHCPOPT_ALL_SUBNETS_LOCAL = 27,
158
    /** Broadcast Address */
159
    DHCPOPT_BROADCAST_ADDRESS = 28,
160
    /** Perform Mask Discovery */
161
    DHCPOPT_PERFORM_MASK_DISCOVERY = 29,
162
    /** Provide Mask to Others */
163
    DHCPOPT_MASK_SUPPLIER = 30,
164
    /** Perform Router Discovery */
165
    DHCPOPT_ROUTER_DISCOVERY = 31,
166
    /** Router Solicitation Address */
167
    DHCPOPT_ROUTER_SOLICITATION_ADDRESS = 32,
168
    /** Static Routing Table */
169
    DHCPOPT_STATIC_ROUTES = 33,
170
    /** Trailer Encapsulation */
171
    DHCPOPT_TRAILER_ENCAPSULATION = 34,
172
    /** ARP Cache Timeout */
173
    DHCPOPT_ARP_CACHE_TIMEOUT = 35,
174
    /** IEEE802.3 Encapsulation */
175
    DHCPOPT_IEEE802_3_ENCAPSULATION = 36,
176
    /** Default TCP Time to Live */
177
    DHCPOPT_DEFAULT_TCP_TTL = 37,
178
    /** TCP Keepalive Interval */
179
    DHCPOPT_TCP_KEEPALIVE_INTERVAL = 38,
180
    /** TCP Keepalive Garbage */
181
    DHCPOPT_TCP_KEEPALIVE_GARBAGE = 39,
182
    /** NIS Domain Name */
183
    DHCPOPT_NIS_DOMAIN = 40,
184
    /** NIS Server Addresses */
185
    DHCPOPT_NIS_SERVERS = 41,
186
    /** NTP Server Addresses */
187
    DHCPOPT_NTP_SERVERS = 42,
188
    /** Vendor Specific Information */
189
    DHCPOPT_VENDOR_ENCAPSULATED_OPTIONS = 43,
190
    /** NETBIOS Name Servers */
191
    DHCPOPT_NETBIOS_NAME_SERVERS = 44,
192
    /** NETBIOS Datagram Distribution */
193
    DHCPOPT_NETBIOS_DD_SERVER = 45,
194
    /** NETBIOS Node Type */
195
    DHCPOPT_NETBIOS_NODE_TYPE = 46,
196
    /** NETBIOS Scope */
197
    DHCPOPT_NETBIOS_SCOPE = 47,
198
    /** X Window Font Server */
199
    DHCPOPT_FONT_SERVERS = 48,
200
    /** X Window Display Manager */
201
    DHCPOPT_X_DISPLAY_MANAGER = 49,
202
    /** Requested IP Address */
203
    DHCPOPT_DHCP_REQUESTED_ADDRESS = 50,
204
    /** IP Address Lease Time */
205
    DHCPOPT_DHCP_LEASE_TIME = 51,
206
    /** Overload "sname" or "file" */
207
    DHCPOPT_DHCP_OPTION_OVERLOAD = 52,
208
    /** DHCP Message Type */
209
    DHCPOPT_DHCP_MESSAGE_TYPE = 53,
210
    /** DHCP Server Identification */
211
    DHCPOPT_DHCP_SERVER_IDENTIFIER = 54,
212
    /** Parameter Request List */
213
    DHCPOPT_DHCP_PARAMETER_REQUEST_LIST = 55,
214
    /** DHCP Error Message */
215
    DHCPOPT_DHCP_MESSAGE = 56,
216
    /** DHCP Maximum Message Size */
217
    DHCPOPT_DHCP_MAX_MESSAGE_SIZE = 57,
218
    /** DHCP Renewal (T1) Time */
219
    DHCPOPT_DHCP_RENEWAL_TIME = 58,
220
    /** DHCP Rebinding (T2) Time */
221
    DHCPOPT_DHCP_REBINDING_TIME = 59,
222
    /** Class Identifier */
223
    DHCPOPT_VENDOR_CLASS_IDENTIFIER = 60,
224
    /** Class Identifier */
225
    DHCPOPT_DHCP_CLIENT_IDENTIFIER = 61,
226
    /** NetWare/IP Domain Name */
227
    DHCPOPT_NWIP_DOMAIN_NAME = 62,
228
    /** NetWare/IP sub Options */
229
    DHCPOPT_NWIP_SUBOPTIONS = 63,
230
    /** NIS+ v3 Client Domain Name */
231
    DHCPOPT_NIS_DOMAIN_NAME = 64,
232
    /** NIS+ v3 Server Addresses */
233
    DHCPOPT_NIS_SERVER_ADDRESS = 65,
234
    /** TFTP Server Name */
235
    DHCPOPT_TFTP_SERVER_NAME = 66,
236
    /** Boot File Name */
237
    DHCPOPT_BOOTFILE_NAME = 67,
238
    /** Home Agent Addresses */
239
    DHCPOPT_HOME_AGENT_ADDRESS = 68,
240
    /** Simple Mail Server (SMTP) Addresses */
241
    DHCPOPT_SMTP_SERVER = 69,
242
    /** Post Office (POP3) Server Addresses */
243
    DHCPOPT_POP3_SERVER = 70,
244
    /** Network News (NNTP) Server Addresses */
245
    DHCPOPT_NNTP_SERVER = 71,
246
    /** WWW Server Addresses */
247
    DHCPOPT_WWW_SERVER = 72,
248
    /** Finger Server Addresses */
249
    DHCPOPT_FINGER_SERVER = 73,
250
    /** Chat (IRC) Server Addresses */
251
    DHCPOPT_IRC_SERVER = 74,
252
    /** StreetTalk Server Addresses */
253
    DHCPOPT_STREETTALK_SERVER = 75,
254
    /** ST Directory Assist. Addresses */
255
    DHCPOPT_STDA_SERVER = 76,
256
    /** User Class Information */
257
    DHCPOPT_USER_CLASS = 77,
258
    /** Directory Agent Information */
259
    DHCPOPT_DIRECTORY_AGENT = 78,
260
    /** Service Location Agent Scope */
261
    DHCPOPT_SERVICE_SCOPE = 79,
262
    /** Rapid Commit */
263
    DHCPOPT_RAPID_COMMIT = 80,
264
    /** Fully Qualified Domain Name */
265
    DHCPOPT_FQDN = 81,
266
    /** Relay Agent Information */
267
    DHCPOPT_DHCP_AGENT_OPTIONS = 82,
268
    /** Internet Storage Name Service */
269
    DHCPOPT_ISNS = 83,
270
    /** Novell Directory Services */
271
    DHCPOPT_NDS_SERVERS = 85,
272
    /** Novell Directory Services */
273
    DHCPOPT_NDS_TREE_NAME = 86,
274
    /** Novell Directory Services */
275
    DHCPOPT_NDS_CONTEXT = 87,
276
    /** BCMCS Controller Domain Name list */
277
    DHCPOPT_BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88,
278
    /** BCMCS Controller IPv4 address option */
279
    DHCPOPT_BCMCS_CONTROLLER_IPV4_ADDRESS = 89,
280
    /** Authentication */
281
    DHCPOPT_AUTHENTICATION = 90,
282
    /** Client Last Transaction Time */
283
    DHCPOPT_CLIENT_LAST_TXN_TIME = 91,
284
    /** Associated IP */
285
    DHCPOPT_ASSOCIATED_IP = 92,
286
    /** Client System Architecture */
287
    DHCPOPT_CLIENT_SYSTEM = 93,
288
    /** Client Network Device Interface */
289
    DHCPOPT_CLIENT_NDI = 94,
290
    /** Lightweight Directory Access Protocol [ */
291
    DHCPOPT_LDAP = 95,
292
    /** UUID/GUID-based Client Identifier */
293
    DHCPOPT_UUID_GUID = 97,
294
    /** Open Group's User Authentication */
295
    DHCPOPT_USER_AUTH = 98,
296
    /** GEOCONF_CIVIC */
297
    DHCPOPT_GEOCONF_CIVIC = 99,
298
    /** IEEE 1003.1 TZ String */
299
    DHCPOPT_PCODE = 100,
300
    /** Reference to the TZ Database */
301
    DHCPOPT_TCODE = 101,
302
    /** NetInfo Parent Server Address */
303
    DHCPOPT_NETINFO_ADDRESS = 112,
304
    /** NetInfo Parent Server Tag */
305
    DHCPOPT_NETINFO_TAG = 113,
306
    /** URL */
307
    DHCPOPT_URL = 114,
308
    /** DHCP Auto-Configuration */
309
    DHCPOPT_AUTO_CONFIG = 116,
310
    /** Name Service Search */
311
    DHCPOPT_NAME_SERVICE_SEARCH = 117,
312
    /** Subnet Selection Option */
313
    DHCPOPT_SUBNET_SELECTION = 118,
314
    /** DNS Domain Search List */
315
    DHCPOPT_DOMAIN_SEARCH = 119,
316
    /** SIP Servers DHCP Option */
317
    DHCPOPT_SIP_SERVERS = 120,
318
    /** Classless Static Route Option */
319
    DHCPOPT_CLASSLESS_STATIC_ROUTE = 121,
320
    /** CableLabs Client Configuration */
321
    DHCPOPT_CCC = 122,
322
    /** GeoConf Option */
323
    DHCPOPT_GEOCONF = 123,
324
    /** Vendor-Identifying Vendor Class */
325
    DHCPOPT_V_I_VENDOR_CLASS = 124,
326
    /** Vendor-Identifying Vendor-Specific Information */
327
    DHCPOPT_V_I_VENDOR_OPTS = 125,
328
    /** OPTION_PANA_AGENT */
329
    DHCPOPT_OPTION_PANA_AGENT = 136,
330
    /** OPTION_V4_LOST */
331
    DHCPOPT_OPTION_V4_LOST = 137,
332
    /** CAPWAP Access Controller addresses */
333
    DHCPOPT_OPTION_CAPWAP_AC_V4 = 138,
334
    /** A Series Of Suboptions */
335
    DHCPOPT_OPTION_IPV4_ADDRESS_MOS = 139,
336
    /** A Series Of Suboptions */
337
    DHCPOPT_OPTION_IPV4_FQDN_MOS = 140,
338
    /** List of domain names to search for SIP User Agent Configuration */
339
    DHCPOPT_SIP_UA_CONFIG = 141,
340
    /** ANDSF IPv4 Address Option for DHCPv4 */
341
    DHCPOPT_OPTION_IPV4_ADDRESS_ANDSF = 142,
342
    /** Geospatial Location with Uncertainty [RF */
343
    DHCPOPT_GEOLOC = 144,
344
    /** Forcerenew Nonce Capable */
345
    DHCPOPT_FORCERENEW_NONCE_CAPABLE = 145,
346
    /** Information for selecting RDNSS */
347
    DHCPOPT_RDNSS_SELECTION = 146,
348
    /** Status code and optional N byte text message describing status */
349
    DHCPOPT_STATUS_CODE = 151,
350
    /** Absolute time (seconds since Jan 1, 1970) message was sent */
351
    DHCPOPT_BASE_TIME = 152,
352
    /** Number of seconds in the past when client entered current state */
353
    DHCPOPT_START_TIME_OF_STATE = 153,
354
    /** Absolute time (seconds since Jan 1, 1970) for beginning of query */
355
    DHCPOPT_QUERY_START_TIME = 154,
356
    /** Absolute time (seconds since Jan 1, 1970) for end of query */
357
    DHCPOPT_QUERY_END_TIME = 155,
358
    /** State of IP address */
359
    DHCPOPT_DHCP_STATE = 156,
360
    /** Indicates information came from local or remote server */
361
    DHCPOPT_DATA_SOURCE = 157,
362
    /** Includes one or multiple lists of PCP server IP addresses; each list is treated as a separate PCP server */
363
    DHCPOPT_OPTION_V4_PCP_SERVER = 158,
364
    /** This option is used to configure a set of ports bound to a shared IPv4 address */
365
    DHCPOPT_OPTION_V4_PORTPARAMS = 159,
366
    /** DHCP Captive-Portal */
367
    DHCPOPT_CAPTIVE_PORTAL = 160,
368
    /** Manufacturer Usage Descriptions */
369
    DHCPOPT_OPTION_MUD_URL_V4 = 161,
370
    /** Etherboot */
371
    DHCPOPT_ETHERBOOT = 175,
372
    /** IP Telephone */
373
    DHCPOPT_IP_TELEPHONE = 176,
374
    /** Magic string = F1:00:74:7E */
375
    DHCPOPT_PXELINUX_MAGIC = 208,
376
    /** Configuration file */
377
    DHCPOPT_CONFIGURATION_FILE = 209,
378
    /** Path Prefix Option */
379
    DHCPOPT_PATH_PREFIX = 210,
380
    /** Reboot Time */
381
    DHCPOPT_REBOOT_TIME = 211,
382
    /** OPTION_6RD with N/4 6rd BR addresses */
383
    DHCPOPT_OPTION_6RD = 212,
384
    /** Access Network Domain Name */
385
    DHCPOPT_OPTION_V4_ACCESS_DOMAIN = 213,
386
    /** Subnet Allocation Option */
387
    DHCPOPT_SUBNET_ALLOCATION = 220,
388
    /** Virtual Subnet Selection (VSS) Option */
389
    DHCPOPT_VIRTUAL_SUBNET_SELECTION = 221,
390
    /** End (last option) */
391
    DHCPOPT_END = 255
392
  };
393
394
395
  /**
396
   * @class DhcpOption
397
   * A wrapper class for DHCP options. This class does not create or modify DHCP option records, but rather
398
   * serves as a wrapper and provides useful methods for setting and retrieving data to/from them
399
   */
400
  class DhcpOption : public TLVRecord<uint8_t, uint8_t>
401
  {
402
  public:
403
404
    /**
405
     * A c'tor for this class that gets a pointer to the option raw data (byte array)
406
     * @param[in] optionRawData A pointer to the option raw data
407
     */
408
347k
    explicit DhcpOption(uint8_t* optionRawData) : TLVRecord(optionRawData) { }
409
410
    /**
411
     * A d'tor for this class, currently does nothing
412
     */
413
0
    virtual ~DhcpOption() { }
414
415
    /**
416
     * Retrieve DHCP option data as IPv4 address. Relevant only if option value is indeed an IPv4 address
417
     * @return DHCP option data as IPv4 address
418
     */
419
    IPv4Address getValueAsIpAddr() const
420
2.01k
    {
421
2.01k
      return getValueAs<uint32_t>();
422
2.01k
    }
423
424
    /**
425
     * Set DHCP option data as IPv4 address. This method copies the 4 bytes of the IP address to the option value
426
     * @param[in] addr The IPv4 address to set
427
     * @param[in] valueOffset An optional parameter that specifies where to start set the option data (default set to 0). For example:
428
     * if option data is 20 bytes long and you want to set the IP address in the 4 last bytes then use this method like this:
429
     * setValueIpAddr(your_addr, 16)
430
     */
431
    void setValueIpAddr(const IPv4Address& addr, int valueOffset = 0)
432
0
    {
433
0
      setValue<uint32_t>(addr.toInt(), valueOffset);
434
0
    }
435
436
    /**
437
     * Retrieve DHCP option data as string. Relevant only if option value is indeed a string
438
     * @param[in] valueOffset An optional parameter that specifies where to start copy the DHCP option data. For example:
439
     * when retrieving Client FQDN option, you may ignore the flags and RCODE fields using this method like this:
440
     * getValueAsString(3). The default is 0 - start copying from the beginning of option data
441
     * @return DHCP option data as string
442
     */
443
    std::string getValueAsString(int valueOffset = 0) const
444
2.01k
    {
445
2.01k
      if (m_Data == nullptr || m_Data->recordLen - valueOffset < 1)
446
84
        return "";
447
448
1.92k
      return std::string((const char*)m_Data->recordValue + valueOffset, (int)m_Data->recordLen - valueOffset);
449
2.01k
    }
450
451
    /**
452
     * Set DHCP option data as string. This method copies the string to the option value. If the string is longer than option length
453
     * the string is trimmed so it will fit the option length
454
     * @param[in] stringValue The string to set
455
     * @param[in] valueOffset An optional parameter that specifies where to start set the option data (default set to 0). For example:
456
     * if option data is 20 bytes long and you want to set a 6 char-long string in the 6 last bytes then use this method like this:
457
     * setValueString("string", 14)
458
     */
459
    void setValueString(const std::string& stringValue, int valueOffset = 0)
460
0
    {
461
0
      // calculate the maximum length of the destination buffer
462
0
      size_t len = (size_t)m_Data->recordLen - (size_t)valueOffset;
463
0
464
0
      // use the length of input string if a buffer is large enough for whole string
465
0
      if (stringValue.length() < len)
466
0
        len = stringValue.length();
467
0
468
0
      memcpy(m_Data->recordValue + valueOffset, stringValue.data(), len);
469
0
    }
470
471
    /**
472
     * Check if a pointer can be assigned to the TLV record data
473
     * @param[in] recordRawData A pointer to the TLV record raw data
474
     * @param[in] tlvDataLen The size of the TLV record raw data
475
     * @return True if data is valid and can be assigned
476
     */
477
    static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen)
478
347k
    {
479
347k
      auto data = (TLVRawData*)recordRawData;
480
347k
      if (data == nullptr)
481
0
        return false;
482
483
347k
      if (tlvDataLen < sizeof(TLVRawData::recordType))
484
5.91k
        return false;
485
486
341k
      if (data->recordType == (uint8_t)DHCPOPT_END || data->recordType == (uint8_t)DHCPOPT_PAD)
487
301k
        return true;
488
489
40.3k
      return TLVRecord<uint8_t, uint8_t>::canAssign(recordRawData, tlvDataLen);
490
341k
    }
491
492
    // implement abstract methods
493
494
    size_t getTotalSize() const
495
1.68M
    {
496
1.68M
      if (m_Data == nullptr)
497
0
        return 0;
498
499
1.68M
      if (m_Data->recordType == (uint8_t)DHCPOPT_END || m_Data->recordType == (uint8_t)DHCPOPT_PAD)
500
1.50M
        return sizeof(uint8_t);
501
502
183k
      return sizeof(uint8_t) * 2 + (size_t)m_Data->recordLen;
503
1.68M
    }
504
505
    size_t getDataSize() const
506
7.53k
    {
507
7.53k
      if (m_Data == nullptr)
508
0
        return 0;
509
510
7.53k
      if (m_Data->recordType == (uint8_t)DHCPOPT_END || m_Data->recordType == (uint8_t)DHCPOPT_PAD)
511
82
        return 0;
512
513
7.45k
      return m_Data->recordLen;
514
7.53k
    }
515
  };
516
517
518
  /**
519
   * @class DhcpOptionBuilder
520
   * A class for building DHCP options. This builder receives the option parameters in its c'tor,
521
   * builds the DHCP option raw buffer and provides a build() method to get a DhcpOption object out of it
522
   */
523
  class DhcpOptionBuilder : public TLVRecordBuilder
524
  {
525
  public:
526
527
    /**
528
     * A c'tor for building DHCP options which their value is a byte array. The DhcpOption object can later
529
     * be retrieved by calling build()
530
     * @param[in] optionType DHCP option type
531
     * @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in any way
532
     * @param[in] optionValueLen DHCP option value length in bytes
533
     */
534
    DhcpOptionBuilder(DhcpOptionTypes optionType, const uint8_t* optionValue, uint8_t optionValueLen) :
535
0
      TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen) { }
536
537
    /**
538
     * A c'tor for building DHCP options which have a 1-byte value. The DhcpOption object can later be retrieved
539
     * by calling build()
540
     * @param[in] optionType DHCP option type
541
     * @param[in] optionValue A 1-byte option value
542
     */
543
    DhcpOptionBuilder(DhcpOptionTypes optionType, uint8_t optionValue) :
544
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) { }
545
546
    /**
547
     * A c'tor for building DHCP options which have a 2-byte value. The DhcpOption object can later be retrieved
548
     * by calling build()
549
     * @param[in] optionType DHCP option type
550
     * @param[in] optionValue A 2-byte option value
551
     */
552
    DhcpOptionBuilder(DhcpOptionTypes optionType, uint16_t optionValue) :
553
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) { }
554
555
    /**
556
     * A c'tor for building DHCP options which have a 4-byte value. The DhcpOption object can later be retrieved
557
     * by calling build()
558
     * @param[in] optionType DHCP option type
559
     * @param[in] optionValue A 4-byte option value
560
     */
561
    DhcpOptionBuilder(DhcpOptionTypes optionType, uint32_t optionValue) :
562
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) { }
563
564
    /**
565
     * A c'tor for building DHCP options which have an IPv4Address value. The DhcpOption object can later be
566
     * retrieved by calling build()
567
     * @param[in] optionType DHCP option type
568
     * @param[in] optionValue The IPv4 address option value
569
     */
570
    DhcpOptionBuilder(DhcpOptionTypes optionType, const IPv4Address& optionValue) :
571
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) { }
572
573
    /**
574
     * A c'tor for building DHCP options which have a string value. The DhcpOption object can later be retrieved
575
     * by calling build()
576
     * @param[in] optionType DHCP option type
577
     * @param[in] optionValue The string option value
578
     */
579
    DhcpOptionBuilder(DhcpOptionTypes optionType, const std::string& optionValue) :
580
0
      TLVRecordBuilder((uint8_t)optionType, optionValue) { }
581
582
    /**
583
     * A copy c'tor which copies all the data from another instance of DhcpOptionBuilder
584
     * @param[in] other The instance to copy from
585
     */
586
    DhcpOptionBuilder(const DhcpOptionBuilder& other) :
587
0
      TLVRecordBuilder(other) { }
588
589
    /**
590
     * Assignment operator that copies all data from another instance of DhcpOptionBuilder
591
     * @param[in] other The instance to assign from
592
     * @return A reference to the assignee
593
     */
594
    DhcpOptionBuilder& operator=(const DhcpOptionBuilder& other)
595
0
    {
596
0
      TLVRecordBuilder::operator=(other);
597
0
      return *this;
598
0
    }
599
600
    /**
601
     * Build the DhcpOption object out of the parameters defined in the c'tor
602
     * @return The DhcpOption object
603
     */
604
    DhcpOption build() const;
605
  };
606
607
608
609
  /**
610
   * @class DhcpLayer
611
   * Represents a DHCP (Dynamic Host Configuration Protocol) protocol layer
612
   */
613
  class DhcpLayer : public Layer
614
  {
615
  public:
616
617
    /**
618
     * A constructor that creates the layer from an existing packet raw data
619
     * @param[in] data A pointer to the raw data
620
     * @param[in] dataLen Size of the data in bytes
621
     * @param[in] prevLayer A pointer to the previous layer
622
     * @param[in] packet A pointer to the Packet instance where layer will be stored in
623
     */
624
    DhcpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
625
626
    /**
627
     * A constructor that creates the layer from scratch. Adds a ::DHCPOPT_DHCP_MESSAGE_TYPE and a ::DHCPOPT_END
628
     * options
629
     * @param[in] msgType A DHCP message type to be set
630
     * @param[in] clientMacAddr A client MAC address to set in dhcp_header#clientHardwareAddress field
631
     */
632
    DhcpLayer(DhcpMessageType msgType, const MacAddress& clientMacAddr);
633
634
    /**
635
     * A constructor that creates the layer from scratch with clean data
636
     */
637
    DhcpLayer();
638
639
    /**
640
     * A destructor for this layer
641
     */
642
11.0k
    virtual ~DhcpLayer() {}
643
644
    /**
645
     * Get a pointer to the DHCP header. Notice this points directly to the data, so every change will change the actual packet data
646
     * @return A pointer to the @ref dhcp_header
647
     */
648
16.1k
    dhcp_header* getDhcpHeader() const { return (dhcp_header*)m_Data; }
649
650
    /**
651
     * @return The BootP opcode of this message
652
     */
653
2.02k
    BootpOpCodes getOpCode() const { return (BootpOpCodes)getDhcpHeader()->opCode; }
654
655
    /**
656
     * @return The client IPv4 address (as extracted from dhcp_header#clientIpAddress converted to IPv4Address object)
657
     */
658
2.02k
    IPv4Address getClientIpAddress() const { return getDhcpHeader()->clientIpAddress; }
659
660
    /**
661
     * Set the client IPv4 address in dhcp_header#clientIpAddress
662
     * @param[in] addr The IPv4 address to set
663
     */
664
0
    void setClientIpAddress(const IPv4Address& addr) { getDhcpHeader()->clientIpAddress = addr.toInt(); }
665
666
    /**
667
     * @return The server IPv4 address (as extracted from dhcp_header#serverIpAddress converted to IPv4Address object)
668
     */
669
2.02k
    IPv4Address getServerIpAddress() const { return getDhcpHeader()->serverIpAddress; }
670
671
    /**
672
     * Set the server IPv4 address in dhcp_header#serverIpAddress
673
     * @param[in] addr The IPv4 address to set
674
     */
675
0
    void setServerIpAddress(const IPv4Address& addr) { getDhcpHeader()->serverIpAddress = addr.toInt(); }
676
677
    /**
678
     * @return Your IPv4 address (as extracted from dhcp_header#yourIpAddress converted to IPv4Address object)
679
     */
680
2.02k
    IPv4Address getYourIpAddress() const { return getDhcpHeader()->yourIpAddress; }
681
682
    /**
683
     * Set your IPv4 address in dhcp_header#yourIpAddress
684
     * @param[in] addr The IPv4 address to set
685
     */
686
0
    void setYourIpAddress(const IPv4Address& addr) { getDhcpHeader()->yourIpAddress = addr.toInt(); }
687
688
    /**
689
     * @return Gateway IPv4 address (as extracted from dhcp_header#gatewayIpAddress converted to IPv4Address object)
690
     */
691
2.02k
    IPv4Address getGatewayIpAddress() const { return getDhcpHeader()->gatewayIpAddress; }
692
693
    /**
694
     * Set the gateway IPv4 address in dhcp_header#gatewayIpAddress
695
     * @param[in] addr The IPv4 address to set
696
     */
697
0
    void setGatewayIpAddress(const IPv4Address& addr) { getDhcpHeader()->gatewayIpAddress = addr.toInt(); }
698
699
    /**
700
     * @return The client MAC address as extracted from dhcp_header#clientHardwareAddress, assuming dhcp_header#hardwareType is 1 (Ethernet)
701
     * and dhcp_header#hardwareAddressLength is 6 (MAC address length). Otherwise returns MacAddress#Zero
702
     */
703
    MacAddress getClientHardwareAddress() const;
704
705
    /**
706
     * Set a MAC address into the first 6 bytes of dhcp_header#clientHardwareAddress. This method also sets dhcp_header#hardwareType
707
     * to 1 (Ethernet) and dhcp_header#hardwareAddressLength to 6 (MAC address length)
708
     * @param[in] addr The MAC address to set
709
     */
710
    void setClientHardwareAddress(const MacAddress& addr);
711
712
    /**
713
     * @return DHCP message type as extracted from ::DHCPOPT_DHCP_MESSAGE_TYPE option. If this option doesn't exist the value of
714
     * ::DHCP_UNKNOWN_MSG_TYPE is returned
715
     */
716
    DhcpMessageType getMessageType() const;
717
718
    /**
719
     * Set DHCP message type. This method searches for existing ::DHCPOPT_DHCP_MESSAGE_TYPE option. If found, it sets the requested
720
     * message type as its value. If not, it creates a ::DHCPOPT_DHCP_MESSAGE_TYPE option and sets the requested message type as its
721
     * value
722
     * @param[in] msgType Message type to set
723
     * @return True if message type was set successfully or false if msgType is ::DHCP_UNKNOWN_MSG_TYPE or if failed to add
724
     * ::DHCPOPT_DHCP_MESSAGE_TYPE option
725
     */
726
    bool setMessageType(DhcpMessageType msgType);
727
728
    /**
729
     * @return The first DHCP option in the packet. If there are no DHCP options the returned value will contain
730
     * a logical NULL (DhcpOption#isNull() == true)
731
     */
732
    DhcpOption getFirstOptionData() const;
733
734
    /**
735
     * Get the DHCP option that comes after a given option. If the given option was the last one, the
736
     * returned value will contain a logical NULL (DhcpOption#isNull() == true)
737
     * @param[in] dhcpOption A given DHCP option
738
     * @return A DhcpOption object containing the option data that comes next, or logical NULL if the given DHCP
739
     * option: (1) was the last one; (2) contains a logical NULL or (3) doesn't belong to this packet
740
     */
741
    DhcpOption getNextOptionData(DhcpOption dhcpOption) const;
742
743
    /**
744
     * Get a DHCP option by type
745
     * @param[in] option DHCP option type
746
     * @return A DhcpOption object containing the first DHCP option data that matches this type, or logical NULL
747
     * (DhcpOption#isNull() == true) if no such option found
748
     */
749
    DhcpOption getOptionData(DhcpOptionTypes option) const;
750
751
    /**
752
     * @return The number of DHCP options in this layer
753
     */
754
    size_t getOptionsCount() const;
755
756
    /**
757
     * Add a new DHCP option at the end of the layer
758
     * @param[in] optionBuilder A DhcpOptionBuilder object that contains the requested DHCP option data to add
759
     * @return A DhcpOption object containing the newly added DHCP option data or logical NULL
760
     * (DhcpOption#isNull() == true) if addition failed
761
     */
762
    DhcpOption addOption(const DhcpOptionBuilder& optionBuilder);
763
764
    /**
765
     * Add a new DHCP option after an existing one
766
     * @param[in] optionBuilder A DhcpOptionBuilder object that contains the requested DHCP option data to add
767
     * @param[in] prevOption The DHCP option type which the newly added option will come after
768
     * @return A DhcpOption object containing the newly added DHCP option data or logical NULL
769
     * (DhcpOption#isNull() == true) if addition failed
770
     */
771
    DhcpOption addOptionAfter(const DhcpOptionBuilder& optionBuilder, DhcpOptionTypes prevOption);
772
773
    /**
774
     * Remove an existing DHCP option from the layer
775
     * @param[in] optionType The DHCP option type to remove
776
     * @return True if DHCP option was successfully removed or false if type wasn't found or if removal failed
777
     */
778
    bool removeOption(DhcpOptionTypes optionType);
779
780
    /**
781
     * Remove all DHCP options in this layer
782
     * @return True if all DHCP options were successfully removed or false if removal failed for some reason
783
     */
784
    bool removeAllOptions();
785
786
    // implement abstract methods
787
788
    /**
789
     * Does nothing for this layer (DhcpLayer is always last)
790
     */
791
11.0k
    void parseNextLayer() {}
792
793
    /**
794
     * @return The size of @ref dhcp_header + size of options
795
     */
796
218k
    size_t getHeaderLen() const { return m_DataLen; }
797
798
    /**
799
     * Calculate the following fields:
800
     * - @ref dhcp_header#magicNumber = DHCP magic number (0x63538263)
801
     * - @ref dhcp_header#opCode = ::DHCP_BOOTREQUEST for message types: ::DHCP_DISCOVER, ::DHCP_REQUEST, ::DHCP_DECLINE, ::DHCP_RELEASE,
802
     *                            ::DHCP_INFORM, ::DHCP_UNKNOWN_MSG_TYPE
803
     *                            ::DHCP_BOOTREPLY for message types: ::DHCP_OFFER, ::DHCP_ACK, ::DHCP_NAK
804
     * - @ref dhcp_header#hardwareType = 1 (Ethernet)
805
     * - @ref dhcp_header#hardwareAddressLength = 6 (MAC address length)
806
     */
807
    void computeCalculateFields();
808
809
    std::string toString() const;
810
811
2.02k
    OsiModelLayer getOsiModelLayer() const { return OsiModelApplicationLayer; }
812
813
  private:
814
815
216k
    uint8_t* getOptionsBasePtr() const { return m_Data + sizeof(dhcp_header); }
816
817
    TLVRecordReader<DhcpOption> m_OptionReader;
818
819
    void initDhcpLayer(size_t numOfBytesToAllocate);
820
821
    DhcpOption addOptionAt(const DhcpOptionBuilder& optionBuilder, int offset);
822
  };
823
}