summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/pkt4.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/pkt4.h')
-rw-r--r--src/lib/dhcp/pkt4.h549
1 files changed, 549 insertions, 0 deletions
diff --git a/src/lib/dhcp/pkt4.h b/src/lib/dhcp/pkt4.h
new file mode 100644
index 0000000..59d1bc1
--- /dev/null
+++ b/src/lib/dhcp/pkt4.h
@@ -0,0 +1,549 @@
+// Copyright (C) 2011-2022 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 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 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