summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/option4_client_fqdn.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/option4_client_fqdn.h')
-rw-r--r--src/lib/dhcp/option4_client_fqdn.h377
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