diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
commit | f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch) | |
tree | 49e44c6f87febed37efb953ab5485aa49f6481a7 /src/lib/dhcp/option4_client_fqdn.h | |
parent | Initial commit. (diff) | |
download | isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.tar.xz isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.zip |
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/dhcp/option4_client_fqdn.h')
-rw-r--r-- | src/lib/dhcp/option4_client_fqdn.h | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/src/lib/dhcp/option4_client_fqdn.h b/src/lib/dhcp/option4_client_fqdn.h new file mode 100644 index 0000000..c34d6b7 --- /dev/null +++ b/src/lib/dhcp/option4_client_fqdn.h @@ -0,0 +1,377 @@ +// Copyright (C) 2013-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 OPTION4_CLIENT_FQDN_H +#define OPTION4_CLIENT_FQDN_H + +#include <dhcp/option.h> +#include <dns/name.h> + +#include <string> +#include <utility> + +namespace isc { +namespace dhcp { + +/// @brief Exception thrown when invalid flags have been specified for +/// DHCPv4 Client FQDN %Option. +class InvalidOption4FqdnFlags : public Exception { +public: + InvalidOption4FqdnFlags(const char* file, size_t line, const char* what) : + isc::Exception(file, line, what) {} +}; + +/// @brief Exception thrown when invalid domain name is specified. +class InvalidOption4FqdnDomainName : public Exception { +public: + InvalidOption4FqdnDomainName(const char* file, size_t line, + const char* what) : + isc::Exception(file, line, what) {} +}; + +/// Forward declaration to implementation of @c Option4ClientFqdn class. +class Option4ClientFqdnImpl; + +/// @brief Represents DHCPv4 Client FQDN %Option (code 81). +/// +/// This option has been defined in the RFC 4702 and it has a following +/// structure: +/// - Code (1 octet) - option code (always equal to 81). +/// - Len (1 octet) - a length of the option. +/// - Flags (1 octet) - a field carrying "NEOS" flags described below. +/// - RCODE1 (1 octet) - deprecated field which should be set to 0 by the client +/// and set to 255 by the server. +/// - RCODE2 (1 octet) - deprecated, should be used in the same way as RCODE1. +/// - Domain Name - variable length field comprising partial or fully qualified +/// domain name. +/// +/// The flags field has the following structure: +/// @code +/// 0 1 2 3 4 5 6 7 +/// +-+-+-+-+-+-+-+-+ +/// | MBZ |N|E|O|S| +/// +-+-+-+-+-+-+-+-+ +/// @endcode +/// where: +/// - N flag specifies whether server should (0) or should not (1) perform DNS +/// Update, +/// - E flag specifies encoding of the Domain Name field. If this flag is set +/// to 1 it indicates canonical wire format without compression. 0 indicates +/// the deprecated ASCII format. +/// - O flag is set by the server to indicate that it has overridden client's +/// preference set with the S bit. +/// - S flag specifies whether server should (1) or should not (0) perform +/// forward (FQDN-to-address) updates. +/// +/// This class exposes a set of functions to modify flags and check their +/// correctness. +/// +/// Domain names being carried by DHCPv4 Client Fqdn %Option can be fully +/// qualified or partial. Partial domain names are encoded similar to the +/// fully qualified domain names, except that they lack terminating zero +/// at the end of their wire representation (or lack of dot at the end, in +/// case of ASCII encoding). It is also accepted to create an instance of +/// this option which has empty domain-name. Clients use empty domain-names +/// to indicate that server should generate complete fully qualified +/// domain-name. +/// +/// Since domain names are case insensitive (see RFC 4343), this class +/// converts them to lower case format regardless if they are received over +/// the wire or created from strings. +/// +/// @warning: The RFC4702 section 2.3.1 states that the clients and servers +/// should use character sets specified in RFC952, section 2.1 for ASCII-encoded +/// domain-names. This class doesn't detect the character set violation for +/// ASCII-encoded domain-name. It could be implemented in the future but it is +/// not important now for two reasons: +/// - ASCII encoding is deprecated +/// - clients SHOULD obey restrictions but if they don't, server may still +/// process the option +/// +/// RFC 4702 mandates that the DHCP client sets RCODE1 and RCODE2 to 0 and that +/// server sets them to 255. This class allows to set the value for these +/// fields and both fields are always set to the same value. There is no way +/// to set them separately (e.g. set different value for RCODE1 and RCODE2). +/// However, there are no use cases which would require it. +/// +/// <b>Design choice:</b> This class uses pimpl idiom to separate the interface +/// from implementation specifics. Implementations may use different approaches +/// to handle domain names (mostly validation of the domain-names). The existing +/// @c isc::dns::Name class is a natural (and the simplest) choice to handle +/// domain-names. Use of this class however, implies that libdhcp must be linked +/// with libdns. At some point these libraries may need to be separated, i.e. to +/// support compilation and use of standalone DHCP server. This will require +/// that the part of implementation which deals with domain-names is modified to +/// not use classes from libdns. These changes will be transparent for this +/// interface. +class Option4ClientFqdn : public Option { +public: + + /// + /// @name A set of constants used to identify and set bits in the flags field + //@{ + static const uint8_t FLAG_S = 0x01; ///< Bit S + static const uint8_t FLAG_O = 0x02; ///< Bit O + static const uint8_t FLAG_E = 0x04; ///< Bit E + static const uint8_t FLAG_N = 0x08; ///< Bit N + //@} + + /// @brief Mask which zeroes MBZ flag bits. + static const uint8_t FLAG_MASK = 0xF; + + /// @brief Represents the value of one of the RCODE1 or RCODE2 fields. + /// + /// Typically, RCODE values are set to 255 by the server and to 0 by the + /// clients (as per RFC 4702). + class Rcode { + public: + Rcode(const uint8_t rcode) + : rcode_(rcode) { } + + /// @brief Returns the value of the RCODE. + /// + /// Returned value can be directly used to create the on-wire format + /// of the DHCPv4 Client FQDN %Option. + uint8_t getCode() const { + return (rcode_); + } + + private: + uint8_t rcode_; + }; + + + /// @brief Type of the domain-name: partial or full. + enum DomainNameType { + PARTIAL, + FULL + }; + + /// @brief The size in bytes of the fixed fields within DHCPv4 Client Fqdn + /// %Option. + /// + /// The fixed fields are: + /// - Flags + /// - RCODE1 + /// - RCODE2 + static const uint16_t FIXED_FIELDS_LEN = 3; + + /// @brief Constructor, creates option instance using flags and domain name. + /// + /// This constructor is used to create an instance of the option which will + /// be included in outgoing messages. + /// + /// Note that the RCODE values are encapsulated by the Rcode object (not a + /// simple uint8_t value). This helps to prevent a caller from confusing the + /// flags value with rcode value (both are uint8_t values). For example: + /// if caller swaps the two, it will be detected in the compilation time. + /// Also, this API encourages the caller to use two predefined functions: + /// @c RCODE_SERVER and @c RCODE_CLIENT to set the value of RCODE. These + /// functions generate objects which represent the only valid values to be + /// be passed to the constructor (255 and 0 respectively). Other + /// values should not be used. However, it is still possible that the other + /// entity (client or server) sends the option with invalid value. Although, + /// the RCODE values are ignored, there should be a way to represent such + /// invalid RCODE value. The Rcode class is capable of representing it. + /// + /// @param flags a combination of flags to be stored in flags field. + /// @param rcode @c Rcode object representing a value for RCODE1 and RCODE2 + /// fields of the option. Both fields are assigned the same value + /// encapsulated by the parameter. + /// @param domain_name a name to be stored in the domain-name field. + /// @param domain_name_type indicates if the domain name is partial + /// or full. + /// @throw InvalidOption4FqdnFlags if value of the flags field is wrong. + /// @throw InvalidOption4FqdnDomainName if the domain-name is invalid. + explicit Option4ClientFqdn(const uint8_t flags, + const Rcode& rcode, + const std::string& domain_name, + const DomainNameType domain_name_type = FULL); + + /// @brief Constructor, creates option instance with empty domain name. + /// + /// This constructor creates an instance of the option with empty + /// domain-name. This domain-name is marked partial. + /// + /// @param flags a combination of flags to be stored in flags field. + /// @param rcode @c Rcode object representing a value for RCODE1 and RCODE2 + /// fields. Both fields are assigned the same value encapsulated by this + /// parameter. + /// @throw InvalidOption4FqdnFlags if value of the flags field is invalid. + Option4ClientFqdn(const uint8_t flags, const Rcode& rcode); + + /// @brief Constructor, creates an option instance from part of the buffer. + /// + /// This constructor is mainly used to parse options in the received + /// messages. Function parameters specify buffer bounds from which the + /// option should be created. The size of the buffer chunk, specified by + /// the constructor's parameters should be equal or larger than the size + /// of the option. Otherwise, constructor will throw an exception. + /// + /// @param first the lower bound of the buffer to create option from. + /// @param last the upper bound of the buffer to create option from. + /// @throw InvalidOption4FqdnFlags if value of the flags field is invalid. + /// @throw InvalidOption4FqdnDomainName if the domain-name carried by the + /// option is invalid. + /// @throw OutOfRange if the option is truncated. + explicit Option4ClientFqdn(OptionBufferConstIter first, + OptionBufferConstIter last); + + /// @brief Copy constructor + Option4ClientFqdn(const Option4ClientFqdn& source); + + /// @brief Copies this option and returns a pointer to the copy. + virtual OptionPtr clone() const; + + /// @brief Destructor + virtual ~Option4ClientFqdn(); + + /// @brief Assignment operator + Option4ClientFqdn& operator=(const Option4ClientFqdn& source); + + /// @brief Checks if the specified flag of the DHCPv4 Client FQDN %Option + /// is set. + /// + /// @param flag A value specifying a bit within flags field to be checked. + /// It must be one of the following @c FLAG_S, @c FLAG_E, @c FLAG_O, + /// @c FLAG_N. + /// + /// @return true if the bit of the specified flags bit is set, false + /// otherwise. + /// @throw InvalidOption4ClientFlags if specified flag which value is to be + /// returned is invalid (is not one of the FLAG_S, FLAG_N, FLAG_O). + bool getFlag(const uint8_t flag) const; + + /// @brief Modifies the value of the specified DHCPv4 Client Fqdn %Option + /// flag. + /// + /// @param flag A value specifying a bit within flags field to be set. It + /// must be one of the following @c FLAG_S, @c FLAG_E, @c FLAG_O, @c FLAG_N. + /// @param set a boolean value which indicates whether flag should be + /// set (true), or cleared (false). + /// @throw InvalidOption4ClientFlags if specified flag which value is to be + /// set is invalid (is not one of the FLAG_S, FLAG_N, FLAG_O). + void setFlag(const uint8_t flag, const bool set); + + /// @brief Sets the flag field value to 0. + void resetFlags(); + + /// @brief Returns @c Rcode objects representing value of RCODE1 and RCODE2. + /// + /// @return Pair of Rcode objects of which first is the RCODE1 and the + /// second is RCODE2. + std::pair<Rcode, Rcode> getRcode() const; + + /// @brief Set Rcode value. + /// + /// @param rcode An @c Rcode object representing value of RCODE1 and RCODE2. + /// Both fields are assigned the same value. + void setRcode(const Rcode& rcode); + + /// @brief Returns the domain-name in the text format. + /// + /// If domain-name is partial, it lacks the dot at the end (e.g. myhost). + /// If domain-name is fully qualified, it has the dot at the end (e.g. + /// myhost.example.com.). + /// + /// @return domain-name in the text format. + std::string getDomainName() const; + + /// @brief Writes domain-name in the wire format into a buffer. + /// + /// The data being written are appended at the end of the buffer. + /// + /// @param [out] buf buffer where domain-name will be written. + void packDomainName(isc::util::OutputBuffer& buf) const; + + /// @brief Set new domain-name. + /// + /// @param domain_name domain name field value in the text format. + /// @param domain_name_type type of the domain name: partial or fully + /// qualified. + /// @throw InvalidOption4FqdnDomainName if the specified domain-name is + /// invalid. + void setDomainName(const std::string& domain_name, + const DomainNameType domain_name_type); + + /// @brief Set empty domain-name. + /// + /// This function is equivalent to @c Option6ClientFqdn::setDomainName + /// with empty partial domain-name. It is exception safe. + void resetDomainName(); + + /// @brief Returns enumerator value which indicates whether domain-name is + /// partial or full. + /// + /// @return An enumerator value indicating whether domain-name is partial + /// or full. + DomainNameType getDomainNameType() const; + + /// @brief Writes option in the wire format into a buffer. + /// + /// @param [out] buf output buffer where option data will be stored. + /// @param check if set to false, allows options larger than 255 for v4 + virtual void pack(isc::util::OutputBuffer& buf, bool check = true) const; + + /// @brief Parses option from the received buffer. + /// + /// Method creates an instance of the DHCPv4 Client FQDN %Option from the + /// wire format. Parameters specify the bounds of the buffer to read option + /// data from. The size of the buffer limited by the specified parameters + /// should be equal or larger than size of the option (including its + /// header). Otherwise exception will be thrown. + /// + /// @param first lower bound of the buffer to parse option from. + /// @param last upper bound of the buffer to parse option from. + virtual void unpack(OptionBufferConstIter first, + OptionBufferConstIter last); + + /// @brief Returns string representation of the option. + /// + /// The string returned by the method comprises the bit value of each + /// option flag and the domain-name. + /// + /// @param indent number of spaces before printed text. + /// + /// @return string with text representation. + virtual std::string toText(int indent = 0) const; + + /// @brief Returns length of the complete option (data length + + /// DHCPv4 option header). + /// + /// @return length of the option. + virtual uint16_t len() const; + + /// + /// @name Well known Rcode declarations for DHCPv4 Client FQDN %Option + /// + //@{ + /// @brief Rcode being set by the server. + inline static const Rcode& RCODE_SERVER() { + static Rcode rcode(255); + return (rcode); + } + + /// @brief Rcode being set by the client. + inline static const Rcode& RCODE_CLIENT() { + static Rcode rcode(0); + return (rcode); + } + //@} + +private: + + /// @brief A pointer to the implementation. + Option4ClientFqdnImpl* impl_; +}; + +/// A pointer to the @c Option4ClientFqdn object. +typedef boost::shared_ptr<Option4ClientFqdn> Option4ClientFqdnPtr; + +} // namespace isc::dhcp +} // namespace isc + +#endif // OPTION4_CLIENT_FQDN_H |