summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/option4_dnr.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/option4_dnr.h')
-rw-r--r--src/lib/dhcp/option4_dnr.h526
1 files changed, 526 insertions, 0 deletions
diff --git a/src/lib/dhcp/option4_dnr.h b/src/lib/dhcp/option4_dnr.h
new file mode 100644
index 0000000..c79b2d4
--- /dev/null
+++ b/src/lib/dhcp/option4_dnr.h
@@ -0,0 +1,526 @@
+// Copyright (C) 2023 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_DNR_H
+#define OPTION4_DNR_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option_data_types.h>
+#include <dns/name.h>
+
+#include <unordered_set>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception thrown when invalid domain name is specified.
+class InvalidOptionDnrDomainName : public Exception {
+public:
+ InvalidOptionDnrDomainName(const char* file, size_t line, const char* what)
+ : isc::Exception(file, line, what) {
+ }
+};
+
+/// @brief Exception thrown when Service parameters have wrong format.
+class InvalidOptionDnrSvcParams : public Exception {
+public:
+ InvalidOptionDnrSvcParams(const char* file, size_t line, const char* what)
+ : isc::Exception(file, line, what) {
+ }
+};
+
+/// @brief Represents DNR Instance which is used both in DHCPv4
+/// and DHCPv6 Encrypted DNS %Option.
+///
+/// DNR Instance includes the configuration data of an encrypted DNS resolver.
+/// It is used to build OPTION_V4_DNR (code 162). There may be multiple DNR Instances
+/// in one OPTION_V4_DNR %Option. OPTION_V6_DNR (code 144) is using very similar structure,
+/// only that there must be only one DNR Instance per one OPTION_V6_DNR %Option. That's why
+/// @c Option6Dnr class can derive from this @c DnrInstance class, whereas @c Option4Dnr class
+/// should have a container of @c DnrInstance's.
+///
+/// DNR Instance Data Format has been defined in the @c draft-ietf-add-dnr (to be replaced
+/// with published RFC).
+class DnrInstance {
+public:
+ /// @brief A Type defined for container holding IP addresses.
+ typedef std::vector<isc::asiolink::IOAddress> AddressContainer;
+
+ /// @brief Size in octets of Service Priority field.
+ static const uint8_t SERVICE_PRIORITY_SIZE = 2;
+
+ /// @brief Set of forbidden SvcParams.
+ ///
+ /// The service parameters MUST NOT include
+ /// "ipv4hint" or "ipv6hint" SvcParams as they are superseded by the
+ /// included IP addresses.
+ static const std::unordered_set<std::string> FORBIDDEN_SVC_PARAMS;
+
+ /// @brief Constructor of the empty DNR Instance.
+ ///
+ /// @param universe either V4 or V6 Option universe
+ explicit DnrInstance(Option::Universe universe);
+
+ /// @brief Constructor of the DNR Instance with all fields from params.
+ ///
+ /// Constructor of the DNR Instance where all fields
+ /// i.e. Service priority, ADN, IP address(es) and Service params
+ /// are provided as ctor parameters.
+ ///
+ /// @param universe either V4 or V6 Option universe
+ /// @param service_priority Service priority
+ /// @param adn ADN FQDN
+ /// @param ip_addresses Container of IP addresses
+ /// @param svc_params Service Parameters
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
+ /// @throw InvalidOptionDnrSvcParams Thrown when @c checkSvcParams(from_wire_data) throws
+ /// @throw OutOfRange Thrown in case of no IP addresses found or when IP addresses length
+ /// is too big
+ DnrInstance(Option::Universe universe,
+ uint16_t service_priority,
+ const std::string& adn,
+ const AddressContainer& ip_addresses,
+ const std::string& svc_params);
+
+ /// @brief Constructor of the DNR Instance in ADN only mode.
+ ///
+ /// Constructor of the DNR Instance in ADN only mode
+ /// i.e. only Service priority and ADN FQDN
+ /// are provided as ctor parameters.
+ ///
+ /// @param universe either V4 or V6 Option universe
+ /// @param service_priority Service priority
+ /// @param adn ADN FQDN
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
+ DnrInstance(Option::Universe universe, uint16_t service_priority, const std::string& adn);
+
+ /// @brief Default destructor.
+ virtual ~DnrInstance() = default;
+
+ /// @brief Getter of the @c dnr_instance_data_length_.
+ ///
+ /// @return Length of all following data inside this DNR instance in octets.
+ uint16_t getDnrInstanceDataLength() const {
+ return (dnr_instance_data_length_);
+ }
+
+ /// @brief Getter of the @c service_priority_.
+ ///
+ /// @return The priority of this DNR instance compared to other instances.
+ uint16_t getServicePriority() const {
+ return (service_priority_);
+ }
+
+ /// @brief Getter of the @c adn_length_.
+ ///
+ /// @return Length of the authentication-domain-name data in octets.
+ uint16_t getAdnLength() const {
+ return (adn_length_);
+ }
+
+ /// @brief Returns the Authentication domain name in the text format.
+ ///
+ /// FQDN data stored in @c adn_ is converted into text format and returned.
+ ///
+ /// @return Authentication domain name in the text format.
+ std::string getAdnAsText() const;
+
+ /// @brief Returns string representation of the DNR instance.
+ ///
+ /// @return String with text representation.
+ std::string getDnrInstanceAsText() const;
+
+ /// @brief Getter of the @c addr_length_.
+ ///
+ /// @return Length of enclosed IP addresses in octets.
+ uint16_t getAddrLength() const {
+ return (addr_length_);
+ }
+
+ /// @brief Getter of the @c svc_params_length_.
+ ///
+ /// @return Length of Service Parameters field in octets.
+ uint16_t getSvcParamsLength() const {
+ return (svc_params_length_);
+ }
+
+ /// @brief Returns vector with addresses.
+ ///
+ /// We return a copy of our list. Although this includes overhead,
+ /// it also makes this list safe to use after this option object
+ /// is no longer available. As options are expected to hold only
+ /// a few (1-3) addresses, the overhead is not that big.
+ ///
+ /// @return Address container with addresses.
+ AddressContainer getAddresses() const {
+ return (ip_addresses_);
+ }
+
+ /// @brief Getter of the @c svc_params_ field.
+ ///
+ /// @return Returns Service Parameters as a string.
+ const std::string& getSvcParams() const {
+ return (svc_params_);
+ }
+
+ /// @brief Returns minimal length of the DNR instance data (without headers) in octets.
+ ///
+ /// @return Minimal length of the DNR instance data (without headers) in octets.
+ uint8_t getMinimalLength() const {
+ return (minimal_length_);
+ }
+
+ /// @brief Returns size in octets of Addr Length field.
+ uint8_t getAddrLengthSize() const {
+ return (addr_length_size_);
+ }
+
+ /// @brief Returns size in octets of DNR Instance Data Length field.
+ uint8_t getDnrInstanceDataLengthSize() const {
+ return (dnr_instance_data_length_size_);
+ }
+
+ /// @brief Returns size in octets of ADN Length field.
+ uint8_t getAdnLengthSize() const {
+ return (adn_length_size_);
+ }
+
+ /// @brief Returns Log prefix depending on V4/V6 Option universe.
+ ///
+ /// @return Log prefix as a string which can be used for prints when throwing an exception.
+ std::string getLogPrefix() const {
+ return (log_prefix_);
+ }
+
+ /// @brief Returns whether ADN only mode is enabled or disabled.
+ bool isAdnOnlyMode() const {
+ return (adn_only_mode_);
+ }
+
+ /// @brief Sets Authentication domain name from given string.
+ ///
+ /// Sets FQDN of the encrypted DNS resolver from given string.
+ /// It may throw an exception if parsing of the FQDN fails or if
+ /// provided FQDN length is bigger than uint16_t Max.
+ /// It also calculates and sets value of Addr length field.
+ ///
+ /// @param adn string representation of ADN FQDN
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
+ /// from given string.
+ void setAdn(const std::string& adn);
+
+ /// @brief Setter of the @c adn_only_mode_ field.
+ ///
+ /// @param adn_only_mode enabled/disabled setting
+ void setAdnOnlyMode(bool adn_only_mode) {
+ adn_only_mode_ = adn_only_mode;
+ }
+
+ /// @brief Writes the ADN FQDN in the wire format into a buffer.
+ ///
+ /// The Authentication Domain Name - fully qualified domain name of the encrypted
+ /// DNS resolver data is appended at the end of the buffer.
+ ///
+ /// @param [out] buf buffer where ADN FQDN will be written.
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown when mandatory field ADN is empty.
+ void packAdn(isc::util::OutputBuffer& buf) const;
+
+ /// @brief Writes the IP address(es) in the wire format into a buffer.
+ ///
+ /// The IP address(es) (@c ip_addresses_) data is appended at the end
+ /// of the buffer.
+ ///
+ /// @param [out] buf buffer where IP address(es) will be written.
+ virtual void packAddresses(isc::util::OutputBuffer& buf) const;
+
+ /// @brief Writes the Service Parameters in the wire format into a buffer.
+ ///
+ /// The Service Parameters (@c svc_params_) data is appended at the end
+ /// of the buffer.
+ ///
+ /// @param [out] buf buffer where SvcParams will be written.
+ void packSvcParams(isc::util::OutputBuffer& buf) const;
+
+ /// @brief Unpacks DNR Instance Data Length from wire data buffer and stores
+ /// it in @c dnr_instance_data_length_.
+ ///
+ /// It may throw in case of malformed data detected during parsing.
+ ///
+ /// @param begin beginning of the buffer from which the field will be read
+ /// @param end end of the buffer from which the field will be read
+ ///
+ /// @throw OutOfRange Thrown in case of truncated data detected.
+ void unpackDnrInstanceDataLength(OptionBufferConstIter& begin, OptionBufferConstIter end);
+
+ /// @brief Unpacks Service Priority from wire data buffer and stores it in @c service_priority_.
+ ///
+ /// @param begin beginning of the buffer from which the field will be read
+ void unpackServicePriority(OptionBufferConstIter& begin);
+
+ /// @brief Unpacks the ADN from given wire data buffer and stores it in @c adn_ field.
+ ///
+ /// It may throw in case of malformed data detected during parsing.
+ ///
+ /// @param begin beginning of the buffer from which the ADN will be read
+ /// @param end end of the buffer from which the ADN will be read
+ ///
+ /// @throw BadValue Thrown in case of any issue with unpacking opaque data of the ADN.
+ /// @throw InvalidOptionDnrDomainName Thrown in case of any issue with parsing ADN
+ /// from given wire data.
+ void unpackAdn(OptionBufferConstIter& begin, OptionBufferConstIter end);
+
+ /// @brief Unpacks IP address(es) from wire data and stores it/them in @c ip_addresses_.
+ ///
+ /// It may throw in case of malformed data detected during parsing.
+ ///
+ /// @param begin beginning of the buffer from which the field will be read
+ /// @param end end of the buffer from which the field will be read
+ ///
+ /// @throw BadValue Thrown in case of any issue with unpacking opaque data of the IP addresses.
+ /// @throw OutOfRange Thrown in case of malformed data detected during parsing e.g.
+ /// Addr Len not divisible by 4, Addr Len is 0.
+ virtual void unpackAddresses(OptionBufferConstIter& begin, OptionBufferConstIter end);
+
+ /// @brief Unpacks Service Parameters from wire data buffer and stores it in @c svc_params_.
+ ///
+ /// It may throw in case of malformed data detected during parsing.
+ ///
+ /// @param begin beginning of the buffer from which the field will be read
+ /// @param end end of the buffer from which the field will be read
+ void unpackSvcParams(OptionBufferConstIter& begin, OptionBufferConstIter end);
+
+ /// @brief Checks SvcParams field if encoded correctly and throws in case of issue found.
+ ///
+ /// The field should be encoded following the rules in
+ /// Section 2.1 of [I-D.ietf-dnsop-svcb-https]. SvcParams are
+ /// a whitespace-separated list, with each SvcParam consisting of
+ /// a SvcParamKey=SvcParamValue pair or a standalone SvcParamKey.
+ ///
+ /// @note It is user's responsibility to provide correct configuration
+ /// of @c SvcParams as described in Section 2.1 of [I-D.ietf-dnsop-svcb-https].
+ /// Currently, SvcParamValue is not verified. Proper syntax of SvcParamValue
+ /// is described in Appendix A of [I-D.ietf-dnsop-svcb-https].
+ ///
+ /// @param from_wire_data used to determine whether SvcParams data comes
+ /// from unpacked wire data or from ctor param
+ ///
+ /// @throw InvalidOptionDnrSvcParams Thrown in case of any issue found when checking
+ /// @c ServiceParams field syntax
+ void checkSvcParams(bool from_wire_data = true);
+
+ /// @brief Checks IP address(es) field if data is correct and throws in case of issue found.
+ ///
+ /// Fields lengths are also calculated and saved to member variables.
+ ///
+ /// @throw OutOfRange Thrown in case of no IP addresses found or when IP addresses length
+ /// is too big
+ /// @throw InvalidOptionDnrSvcParams Thrown when @c checkSvcParams(from_wire_data) throws
+ void checkFields();
+
+ /// @brief Adds IP address to @c ip_addresses_ container.
+ ///
+ /// @param ip_address IP address to be added
+ void addIpAddress(const asiolink::IOAddress& ip_address);
+
+protected:
+ /// @brief Either V4 or V6 Option universe.
+ Option::Universe universe_;
+
+ /// @brief Authentication domain name field of variable length.
+ ///
+ /// Authentication domain name field of variable length holding
+ /// a fully qualified domain name of the encrypted DNS resolver.
+ /// This field is formatted as specified in Section 10 of RFC8415.
+ boost::shared_ptr<isc::dns::Name> adn_;
+
+ /// @brief Length of all following data inside this DNR instance in octets.
+ ///
+ /// This field is only used for DHCPv4 Encrypted DNS %Option.
+ uint16_t dnr_instance_data_length_;
+
+ /// @brief The priority of this instance compared to other DNR instances.
+ uint16_t service_priority_;
+
+ /// @brief Length of the authentication-domain-name data in octets.
+ uint16_t adn_length_;
+
+ /// @brief Length of included IP addresses in octets.
+ uint16_t addr_length_;
+
+ /// @brief Vector container holding one or more IP addresses.
+ ///
+ /// One or more IP addresses to reach the encrypted DNS resolver.
+ /// In case of DHCPv4, both private and public IPv4 addresses can
+ /// be included in this field.
+ /// In case of DHCPv6, an address can be link-local, ULA, or GUA.
+ AddressContainer ip_addresses_;
+
+ /// @brief Length of Service Parameters field in octets.
+ uint16_t svc_params_length_;
+
+ /// @brief Flag stating whether ADN only mode is used or not.
+ ///
+ /// "Addr Length", "IP(v4/v6) Address(es)", and "Service Parameters (SvcParams)"
+ /// fields are not present if the ADN-only mode is used.
+ bool adn_only_mode_;
+
+ /// @brief Service Parameters (SvcParams) (variable length).
+ ///
+ /// Specifies a set of service parameters that are encoded
+ /// following the rules in Section 2.1 of [I-D.ietf-dnsop-svcb-https].
+ std::string svc_params_;
+
+ /// @brief Calculates and returns length of DNR Instance data in octets.
+ /// @return length of DNR Instance data in octets.
+ uint16_t dnrInstanceLen() const;
+
+private:
+ /// @brief Size in octets of DNR Instance Data Length field.
+ ///
+ /// @note This field is used only in case of V4 DNR option.
+ uint8_t dnr_instance_data_length_size_;
+
+ /// @brief Size in octets of ADN Length field.
+ uint8_t adn_length_size_;
+
+ /// @brief Size in octets of Addr Length field.
+ uint8_t addr_length_size_;
+
+ /// @brief Minimal length of the DNR instance data (without headers) in octets.
+ ///
+ /// @note If the ADN-only mode is used, then "Addr Length", "ip(v4/v6)-address(es)",
+ /// and "Service Parameters (SvcParams)" fields are not present.
+ /// So minimal length of data is calculated by adding 2 octets for Service Priority,
+ /// octets needed for ADN Length and octets needed for DNR Instance Data Length
+ /// (only in case of DHCPv4).
+ uint8_t minimal_length_;
+
+ /// @brief Log prefix as a string which can be used for prints when throwing an exception.
+ std::string log_prefix_;
+
+ /// @brief Initializes private member variables basing on option's V4/V6 Universe.
+ ///
+ /// @note It must be called in all types of constructors of class @c DnrInstance .
+ void initMembers();
+};
+
+/// @brief Represents DHCPv4 Encrypted DNS %Option (code 162).
+///
+/// This option has been defined in the @c draft-ietf-add-dnr (to be replaced
+/// with published RFC) and it has a following structure:
+/// - option-code = 162 (1 octet)
+/// - option-len (1 octet)
+/// - multiple (one or more) DNR Instance Data
+///
+/// DNR Instance Data structure:
+/// - DNR Instance Data Length (2 octets)
+/// - Service Priority (2 octets)
+/// - ADN Length (1 octet)
+/// - Authentication Domain Name (variable length)
+/// - Addr Length (1 octet)
+/// - IPv4 Address(es) (variable length)
+/// - Service Parameters (variable length).
+class Option4Dnr : public Option {
+public:
+ /// @brief A Type defined for container holding DNR Instances.
+ typedef std::vector<DnrInstance> DnrInstanceContainer;
+
+ /// @brief Constructor of the %Option from on-wire data.
+ ///
+ /// This constructor creates an instance of the option using a buffer with
+ /// on-wire data. It may throw an exception if the @c unpack method throws.
+ ///
+ /// @param begin Iterator pointing to the beginning of the buffer holding an
+ /// option.
+ /// @param end Iterator pointing to the end of the buffer holding an option.
+ ///
+ /// @throw OutOfRange Thrown in case of truncated data. May be also thrown when
+ /// @c DnrInstance::unpackDnrInstanceDataLength(begin,end) throws.
+ /// @throw BadValue Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
+ /// @throw InvalidOptionDnrDomainName Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
+ Option4Dnr(OptionBufferConstIter begin, OptionBufferConstIter end);
+
+ /// @brief Constructor of the empty %Option.
+ ///
+ /// No DNR instances are included in the %Option when using this ctor.
+ /// They must be added afterwards.
+ /// No fields data included in the %Option when using this ctor.
+ /// They must be added afterwards.
+ Option4Dnr() : Option(V4, DHO_V4_DNR) {}
+
+ /// @brief Adds given DNR instance to Option's DNR Instance container.
+ /// @param dnr_instance DNR instance to be added
+ void addDnrInstance(DnrInstance& dnr_instance);
+
+ /// @brief Getter of the @c dnr_instances_ field.
+ /// @return Reference to Option's DNR Instance container
+ const DnrInstanceContainer& getDnrInstances() const {
+ return (dnr_instances_);
+ }
+
+ /// @brief Copies this option and returns a pointer to the copy.
+ ///
+ /// @return Pointer to the copy of the option.
+ OptionPtr clone() const override;
+
+ /// @brief Writes option in wire-format to a buffer.
+ ///
+ /// Writes option in wire-format to buffer, returns pointer to first unused
+ /// byte after stored option (that is useful for writing options one after
+ /// another).
+ ///
+ /// @param buf pointer to a buffer
+ /// @param check flag which indicates if checking the option length is
+ /// required (used only in V4)
+ ///
+ /// @throw InvalidOptionDnrDomainName Thrown when Option's mandatory field ADN is empty.
+ /// @throw OutOfRange Thrown when @c check param set to @c true and
+ /// @c Option::packHeader(buf,check) throws.
+ void pack(util::OutputBuffer& buf, bool check = true) const override;
+
+ /// @brief Parses received wire data buffer.
+ ///
+ /// @param begin iterator to first byte of option data
+ /// @param end iterator to end of option data (first byte after option end)
+ ///
+ /// @throw OutOfRange Thrown in case of truncated data. May be also thrown when
+ /// @c DnrInstance::unpackDnrInstanceDataLength(begin,end) throws.
+ /// @throw BadValue Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
+ /// @throw InvalidOptionDnrDomainName Thrown when @c DnrInstance::unpackAdn(begin,end) throws.
+ void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) override;
+
+ /// @brief Returns string representation of the option.
+ ///
+ /// @param indent number of spaces before printing text
+ ///
+ /// @return string with text representation.
+ std::string toText(int indent = 0) const override;
+
+ /// @brief Returns length of the complete option (data length + DHCPv4/DHCPv6
+ /// option header)
+ ///
+ /// @return length of the option
+ uint16_t len() const override;
+
+protected:
+ /// @brief Container holding DNR Instances.
+ DnrInstanceContainer dnr_instances_;
+};
+
+/// A pointer to the @c OptionDnr4 object.
+typedef boost::shared_ptr<Option4Dnr> Option4DnrPtr;
+
+} // namespace dhcp
+} // namespace isc
+
+#endif // OPTION4_DNR_H