summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/pkt4.h
blob: ac88e3ccd6b08d7e02016b5bb56800b40c27dd25 (plain)
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
// Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#ifndef PKT4_H
#define PKT4_H

#include <asiolink/io_address.h>
#include <dhcp/option.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 <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. DHCPDISOVER=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 writting 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 performs sanity check on a packet.
    ///
    /// This is usually performed after unpack(). It checks if packet is sane:
    /// required options are present, fields have sane content etc.
    /// For example verifies that DHCP_MESSAGE_TYPE is present and have
    /// reasonable value. This method is expected to grow significantly.
    /// It makes sense to separate unpack() and check() for testing purposes.
    ///
    /// @todo It is called from unpack() directly. It should be separated.
    ///
    /// Method will throw exception if anomaly is found.
    void check();

    /// @brief Returns text representation of the packet.
    ///
    /// This function is useful mainly for debugging.
    ///
    /// @return string with text representation
    std::string toText();

    /// @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).
    ///
    /// @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 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 = MAX_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 = MAX_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 Add an option.
    ///
    /// @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 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).
    ///
    /// This function uses a combination of Giaddr and Hops. It is expected that
    /// if Giaddr is not 0, the Hops is greater than 0. In this case the message
    /// is considered relayed. If Giaddr is 0, the Hops value must also be 0. In
    /// this case the message is considered non-relayed. For any other
    /// combination of Giaddr and Hops, an exception is thrown to indicate that
    /// the message is malformed.
    ///
    /// @return Boolean value which indicates whether the message is relayed
    /// (true) or non-relayed (false).
    /// @throw isc::BadValue if invalid combination of Giaddr and Hops values is
    /// found.
    bool isRelayed() const;

    /// @brief That's the data of input buffer used in RX packet.
    ///
    /// @note Note that InputBuffer does not store the data itself, but just
    /// expects that data will be valid for the whole life of InputBuffer.
    /// Therefore we need to keep the data around.
    ///
    /// @warning This public member is accessed by derived
    /// classes directly. One of such derived classes is
    /// @ref perfdhcp::PerfPkt4. The impact on derived clasess'
    /// behavior must be taken into consideration before making
    /// changes to this member such as access scope restriction or
    /// data format change etc. This field is also public, because
    /// it may be modified by callouts (which are written in C++ now,
    /// but we expect to also have them in Python, so any accesibility
    /// methods would overly complicate things here and degrade
    /// performance).
    std::vector<uint8_t> data_;

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 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());
    }

    /// local HW address (dst if receiving packet, src if sending packet)
    HWAddrPtr local_hwaddr_;

    /// @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