// 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 #include #include #include #include #include #include #include #include #include #include #include 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(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(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& 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& 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& 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& 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 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 Pkt4Ptr; } // isc::dhcp namespace } // isc namespace #endif