1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
|
// Copyright (C) 2011-2023 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef PKT4_H
#define PKT4_H
#include <asiolink/io_address.h>
#include <dhcp/duid.h>
#include <util/buffer.h>
#include <dhcp/option.h>
#include <dhcp/classify.h>
#include <dhcp/pkt.h>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <set>
#include <list>
#include <time.h>
namespace isc {
namespace dhcp {
/// @brief Represents DHCPv4 packet
///
/// This class represents a single DHCPv4 packet. It handles both incoming
/// and transmitted packets, parsing incoming options, options handling
/// (add, get, remove), on-wire assembly, sanity checks and other operations.
/// This specific class has several DHCPv4-specific methods, but it uses a lot
/// of common operations from its base @c Pkt class that is shared with Pkt6.
class Pkt4 : public Pkt {
public:
/// length of the CHADDR field in DHCPv4 message
const static size_t MAX_CHADDR_LEN = 16;
/// length of the SNAME field in DHCPv4 message
const static size_t MAX_SNAME_LEN = 64;
/// length of the FILE field in DHCPv4 message
const static size_t MAX_FILE_LEN = 128;
/// specifies DHCPv4 packet header length (fixed part)
const static size_t DHCPV4_PKT_HDR_LEN = 236;
/// Mask for the value of flags field in the DHCPv4 message
/// to check whether client requested broadcast response.
const static uint16_t FLAG_BROADCAST_MASK = 0x8000;
/// Constructor, used in replying to a message.
///
/// @param msg_type type of message (e.g. DHCPDISCOVER=1)
/// @param transid transaction-id
Pkt4(uint8_t msg_type, uint32_t transid);
/// @brief Constructor, used in message reception.
///
/// Creates new message. Pkt4 will copy data to bufferIn_
/// buffer on creation.
///
/// @param data pointer to received data
/// @param len size of buffer to be allocated for this packet.
Pkt4(const uint8_t* data, size_t len);
/// @brief Prepares on-wire format of DHCPv4 packet.
///
/// Prepares on-wire format of message and all its options.
/// Options must be stored in options_ field.
/// Output buffer will be stored in buffer_out_.
/// The buffer_out_ is cleared before writing to the buffer.
///
/// @throw InvalidOperation if packing fails
virtual void pack();
/// @brief Parses on-wire form of DHCPv4 packet.
///
/// Parses received packet, stored in on-wire format in bufferIn_.
///
/// Will create a collection of option objects that will
/// be stored in options_ container.
///
/// Method with throw exception if packet parsing fails.
virtual void unpack();
/// @brief Returns text representation of the primary packet identifiers
///
/// This method is intended to be used to provide a consistent way to
/// identify packets within log statements. It is an instance-level
/// wrapper around static makeLabel(). See this method for string
/// content.
///
/// This method is exception safe.
///
/// @return string with text representation
std::string getLabel() const;
/// @brief Returns text representation of the given packet identifiers
///
/// @param hwaddr - hardware address to include in the string, it may be
/// NULL.
/// @param client_id - client id to include in the string, it may be NULL.
/// to include in the string
/// @param transid - numeric transaction id to include in the string
///
/// @return string with text representation
static std::string makeLabel(const HWAddrPtr& hwaddr,
const ClientIdPtr& client_id,
const uint32_t transid);
/// @brief Returns text representation of the given packet identifiers.
///
/// This variant of the method does not include transaction id.
///
/// @param hwaddr hardware address to include in the string, it may be
/// NULL.
/// @param client_id client id to include in the string, it may be NULL.
static std::string makeLabel(const HWAddrPtr& hwaddr, const ClientIdPtr& client_id);
/// @brief Returns text representation of the packet.
///
/// This function is useful mainly for debugging.
///
/// @return string with text representation
std::string toText() const;
/// @brief Returns the size of the required buffer to build the packet.
///
/// Returns the size of the required buffer to build the packet with
/// the current set of packet options.
///
/// @return number of bytes required to build this packet
size_t len();
/// @brief Sets hops field.
///
/// @param hops value to be set
void setHops(uint8_t hops) { hops_ = hops; };
/// @brief Returns hops field.
///
/// @return hops field
uint8_t getHops() const { return (hops_); };
// Note: There's no need to manipulate OP field directly,
// thus no setOp() method. See op_ comment.
/// @brief Returns op field.
///
/// @return op field
uint8_t getOp() const { return (op_); };
/// @brief Sets secs field.
///
/// @param secs value to be set
void setSecs(uint16_t secs) { secs_ = secs; };
/// @brief Returns secs field.
///
/// @return secs field
uint16_t getSecs() const { return (secs_); };
/// @brief Sets flags field.
///
/// @param flags value to be set
void setFlags(uint16_t flags) { flags_ = flags; };
/// @brief Returns flags field.
///
/// @return flags field
uint16_t getFlags() const { return (flags_); };
/// @brief Returns ciaddr field.
///
/// @return ciaddr field
const isc::asiolink::IOAddress&
getCiaddr() const { return (ciaddr_); };
/// @brief Sets ciaddr field.
///
/// @param ciaddr value to be set
void
setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; };
/// @brief Returns siaddr field.
///
/// @return siaddr field
const isc::asiolink::IOAddress&
getSiaddr() const { return (siaddr_); };
/// @brief Sets siaddr field.
///
/// @param siaddr value to be set
void
setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; };
/// @brief Returns yiaddr field.
///
/// @return yiaddr field
const isc::asiolink::IOAddress&
getYiaddr() const { return (yiaddr_); };
/// @brief Sets yiaddr field.
///
/// @param yiaddr value to be set
void
setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; };
/// @brief Returns giaddr field.
///
/// @return giaddr field
const isc::asiolink::IOAddress&
getGiaddr() const { return (giaddr_); };
/// @brief Sets giaddr field.
///
/// @param giaddr value to be set
void
setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };
/// @brief Returns DHCP message type (e.g. 1 = DHCPDISCOVER).
///
/// This method is exception safe. For packets without DHCP Message Type
/// option, it returns DHCP_NOTYPE (0).
///
/// @return message type
uint8_t getType() const;
/// @brief Sets DHCP message type (e.g. 1 = DHCPDISCOVER).
///
/// @param type message type to be set
void setType(uint8_t type);
/// @brief Returns name of the DHCP message for a given type number.
///
/// This method is exception safe. For messages without DHCP Message Type
/// options, it returns UNKNOWN.
///
/// @param type DHCPv4 message type which name should be returned.
///
/// @return Pointer to the "const" string containing DHCP message name.
/// If the message type is unsupported the "UNKNOWN" is returned.
/// The caller must not release the returned pointer.
static const char* getName(const uint8_t type);
/// @brief Returns name of the DHCP message.
///
/// @return Pointer to the "const" string containing DHCP message name.
/// If the message type is unsupported the "UNKNOWN" is returned.
/// The caller must not release the returned pointer.
const char* getName() const;
/// @brief Returns sname field
///
/// Note: This is 64 bytes long field. It doesn't have to be
/// null-terminated. Do not use strlen() or similar on it.
///
/// @return sname field
const OptionBuffer
getSname() const { return (std::vector<uint8_t>(sname_, &sname_[MAX_SNAME_LEN])); };
/// @brief Sets sname field.
///
/// @param sname value to be set
/// @param sname_len length of the sname buffer (up to MAX_SNAME_LEN)
void setSname(const uint8_t* sname, size_t sname_len);
/// @brief Returns file field
///
/// Note: This is 128 bytes long field. It doesn't have to be
/// null-terminated. Do not use strlen() or similar on it.
///
/// @return pointer to file field
const OptionBuffer
getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); };
/// Sets file field
///
/// @param file value to be set
/// @param file_len length of the file buffer (up to MAX_FILE_LEN)
void
setFile(const uint8_t* file, size_t file_len);
/// @brief Sets hardware address.
///
/// Sets parameters of hardware address. hlen specifies
/// length of mac_addr buffer. Content of mac_addr buffer
/// will be copied to appropriate field.
///
/// Note: mac_addr must be a buffer of at least hlen bytes.
///
/// @param htype hardware type (will be sent in htype field)
/// @param hlen hardware length (will be sent in hlen field)
/// @param mac_addr pointer to hardware address
void setHWAddr(uint8_t htype, uint8_t hlen,
const std::vector<uint8_t>& mac_addr);
/// @brief Sets hardware address
///
/// Sets hardware address, based on existing HWAddr structure
/// @param addr already filled in HWAddr structure
/// @throw BadValue if addr is null
void setHWAddr(const HWAddrPtr& addr);
/// Returns htype field
///
/// @return hardware type
uint8_t
getHtype() const;
/// Returns hlen field
///
/// @return hardware address length
uint8_t
getHlen() const;
/// @brief returns hardware address information
/// @return hardware address structure
HWAddrPtr getHWAddr() const { return (hwaddr_); }
/// @brief Returns text representation of the hardware address
///
/// Returns text representation of the hardware address (e.g. hwaddr=00:01:02:03:04:05).
/// If there is no defined hardware address, it returns @c hwaddr=(undefined).
///
/// @return string with text representation
std::string getHWAddrLabel() const;
/// @brief Add an option.
///
/// @note: to avoid throwing when adding multiple options
/// with the same type use @ref Pkt::addOption.
///
/// @throw BadValue if option with that type is already present.
///
/// @param opt option to be added
virtual void
addOption(const OptionPtr& opt);
/// @brief Sets local HW address.
///
/// Sets the source HW address for the outgoing packet or
/// destination HW address for the incoming packet.
///
/// @note mac_addr must be a buffer of at least hlen bytes.
///
/// @param htype hardware type (will be sent in htype field)
/// @param hlen hardware length (will be sent in hlen field)
/// @param mac_addr pointer to hardware address
void setLocalHWAddr(const uint8_t htype, const uint8_t hlen,
const std::vector<uint8_t>& mac_addr);
/// @brief Sets local HW address.
///
/// Sets hardware address from an existing HWAddr structure.
/// The local address is a source address for outgoing
/// packet and destination address for incoming packet.
///
/// @param addr structure representing HW address.
///
/// @throw BadValue if addr is null
void setLocalHWAddr(const HWAddrPtr& addr);
/// @brief Returns local HW address.
///
/// @return local HW addr.
HWAddrPtr getLocalHWAddr() const {
return (local_hwaddr_);
}
/// @brief Returns a reference to option codes which unpacking
/// will be deferred.
///
/// Only options 43 and 224-254 are subject of deferred
/// unpacking: when the packet unpacking is performed, each time
/// such an option is found, it is unpacked as an unknown option
/// and the code added in this list.
///
/// @return List of codes of options which unpacking is deferred.
std::list<uint16_t>& getDeferredOptions() {
return (deferred_options_);
}
/// @brief Checks if a DHCPv4 message has been relayed.
///
/// This function returns a boolean value which indicates whether a DHCPv4
/// message has been relayed (if true is returned) or not (if false).
///
/// The message is considered relayed if the giaddr field is non-zero and
/// non-broadcast.
///
/// @return Boolean value which indicates whether the message is relayed
/// (true) or non-relayed (false).
bool isRelayed() const;
/// @brief Checks if a DHCPv4 message has been transported over DHCPv6
///
/// @return Boolean value which indicates whether the message is
/// transported over DHCPv6 (true) or native DHCPv4 (false)
virtual bool isDhcp4o6() const {
return (false);
}
private:
/// @brief Generic method that validates and sets HW address.
///
/// This is a generic method used by all modifiers of this class
/// which set class members representing HW address.
///
/// @param htype hardware type.
/// @param hlen hardware length.
/// @param mac_addr pointer to actual hardware address.
/// @param [out] hw_addr pointer to a class member to be modified.
///
/// @trow isc::OutOfRange if invalid HW address specified.
virtual void setHWAddrMember(const uint8_t htype, const uint8_t hlen,
const std::vector<uint8_t>& mac_addr,
HWAddrPtr& hw_addr);
protected:
/// converts DHCP message type to BOOTP op type
///
/// @param dhcpType DHCP message type (e.g. DHCPDISCOVER)
///
/// @return BOOTP type (BOOTREQUEST or BOOTREPLY)
uint8_t
DHCPTypeToBootpType(uint8_t dhcpType);
/// @brief No-op
///
/// This method returns hardware address generated from the IPv6 link-local
/// address. As there is no IPv4-equivalent, it always returns NULL.
/// We need this stub implementation here, to keep all the get hardware
/// address logic in the base class.
///
/// @return always NULL
virtual HWAddrPtr getMACFromSrcLinkLocalAddr() {
return (HWAddrPtr());
}
/// @brief No-op
///
/// This method returns hardware address extracted from an IPv6 relay agent.
/// option. As there is no IPv4-equivalent, it always returns NULL.
/// We need this stub implementation here, to keep all the get hardware
/// address logic in the base class.
///
/// @return always NULL
virtual HWAddrPtr getMACFromIPv6RelayOpt() {
return (HWAddrPtr());
}
/// @brief No-op
///
/// This is a DHCPv4 version of the function that attempts to extract
/// MAC address from the options inserted by a cable modem. It is currently
/// not implemented for v4.
///
/// @return always NULL
virtual HWAddrPtr getMACFromDocsisModem() {
return (HWAddrPtr());
}
/// @brief No-op
///
/// This method returns hardware address extracted from DUID.
/// Currently it is a no-op, even though there's RFC that defines how to
/// use DUID in DHCPv4 (see RFC4361). We may implement it one day.
///
/// @return always NULL
virtual HWAddrPtr getMACFromDUID(){
return (HWAddrPtr());
}
/// @brief No-op
///
/// This is a DHCPv4 version of the function that attempts to extract
/// MAC address from the options inserted by a CMTS. It is currently
/// not implemented for v4.
///
/// @return always NULL
virtual HWAddrPtr getMACFromDocsisCMTS() {
return (HWAddrPtr());
}
/// @brief No-op
///
/// This method returns hardware address extracted from remote-id relay option.
/// Currently it is a no-op, it always returns NULL.
///
/// @return always NULL
virtual HWAddrPtr getMACFromRemoteIdRelayOption() {
return (HWAddrPtr());
}
/// @brief local HW address (dst if receiving packet, src if sending packet)
HWAddrPtr local_hwaddr_;
// @brief List of deferred option codes
std::list<uint16_t> deferred_options_;
/// @brief message operation code
///
/// Note: This is legacy BOOTP field. There's no need to manipulate it
/// directly. Its value is set based on DHCP message type. Note that
/// DHCPv4 protocol reuses BOOTP message format, so this field is
/// kept due to BOOTP format. This is NOT DHCPv4 type (DHCPv4 message
/// type is kept in message type option).
uint8_t op_;
/// @brief link-layer address and hardware information
/// represents 3 fields: htype (hardware type, 1 byte), hlen (length of the
/// hardware address, up to 16) and chaddr (hardware address field,
/// 16 bytes)
HWAddrPtr hwaddr_;
/// Number of relay agents traversed
uint8_t hops_;
/// elapsed (number of seconds since beginning of transmission)
uint16_t secs_;
/// flags
uint16_t flags_;
/// ciaddr field (32 bits): Client's IP address
isc::asiolink::IOAddress ciaddr_;
/// yiaddr field (32 bits): Client's IP address ("your"), set by server
isc::asiolink::IOAddress yiaddr_;
/// siaddr field (32 bits): next server IP address in boot process(e.g.TFTP)
isc::asiolink::IOAddress siaddr_;
/// giaddr field (32 bits): Gateway IP address
isc::asiolink::IOAddress giaddr_;
/// sname field (64 bytes)
uint8_t sname_[MAX_SNAME_LEN];
/// file field (128 bytes)
uint8_t file_[MAX_FILE_LEN];
// end of real DHCPv4 fields
}; // Pkt4 class
/// @brief A pointer to Pkt4 object.
typedef boost::shared_ptr<Pkt4> Pkt4Ptr;
} // isc::dhcp namespace
} // isc namespace
#endif
|