pkt4.h 16.9 KB
Newer Older
1
// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//
// 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

18 19 20
#include <asiolink/io_address.h>
#include <util/buffer.h>
#include <dhcp/option.h>
21
#include <dhcp/hwaddr.h>
22 23 24 25

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/shared_ptr.hpp>

26
#include <iostream>
27
#include <vector>
28 29

#include <time.h>
30 31 32 33 34 35 36 37

namespace isc {

namespace dhcp {

class Pkt4 {
public:

38
    /// length of the CHADDR field in DHCPv4 message
39 40
    const static size_t MAX_CHADDR_LEN = 16;

41
    /// length of the SNAME field in DHCPv4 message
42 43
    const static size_t MAX_SNAME_LEN = 64;

44
    /// length of the FILE field in DHCPv4 message
45 46
    const static size_t MAX_FILE_LEN = 128;

47
    /// specifies DHCPv4 packet header length (fixed part)
48 49
    const static size_t DHCPV4_PKT_HDR_LEN = 236;

50
    /// Constructor, used in replying to a message.
51 52 53 54 55
    ///
    /// @param msg_type type of message (e.g. DHCPDISOVER=1)
    /// @param transid transaction-id
    Pkt4(uint8_t msg_type, uint32_t transid);

56
    /// @brief Constructor, used in message reception.
57
    ///
58 59
    /// Creates new message. Pkt4 will copy data to bufferIn_
    /// buffer on creation.
60 61 62 63 64
    ///
    /// @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);

65
    /// @brief Prepares on-wire format of DHCPv4 packet.
66 67 68
    ///
    /// Prepares on-wire format of message and all its options.
    /// Options must be stored in options_ field.
69
    /// Output buffer will be stored in bufferOut_.
70 71 72 73 74
    ///
    /// @return true if packing procedure was successful
    bool
    pack();

75 76 77
    /// @brief Parses on-wire form of DHCPv4 packet.
    ///
    /// Parses received packet, stored in on-wire format in bufferIn_.
78 79 80 81
    ///
    /// Will create a collection of option objects that will
    /// be stored in options_ container.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
82 83
    /// Method with throw exception if packet parsing fails.
    void unpack();
84

85 86 87 88 89 90 91 92
    /// @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.
    ///
93
    /// @todo It is called from unpack() directly. It should be separated.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
94
    ///
95 96 97
    /// Method will throw exception if anomaly is found.
    void check();

98 99 100 101 102 103 104 105
    /// @brief Copies content of input buffer to output buffer.
    ///
    /// This is mostly a diagnostic function. It is being used for sending
    /// received packet. Received packet is stored in bufferIn_, but
    /// transmitted data is stored in bufferOut_. If we want to send packet
    /// that we just received, a copy between those two buffers is necessary.
    void repack();

106 107 108 109 110
    /// @brief Returns text representation of the packet.
    ///
    /// This function is useful mainly for debugging.
    ///
    /// @return string with text representation
111
    std::string toText();
112

113
    /// @brief Returns the size of the required buffer to build the packet.
114
    ///
115 116
    /// Returns the size of the required buffer to build the packet with
    /// the current set of packet options.
117 118
    ///
    /// @return number of bytes required to build this packet
119
    size_t len();
120

121
    /// @brief Sets hops field.
122 123
    ///
    /// @param hops value to be set
124
    void setHops(uint8_t hops) { hops_ = hops; };
125

126
    /// @brief Returns hops field.
127 128
    ///
    /// @return hops field
129
    uint8_t getHops() const { return (hops_); };
130 131 132 133

    // Note: There's no need to manipulate OP field directly,
    // thus no setOp() method. See op_ comment.

134
    /// @brief Returns op field.
135 136
    ///
    /// @return op field
137
    uint8_t getOp() const { return (op_); };
138

139
    /// @brief Sets secs field.
140 141
    ///
    /// @param secs value to be set
142
    void setSecs(uint16_t secs) { secs_ = secs; };
143

144
    /// @brief Returns secs field.
145 146
    ///
    /// @return secs field
147
    uint16_t getSecs() const { return (secs_); };
148

149
    /// @brief Sets flags field.
150 151
    ///
    /// @param flags value to be set
152
    void setFlags(uint16_t flags) { flags_ = flags; };
153

154
    /// @brief Returns flags field.
155 156
    ///
    /// @return flags field
157
    uint16_t getFlags() const { return (flags_); };
158 159


160
    /// @brief Returns ciaddr field.
161 162
    ///
    /// @return ciaddr field
Tomek Mrugalski's avatar
Tomek Mrugalski committed
163 164
    const isc::asiolink::IOAddress&
    getCiaddr() const { return (ciaddr_); };
165

166
    /// @brief Sets ciaddr field.
167 168 169 170 171 172
    ///
    /// @param ciaddr value to be set
    void
    setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; };


173
    /// @brief Returns siaddr field.
174 175
    ///
    /// @return siaddr field
Tomek Mrugalski's avatar
Tomek Mrugalski committed
176 177
    const isc::asiolink::IOAddress&
    getSiaddr() const { return (siaddr_); };
178

179
    /// @brief Sets siaddr field.
180 181 182 183 184 185
    ///
    /// @param siaddr value to be set
    void
    setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; };


186
    /// @brief Returns yiaddr field.
187 188
    ///
    /// @return yiaddr field
Tomek Mrugalski's avatar
Tomek Mrugalski committed
189 190
    const isc::asiolink::IOAddress&
    getYiaddr() const { return (yiaddr_); };
191

192
    /// @brief Sets yiaddr field.
193 194 195 196 197 198
    ///
    /// @param yiaddr value to be set
    void
    setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; };


199
    /// @brief Returns giaddr field.
200 201
    ///
    /// @return giaddr field
Tomek Mrugalski's avatar
Tomek Mrugalski committed
202 203
    const isc::asiolink::IOAddress&
    getGiaddr() const { return (giaddr_); };
204

205
    /// @brief Sets giaddr field.
206 207 208 209 210
    ///
    /// @param giaddr value to be set
    void
    setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };

211 212 213 214 215
    /// @brief Sets transaction-id value
    ///
    /// @param transid transaction-id to be set.
    void setTransid(uint32_t transid) { transid_ = transid; }

216
    /// @brief Returns value of transaction-id field.
217 218
    ///
    /// @return transaction-id
Tomek Mrugalski's avatar
Tomek Mrugalski committed
219
    uint32_t getTransid() const { return (transid_); };
220

221
    /// @brief Returns message type (e.g. 1 = DHCPDISCOVER).
222 223 224
    ///
    /// @return message type
    uint8_t
Tomek Mrugalski's avatar
Tomek Mrugalski committed
225
    getType() const { return (msg_type_); }
226

227
    /// @brief Sets message type (e.g. 1 = DHCPDISCOVER).
228 229 230 231 232 233 234
    ///
    /// @param type message type to be set
    void setType(uint8_t type) { msg_type_=type; };

    /// @brief Returns sname field
    ///
    /// Note: This is 64 bytes long field. It doesn't have to be
235
    /// null-terminated. Do not use strlen() or similar on it.
236 237
    ///
    /// @return sname field
238
    const OptionBuffer
Tomek Mrugalski's avatar
Tomek Mrugalski committed
239
    getSname() const { return (std::vector<uint8_t>(sname_, &sname_[MAX_SNAME_LEN])); };
240

241
    /// @brief Sets sname field.
242 243
    ///
    /// @param sname value to be set
244 245
    /// @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);
246 247 248 249

    /// @brief Returns file field
    ///
    /// Note: This is 128 bytes long field. It doesn't have to be
250
    /// null-terminated. Do not use strlen() or similar on it.
251 252
    ///
    /// @return pointer to file field
253
    const OptionBuffer
Tomek Mrugalski's avatar
Tomek Mrugalski committed
254
    getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); };
255 256 257 258

    /// Sets file field
    ///
    /// @param file value to be set
259
    /// @param file_len length of the file buffer (up to MAX_FILE_LEN)
260
    void
261
    setFile(const uint8_t* file, size_t file_len = MAX_FILE_LEN);
262

263 264 265
    /// @brief Sets hardware address.
    ///
    /// Sets parameters of hardware address. hlen specifies
266
    /// length of mac_addr buffer. Content of mac_addr buffer
267 268
    /// will be copied to appropriate field.
    ///
269
    /// Note: mac_addr must be a buffer of at least hlen bytes.
270
    ///
271
    /// @param hType hardware type (will be sent in htype field)
272
    /// @param hlen hardware length (will be sent in hlen field)
273
    /// @param mac_addr pointer to hardware address
274
    void setHWAddr(uint8_t hType, uint8_t hlen,
275
                   const std::vector<uint8_t>& mac_addr);
276

277 278 279 280 281 282 283
    /// @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);

284 285 286 287
    /// Returns htype field
    ///
    /// @return hardware type
    uint8_t
288
    getHtype() const;
289 290 291 292 293

    /// Returns hlen field
    ///
    /// @return hardware address length
    uint8_t
294
    getHlen() const;
295

296 297 298
    /// @brief returns hardware address information
    /// @return hardware address structure
    HWAddrPtr getHWAddr() const { return (hwaddr_); }
299

300
    /// @brief Returns reference to output buffer.
301 302
    ///
    /// Returned buffer will contain reasonable data only for
Tomek Mrugalski's avatar
Tomek Mrugalski committed
303 304
    /// output (TX) packet and after pack() was called. This buffer
    /// is only valid till Pkt4 object is valid.
305 306 307 308 309
    ///
    /// RX packet or TX packet before pack() will return buffer with
    /// zero length
    ///
    /// @return reference to output buffer
Tomek Mrugalski's avatar
Tomek Mrugalski committed
310 311
    const isc::util::OutputBuffer&
    getBuffer() const { return (bufferOut_); };
312

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    /// @brief Add an option.
    ///
    /// Throws BadValue if option with that type is already present.
    ///
    /// @param opt option to be added
    void
    addOption(boost::shared_ptr<Option> opt);

    /// @brief Returns an option of specified type.
    ///
    /// @return returns option of requested type (or NULL)
    ///         if no such option is present
    boost::shared_ptr<Option>
    getOption(uint8_t opt_type);

328 329 330 331 332 333
    /// @brief Returns interface name.
    ///
    /// Returns interface name over which packet was received or is
    /// going to be transmitted.
    ///
    /// @return interface name
Tomek Mrugalski's avatar
Tomek Mrugalski committed
334
    std::string getIface() const { return iface_; };
335

336 337 338 339 340 341
    /// @brief Returns packet timestamp.
    ///
    /// Returns packet timestamp value updated when
    /// packet is received or send.
    ///
    /// @return packet timestamp.
342
    const boost::posix_time::ptime& getTimestamp() const { return timestamp_; }
343

344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
    /// @brief Sets interface name.
    ///
    /// Sets interface name over which packet was received or is
    /// going to be transmitted.
    ///
    /// @return interface name
    void setIface(const std::string& iface ) { iface_ = iface; };

    /// @brief Sets interface index.
    ///
    /// @param ifindex specifies interface index.
    void setIndex(uint32_t ifindex) { ifindex_ = ifindex; };

    /// @brief Returns interface index.
    ///
    /// @return interface index
360
    uint32_t getIndex() const { return (ifindex_); };
361 362 363

    /// @brief Sets remote address.
    ///
364
    /// @param remote specifies remote address
365 366 367 368 369 370 371
    void setRemoteAddr(const isc::asiolink::IOAddress& remote) {
        remote_addr_ = remote;
    }

    /// @brief Returns remote address
    ///
    /// @return remote address
372
    const isc::asiolink::IOAddress& getRemoteAddr() const {
373 374 375 376 377
        return (remote_addr_);
    }

    /// @brief Sets local address.
    ///
378
    /// @param local specifies local address
379 380 381 382 383 384 385
    void setLocalAddr(const isc::asiolink::IOAddress& local) {
        local_addr_ = local;
    }

    /// @brief Returns local address.
    ///
    /// @return local address
386
    const isc::asiolink::IOAddress& getLocalAddr() const {
387 388 389 390 391
        return (local_addr_);
    }

    /// @brief Sets local port.
    ///
392
    /// @param local specifies local port
393 394 395 396 397
    void setLocalPort(uint16_t local) { local_port_ = local; }

    /// @brief Returns local port.
    ///
    /// @return local port
398
    uint16_t getLocalPort() const { return (local_port_); }
399 400 401

    /// @brief Sets remote port.
    ///
402
    /// @param remote specifies remote port
403 404 405 406 407
    void setRemotePort(uint16_t remote) { remote_port_ = remote; }

    /// @brief Returns remote port.
    ///
    /// @return remote port
408
    uint16_t getRemotePort() const { return (remote_port_); }
409

410 411 412 413 414 415 416 417
    /// @brief Update packet timestamp.
    ///
    /// Updates packet timestamp. This method is invoked
    /// by interface manager just before sending or
    /// just after receiving it.
    /// @throw isc::Unexpected if timestamp update failed
    void updateTimestamp();

418 419
protected:

420 421 422 423 424 425 426 427
    /// 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);

428 429 430 431 432 433 434 435 436 437 438
    /// local address (dst if receiving packet, src if sending packet)
    isc::asiolink::IOAddress local_addr_;

    /// remote address (src if receiving packet, dst if sending packet)
    isc::asiolink::IOAddress remote_addr_;

    /// name of the network interface the packet was received/to be sent over
    std::string iface_;

    /// @brief interface index
    ///
439 440 441
    /// Each network interface has assigned unique ifindex. It is functional
    /// equvalent of name, but sometimes more useful, e.g. when using crazy
    /// systems that allow spaces in interface names e.g. MS Windows)
442
    uint32_t ifindex_;
443 444

    /// local UDP port
445
    uint16_t local_port_;
446 447

    /// remote UDP port
448
    uint16_t remote_port_;
449

450
    /// @brief message operation code
451
    ///
452 453 454 455 456
    /// 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).
457 458
    uint8_t op_;

459 460 461 462 463
    /// @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_;
464 465 466 467 468 469 470 471 472 473 474 475 476

    /// Number of relay agents traversed
    uint8_t hops_;

    /// DHCPv4 transaction-id (32 bits, not 24 bits as in DHCPv6)
    uint32_t transid_;

    /// elapsed (number of seconds since beginning of transmission)
    uint16_t secs_;

    /// flags
    uint16_t flags_;

477
    /// ciaddr field (32 bits): Client's IP address
478 479
    isc::asiolink::IOAddress ciaddr_;

480
    /// yiaddr field (32 bits): Client's IP address ("your"), set by server
481 482
    isc::asiolink::IOAddress yiaddr_;

483
    /// siaddr field (32 bits): next server IP address in boot process(e.g.TFTP)
484 485
    isc::asiolink::IOAddress siaddr_;

486
    /// giaddr field (32 bits): Gateway IP address
487 488
    isc::asiolink::IOAddress giaddr_;

489 490
    /// sname field (64 bytes)
    uint8_t sname_[MAX_SNAME_LEN];
491

492 493
    /// file field (128 bytes)
    uint8_t file_[MAX_FILE_LEN];
494 495 496

    // end of real DHCPv4 fields

497
    /// output buffer (used during message transmission)
498 499 500 501 502 503 504
    ///
    /// @warning This protected 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.
505 506
    isc::util::OutputBuffer bufferOut_;

507 508 509 510
    /// that's the data of input buffer used in RX packet. 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.
511 512 513 514 515 516 517
    ///
    /// @warning This protected 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.
518 519
    std::vector<uint8_t> data_;

520
    /// message type (e.g. 1=DHCPDISCOVER)
521
    /// @todo this will eventually be replaced with DHCP Message Type
522 523 524 525
    /// option (option 53)
    uint8_t msg_type_;

    /// collection of options present in this message
526
    ///
527
    /// @warning This protected member is accessed by derived
528 529 530 531 532
    /// 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.
533
    isc::dhcp::Option::OptionCollection options_;
534 535

    /// packet timestamp
536
    boost::posix_time::ptime timestamp_;
537 538
}; // Pkt4 class

539 540
typedef boost::shared_ptr<Pkt4> Pkt4Ptr;

541 542 543 544 545
} // isc::dhcp namespace

} // isc namespace

#endif