#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
+#include <dhcp/opaque_data_tuple.h>
#include <dhcp/option_dnr.h>
namespace isc {
namespace dhcp {
-OptionDNR6::OptionDNR6() : Option(V6, D6O_V6_DNR) {
-}
-
OptionDNR6::OptionDNR6(OptionBufferConstIter begin, OptionBufferConstIter end)
: Option(V6, D6O_V6_DNR) {
unpack(begin, end);
void
OptionDNR6::pack(util::OutputBuffer& buf, bool check) const {
- Option::pack(buf, check);
+ packHeader(buf, check);
+
+ buf.writeUint16(service_priority_);
+ // TBD
}
void
OptionDNR6::unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
- Option::unpack(begin, end);
+ if (std::distance(begin, end) < getMinimalLength()) {
+ isc_throw(OutOfRange, "parsed DHCPv6 Encrypted DNS Option ("
+ << D6O_V6_DNR << ") data truncated to"
+ " size " << std::distance(begin, end));
+ }
+ setData(begin, end);
+ // First two octets of Option data is Service Priority - this is mandatory field.
+ service_priority_ = isc::util::readUint16((&*begin), SERVICE_PRIORITY_SIZE);
+ begin += sizeof(service_priority_);
+
+ // Next comes two octets of ADN Length plus the ADN data itself (variable length).
+ // This is Opaque Data Tuple so let's use this class to retrieve the ADN data.
+ OpaqueDataTuple adn_tuple(OpaqueDataTuple::LENGTH_2_BYTES, begin, end);
+ adn_length_ = adn_tuple.getLength();
+ if (adn_length_ > 0) {
+ // Let's try to extract ADN FQDN data
+ isc::util::InputBuffer name_buf(&adn_tuple.getData(),
+ adn_length_);
+ try {
+ adn_.reset(new isc::dns::Name(name_buf, true));
+ } catch (const Exception&) {
+ isc_throw(InvalidOptionDNR6DomainName, "failed to parse "
+ "fully qualified domain-name from wire format");
+ }
+ }
+ begin += adn_tuple.getTotalLength();
+
+ if (begin == end) {
+ // ADN only mode, other fields are not included
+ return;
+ }
+ if (std::distance(begin, end) < ADDR_LENGTH_SIZE) {
+ isc_throw(OutOfRange, "truncated DHCPv6 Encrypted DNS Option (" << D6O_V6_DNR << ") - after"
+ " ADN field, there should be at least 2 bytes long Addr Length field");
+ }
+ addr_length_ = isc::util::readUint16((&*begin), ADDR_LENGTH_SIZE);
+ // TBD
}
std::string
#define OPTION_DNR_H
#include <dhcp/option.h>
+#include <dns/name.h>
namespace isc {
namespace dhcp {
+/// @brief Exception thrown when invalid domain name is specified.
+class InvalidOptionDNR6DomainName : public Exception {
+public:
+ InvalidOptionDNR6DomainName(const char* file, size_t line,
+ const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
class OptionDNR6 : public Option {
public:
- OptionDNR6();
+
+ /// @brief Size in octets of Service Priority field
+ static const uint8_t SERVICE_PRIORITY_SIZE = 2;
+
+ /// @brief Size in octets of ADN Length field
+ static const uint8_t ADN_LENGTH_SIZE = 2;
+
+ /// @brief Size in octets of Addr Length field
+ static const uint8_t ADDR_LENGTH_SIZE = 2;
+
+ OptionDNR6() : Option(V6, D6O_V6_DNR) {
+ };
OptionDNR6(OptionBufferConstIter begin, OptionBufferConstIter end);
virtual OptionPtr clone() const;
virtual void pack(util::OutputBuffer& buf, bool check) const;
virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end);
virtual std::string toText(int indent) const;
virtual uint16_t len() const;
+
+private:
+ /// @brief The priority of this OPTION_V6_DNR instance compared to other instances.
+ uint16_t service_priority_;
+
+ /// @brief Length of the authentication-domain-name field in octets.
+ uint16_t adn_length_;
+
+ /// @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 enclosed IPv6 addresses in octets.
+ uint16_t addr_length_;
+
+ /// @brief Returns minimal length of the option data (without headers) in octets.
+ ///
+ /// If the ADN-only mode is used, then "Addr Length", "ipv6-address(es)",
+ /// and "Service Parameters (SvcParams)" fields are not present. In this
+ /// case minimal length of data is 2 octets for Service Priority plus 2 octets
+ /// for ADN Length.
+ ///
+ /// @return Minimal length of the option data (without headers) in octets.
+ static uint8_t getMinimalLength() {
+ return SERVICE_PRIORITY_SIZE + ADN_LENGTH_SIZE;
+ };
};
class OptionDNR4 : public Option {