pkt6.h 17.5 KB
Newer Older
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1
// Copyright (C) 2011-2013 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 PKT6_H
#define PKT6_H

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

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

25
#include <iostream>
26

27
#include <time.h>
28 29 30

namespace isc {

31
namespace dhcp {
32

33 34
class Pkt6 {
public:
35
    /// specifies non-relayed DHCPv6 packet header length (over UDP)
36
    const static size_t DHCPV6_PKT_HDR_LEN = 4;
37

38 39 40
    /// specifies relay DHCPv6 packet header length (over UDP)
    const static size_t DHCPV6_RELAY_HDR_LEN = 34;

41 42 43 44
    /// DHCPv6 transport protocol
    enum DHCPv6Proto {
        UDP = 0, // most packets are UDP
        TCP = 1  // there are TCP DHCPv6 packets (bulk leasequery, failover)
45
    };
46

47 48 49 50 51

    /// @brief structure that describes a single relay information
    ///
    /// Client sends messages. Each relay along its way will encapsulate the message.
    /// This structure represents all information added by a single relay.
52 53
    struct RelayInfo {

54
        /// @brief default constructor
55
        RelayInfo();
56 57 58 59 60 61 62 63
        uint8_t   msg_type_;               ///< message type (RELAY-FORW oro RELAY-REPL)
        uint8_t   hop_count_;              ///< number of traversed relays (up to 32)
        isc::asiolink::IOAddress linkaddr_;///< fixed field in relay-forw/relay-reply
        isc::asiolink::IOAddress peeraddr_;///< fixed field in relay-forw/relay-reply

        /// @brief length of the relay_msg_len
        /// Used when calculating length during pack/unpack
        uint16_t  relay_msg_len_;
64

65 66
        /// options received from a specified relay, except relay-msg option
        isc::dhcp::Option::OptionCollection options_;
67 68
    };

69 70 71 72 73
    /// Constructor, used in replying to a message
    ///
    /// @param msg_type type of message (SOLICIT=1, ADVERTISE=2, ...)
    /// @param transid transaction-id
    /// @param proto protocol (TCP or UDP)
74 75
    Pkt6(uint8_t msg_type,
         uint32_t transid,
76 77 78 79 80 81
         DHCPv6Proto proto = UDP);

    /// Constructor, used in message transmission
    ///
    /// Creates new message. Transaction-id will randomized.
    ///
82 83
    /// @param buf pointer to a buffer of received packet content
    /// @param len size of buffer of received packet content
84
    /// @param proto protocol (usually UDP, but TCP will be supported eventually)
85
    Pkt6(const uint8_t* buf, uint32_t len, DHCPv6Proto proto = UDP);
86 87 88 89 90 91 92 93 94

    /// @brief Prepares on-wire format.
    ///
    /// Prepares on-wire format of message and all its options.
    /// Options must be stored in options_ field.
    /// Output buffer will be stored in data_. Length
    /// will be set in data_len_.
    ///
    /// @return true if packing procedure was successful
95
    bool pack();
96 97 98 99 100 101 102

    /// @brief Dispatch method that handles binary packet parsing.
    ///
    /// This method calls appropriate dispatch function (unpackUDP or
    /// unpackTCP).
    ///
    /// @return true if parsing was successful
103
    bool unpack();
104

105 106 107 108
    /// @brief Returns reference to output buffer.
    ///
    /// Returned buffer will contain reasonable data only for
    /// output (TX) packet and after pack() was called. This buffer
109
    /// is only valid till Pkt6 object is valid.
110 111 112 113 114 115 116 117 118 119 120 121 122
    ///
    /// RX packet or TX packet before pack() will return buffer with
    /// zero length
    ///
    /// @return reference to output buffer
    const isc::util::OutputBuffer& getBuffer() const { return (bufferOut_); };

    /// @brief Returns reference to input buffer.
    ///
    /// @return reference to input buffer
    const OptionBuffer& getData() const { return(data_); }

    /// @brief Returns protocol of this packet (UDP or TCP).
123 124
    ///
    /// @return protocol type
125
    DHCPv6Proto getProto();
126 127 128 129

    /// Sets protocol of this packet.
    ///
    /// @param proto protocol (UDP or TCP)
130
    void setProto(DHCPv6Proto proto = UDP) { proto_ = proto; }
131 132 133 134 135 136

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

139
    /// @brief Returns length of the packet.
140
    ///
141 142 143
    /// This function returns size required to hold this packet.
    /// It includes DHCPv6 header and all options stored in
    /// options_ field.
144
    ///
145 146 147 148
    /// Note: It does not return proper length of incoming packets
    /// before they are unpacked.
    ///
    /// @return number of bytes required to assemble this packet
149
    uint16_t len();
150 151 152 153

    /// Returns message type (e.g. 1 = SOLICIT)
    ///
    /// @return message type
154
    uint8_t getType() const { return (msg_type_); }
155 156 157 158

    /// Sets message type (e.g. 1 = SOLICIT)
    ///
    /// @param type message type to be set
159
    void setType(uint8_t type) { msg_type_=type; };
160

161 162 163 164 165
    /// @brief Sets transaction-id value
    ///
    /// @param transid transaction-id to be set.
    void setTransid(uint32_t transid) { transid_ = transid; }

166 167 168
    /// Returns value of transaction-id field
    ///
    /// @return transaction-id
169
    uint32_t getTransid() const { return (transid_); };
170 171 172 173

    /// Adds an option to this packet.
    ///
    /// @param opt option to be added.
174
    void addOption(const OptionPtr& opt);
175 176 177 178 179

    /// @brief Returns the first option of specified type.
    ///
    /// Returns the first option of specified type. Note that in DHCPv6 several
    /// instances of the same option are allowed (and frequently used).
180
    /// Also see \ref getOptions().
181
    ///
182
    /// @param type option type we are looking for
183 184
    ///
    /// @return pointer to found option (or NULL)
185
    OptionPtr getOption(uint16_t type);
186

Tomek Mrugalski's avatar
Tomek Mrugalski committed
187 188 189 190 191
    /// @brief returns option inserted by relay
    ///
    /// Returns an option from specified relay scope (inserted by a given relay
    /// if this is received packet or to be decapsulated by a given relay if
    /// this is a transmitted packet). nesting_level specifies which relay
192
    /// scope is to be used. 0 is the outermost encapsulation (relay closest to
Tomek Mrugalski's avatar
Tomek Mrugalski committed
193 194 195 196 197 198 199 200 201 202
    /// the server). pkt->relay_info_.size() - 1 is the innermost encapsulation
    /// (relay closest to the client).
    ///
    /// @throw isc::OutOfRange if nesting level has invalid value.
    ///
    /// @param option_code code of the requested option
    /// @param nesting_level see description above
    ///
    /// @return pointer to the option (or NULL if there is no such option)
    OptionPtr getRelayOption(uint16_t option_code, uint8_t nesting_level);
203

204 205 206 207 208 209 210 211 212
    /// @brief Returns all instances of specified type.
    ///
    /// Returns all instances of options of the specified type. DHCPv6 protocol
    /// allows (and uses frequently) multiple instances.
    ///
    /// @param type option type we are looking for
    /// @return instance of option collection with requested options
    isc::dhcp::Option::OptionCollection getOptions(uint16_t type);

213 214 215 216 217
    /// Attempts to delete first suboption of requested type
    ///
    /// @param type Type of option to be deleted.
    ///
    /// @return true if option was deleted, false if no such option existed
218
    bool delOption(uint16_t type);
219

220 221 222 223
    /// @brief This method copies data from output buffer to input buffer
    ///
    /// This is useful only in testing
    void repack();
224

225 226
    /// @brief Sets remote address.
    ///
227
    /// @param remote specifies remote address
228
    void setRemoteAddr(const isc::asiolink::IOAddress& remote) { remote_addr_ = remote; }
229

230 231 232
    /// @brief Returns remote address
    ///
    /// @return remote address
233 234 235
    const isc::asiolink::IOAddress& getRemoteAddr() const {
        return (remote_addr_);
    }
236

237 238
    /// @brief Sets local address.
    ///
239
    /// @param local specifies local address
240
    void setLocalAddr(const isc::asiolink::IOAddress& local) { local_addr_ = local; }
241

242 243 244
    /// @brief Returns local address.
    ///
    /// @return local address
245 246 247
    const isc::asiolink::IOAddress& getLocalAddr() const {
        return (local_addr_);
    }
248

249 250
    /// @brief Sets local port.
    ///
251
    /// @param local specifies local port
252
    void setLocalPort(uint16_t local) { local_port_ = local; }
253

254
    /// @brief Returns local port.
255
    ///
256
    /// @return local port
257
    uint16_t getLocalPort() const { return (local_port_); }
258

259 260
    /// @brief Sets remote port.
    ///
261
    /// @param remote specifies remote port
262
    void setRemotePort(uint16_t remote) { remote_port_ = remote; }
263

264 265 266
    /// @brief Returns remote port.
    ///
    /// @return remote port
267
    uint16_t getRemotePort() const { return (remote_port_); }
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

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

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

    /// @brief Returns interface name.
    ///
    /// Returns interface name over which packet was received or is
    /// going to be transmitted.
    ///
    /// @return interface name
    std::string getIface() const { return iface_; };

287 288 289
    /// @brief Returns packet timestamp.
    ///
    /// Returns packet timestamp value updated when
290
    /// packet is received or sent.
291 292
    ///
    /// @return packet timestamp.
293
    const boost::posix_time::ptime& getTimestamp() const { return timestamp_; }
294

295 296 297 298 299 300 301
    /// @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; };
302

303 304 305 306 307 308 309 310
    /// @brief add information about one traversed relay
    ///
    /// This adds information about one traversed relay, i.e.
    /// one relay-forw or relay-repl level of encapsulation.
    ///
    /// @param relay structure with necessary relay information
    void addRelayInfo(const RelayInfo& relay);

311
    /// collection of options present in this message
312
    ///
313 314
    /// @todo: Text mentions protected, but this is really public
    ///
315 316 317 318 319 320
    /// @warning This protected member is accessed by derived
    /// classes directly. One of such derived classes is
    /// @ref perfdhcp::PerfPkt6. 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.
321
    isc::dhcp::Option::OptionCollection options_;
322

323 324 325 326 327 328 329 330
    /// @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();

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
    /// @brief Return textual type of packet.
    ///
    /// Returns the name of valid packet received by the server (e.g. SOLICIT).
    /// If the packet is unknown - or if it is a valid DHCP packet but not one
    /// expected to be received by the server (such as an ADVERTISE), the string
    /// "UNKNOWN" is returned.  This method is used in debug messages.
    ///
    /// As the operation of the method does not depend on any server state, it
    /// is declared static. There is also non-static getName() method that
    /// works on Pkt6 objects.
    ///
    /// @param type DHCPv6 packet type
    ///
    /// @return Pointer to "const" string containing the packet name.
    ///         Note that this string is statically allocated and MUST NOT
    ///         be freed by the caller.
    static const char* getName(uint8_t type);

    /// @brief returns textual representation of packet type.
    ///
    /// This method requires an object. There is also static version, which
    /// requires one parameter (type).
    ///
    /// @return Pointer to "const" string containing packet name.
    ///         Note that this string is statically allocated and MUST NOT
    ///         be freed by the caller.
    const char* getName() const;

359 360 361 362 363 364 365 366 367
    /// relay information
    ///
    /// this is a public field. Otherwise we hit one of the two problems:
    /// we return reference to an internal field (and that reference could
    /// be potentially used past Pkt6 object lifetime causing badness) or
    /// we return a copy (which is inefficient and also causes any updates
    /// to be impossible). Therefore public field is considered the best
    /// (or least bad) solution.
    std::vector<RelayInfo> relay_info_;
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
protected:
    /// Builds on wire packet for TCP transmission.
    ///
    /// TODO This function is not implemented yet.
    ///
    /// @return true, if build was successful
    bool packTCP();

    /// Builds on wire packet for UDP transmission.
    ///
    /// @return true, if build was successful
    bool packUDP();

    /// @brief Parses on-wire form of TCP DHCPv6 packet.
    ///
    /// Parses received packet, stored in on-wire format in data_.
    /// data_len_ must be set to indicate data length.
    /// Will create a collection of option objects that will
    /// be stored in options_ container.
    ///
    /// TODO This function is not implemented yet.
    ///
    /// @return true, if build was successful
    bool unpackTCP();

    /// @brief Parses on-wire form of UDP DHCPv6 packet.
    ///
    /// Parses received packet, stored in on-wire format in data_.
    /// data_len_ must be set to indicate data length.
    /// Will create a collection of option objects that will
    /// be stored in options_ container.
    ///
    /// @return true, if build was successful
    bool unpackUDP();

403 404 405 406 407 408 409 410 411
    /// @brief unpacks direct (non-relayed) message
    ///
    /// This method unpacks specified buffer range as a direct
    /// (e.g. solicit or request) message. This method is called from
    /// unpackUDP() when received message is detected to be direct.
    ///
    /// @param begin start of the buffer
    /// @param end end of the buffer
    /// @return true if parsing was successful and there are no leftover bytes
412 413 414
    bool unpackMsg(OptionBuffer::const_iterator begin,
                   OptionBuffer::const_iterator end);

415 416 417 418 419 420 421
    /// @brief unpacks relayed message (RELAY-FORW or RELAY-REPL)
    ///
    /// This method is called from unpackUDP() when received message
    /// is detected to be relay-message. It goes iteratively over
    /// all relays (if there are multiple encapsulation levels).
    ///
    /// @return true if parsing was successful
422 423
    bool unpackRelayMsg();

424 425 426
    /// @brief calculates overhead introduced in specified relay
    ///
    /// It is used when calculating message size and packing message
Tomek Mrugalski's avatar
Tomek Mrugalski committed
427
    /// @param relay RelayInfo structure that holds information about relay
428
    /// @return number of bytes needed to store relay information
429
    uint16_t getRelayOverhead(const RelayInfo& relay) const;
430

431 432
    /// @brief calculates overhead for all relays defined for this message
    /// @return number of bytes needed to store all relay information
433 434
    uint16_t calculateRelaySizes();

Tomek Mrugalski's avatar
Tomek Mrugalski committed
435
    /// @brief calculates size of the message as if it was not relayed at all
436
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
437
    /// This is equal to len() if the message was not relayed.
438
    /// @return number of bytes required to store the message
439
    uint16_t directLen() const;
440

441 442 443 444
    /// UDP (usually) or TCP (bulk leasequery or failover)
    DHCPv6Proto proto_;

    /// DHCPv6 message type
445
    uint8_t msg_type_;
446 447

    /// DHCPv6 transaction-id
448
    uint32_t transid_;
449 450

    /// unparsed data (in received packets)
451 452 453 454 455 456 457
    ///
    /// @warning This protected member is accessed by derived
    /// classes directly. One of such derived classes is
    /// @ref perfdhcp::PerfPkt6. 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.
458 459 460 461 462 463 464 465
    OptionBuffer data_;

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

    /// @brief interface index
    ///
    /// interface index (each network interface has assigned unique ifindex
466
    /// it is functional equivalent of name, but sometimes more useful, e.g.
467 468 469 470 471 472 473 474 475 476 477
    /// when using crazy systems that allow spaces in interface names
    /// e.g. windows
    int ifindex_;

    /// 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_;

    /// local TDP or UDP port
478
    uint16_t local_port_;
479 480

    /// remote TCP or UDP port
481
    uint16_t remote_port_;
482 483

    /// output buffer (used during message transmission)
484 485 486 487 488 489 490
    ///
    /// @warning This protected member is accessed by derived
    /// classes directly. One of such derived classes is
    /// @ref perfdhcp::PerfPkt6. 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.
491
    isc::util::OutputBuffer bufferOut_;
492 493

    /// packet timestamp
494
    boost::posix_time::ptime timestamp_;
495 496
}; // Pkt6 class

497 498
typedef boost::shared_ptr<Pkt6> Pkt6Ptr;

499 500 501
} // isc::dhcp namespace

} // isc namespace
502 503

#endif