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