buf.writeUint8(dnr_instance.getAdnLength());
dnr_instance.packAdn(buf);
if (dnr_instance.isAdnOnlyMode()) {
- return;
+ continue;
}
buf.writeUint8(dnr_instance.getAddrLength());
dnr_instance.packAddresses(buf);
setData(begin, end);
size_t offset = 0;
while (offset < std::distance(begin, end)) {
- if (std::distance(begin + offset, end) < getMinimalLength()) {
+ DnrInstance dnr_instance(V4);
+ if (std::distance(begin + offset, end) < dnr_instance.getMinimalLength()) {
isc_throw(OutOfRange, "DHCPv4 Encrypted DNS Option (" << type_ << ") malformed: "
"DNR instance data truncated to size "
<< std::distance(begin + offset, end));
}
- DnrInstance dnr_instance(V4);
dnr_instance.setDnrInstanceDataLength(
- readUint16(&(*(begin + offset)), DNR_INSTANCE_DATA_LENGTH_SIZE));
+ readUint16(&(*(begin + offset)), dnr_instance.getDnrInstanceDataLengthSize()));
OptionBufferConstIter dnr_instance_end = begin + offset +
dnr_instance.getDnrInstanceDataLength();
- offset += DNR_INSTANCE_DATA_LENGTH_SIZE;
+ offset += dnr_instance.getDnrInstanceDataLengthSize();
dnr_instance.setServicePriority(
- readUint16(&(*(begin + offset)), SERVICE_PRIORITY_SIZE));
- offset += SERVICE_PRIORITY_SIZE;
+ readUint16(&(*(begin + offset)), dnr_instance.SERVICE_PRIORITY_SIZE));
+ offset += dnr_instance.SERVICE_PRIORITY_SIZE;
OpaqueDataTuple adn_tuple(OpaqueDataTuple::LENGTH_1_BYTE, begin + offset, dnr_instance_end);
auto adn_length = adn_tuple.getLength();
<< " is not greater than 0");
}
- offset += ADDR_LENGTH_SIZE;
+ offset += dnr_instance.getAddrLengthSize();
OptionBufferConstIter addr_begin = begin + offset;
OptionBufferConstIter addr_end = addr_begin + addr_length;
auto ip_addresses = dnr_instance.getIpAddresses();
// SvcParams (variable length) field is last.
auto svc_params_length = std::distance(begin + offset, dnr_instance_end);
if (svc_params_length > 0) {
- std::string svc_params = dnr_instance.getSvcParams();
+ std::string svc_params;
svc_params.assign(begin + offset, dnr_instance_end);
+ dnr_instance.setSvcParams(svc_params);
dnr_instance.checkSvcParams();
offset += svc_params_length;
}
std::string
Option4Dnr::toText(int indent) const {
- return Option::toText(indent);
+ std::ostringstream stream;
+ std::string in(indent, ' '); // base indentation
+ stream << in << "type=" << type_ << "(V4_DNR), "
+ << "len=" << (len() - getHeaderLen());
+ int i = 0;
+ for(const DnrInstance& dnr_instance : dnr_instances_) {
+ stream << ", DNR Instance " << ++i << "(Instance len="
+ << dnr_instance.getDnrInstanceDataLength() << ", "
+ << dnr_instance.getDnrInstanceAsText() << ")";
+ }
+ return (stream.str());
}
uint16_t
Option4Dnr::len() const {
uint16_t len = OPTION4_HDR_LEN;
for (const DnrInstance& dnr_instance : dnr_instances_) {
- len += dnr_instance.getDnrInstanceDataLength() + DNR_INSTANCE_DATA_LENGTH_SIZE;
+ len += dnr_instance.getDnrInstanceDataLength() + dnr_instance.getDnrInstanceDataLengthSize();
}
return (len);
}
}
adn_length_ = adn_len;
+ if (universe_ == Option::V4) {
+ setDnrInstanceDataLength(dnrInstanceLen());
+ }
}
void
checkSvcParams(false);
}
adn_only_mode_ = false;
- auto addr_len = ip_addresses_.size() * V6ADDRESS_LEN;
- if (addr_len > std::numeric_limits<uint16_t>::max()) {
+ const uint8_t addr_field_len = (universe_ == Option::V4) ? V4ADDRESS_LEN : V6ADDRESS_LEN;
+ const uint16_t max_addr_len = (universe_ == Option::V4)
+ ? std::numeric_limits<uint8_t>::max()
+ : std::numeric_limits<uint16_t>::max();
+ auto addr_len = ip_addresses_.size() * addr_field_len;
+ if (addr_len > max_addr_len) {
isc_throw(OutOfRange,
- "Given IPv6 addresses length " << addr_len << " is bigger than uint_16 MAX");
+ "Given IP addresses length " << addr_len << " is bigger than MAX " << max_addr_len);
}
addr_length_ = addr_len;
+ if (universe_ == Option::V4) {
+ setDnrInstanceDataLength(dnrInstanceLen());
+ }
}
std::string
("DHCPv6 Encrypted DNS Option (" + std::to_string(D6O_V6_DNR) + ")");
}
+DnrInstance::DnrInstance(Option::Universe universe,
+ const uint16_t service_priority,
+ const std::string& adn,
+ const DnrInstance::AddressContainer& ip_addresses,
+ const std::string& svc_params)
+ : universe_(universe), service_priority_(service_priority),
+ ip_addresses_(ip_addresses), svc_params_(svc_params) {
+ setAdn(adn);
+ checkFields();
+}
+
+DnrInstance::DnrInstance(Option::Universe universe,
+ const uint16_t service_priority,
+ const std::string& adn)
+ : universe_(universe), service_priority_(service_priority){
+ setAdn(adn);
+}
+
+std::string
+DnrInstance::getDnrInstanceAsText() const {
+ std::string text = "service_priority=" + std::to_string(service_priority_) + ", "
+ + "adn_length=" + std::to_string(adn_length_) + ", "
+ + "adn='" + getAdnAsText() + "'";
+ if (!adn_only_mode_) {
+ text += ", addr_length=" + std::to_string(addr_length_) + ", address(es):";
+ for (const auto& address : ip_addresses_) {
+ text += " " + address.toText();
+ }
+ if (svc_params_length_ > 0) {
+ text += ", svc_params='" + svc_params_ + "'";
+ }
+ }
+ return text;
+}
+
+uint16_t
+DnrInstance::dnrInstanceLen() const {
+ uint16_t len = SERVICE_PRIORITY_SIZE + adn_length_ + getAdnLengthSize();
+ if (!adn_only_mode_) {
+ len += addr_length_ + getAddrLengthSize() + svc_params_length_;
+ }
+ return (len);
+}
+
+uint8_t
+DnrInstance::getDnrInstanceDataLengthSize() const {
+ if (universe_ == Option::V6) {
+ return (0);
+ }
+ return (2);
+}
+
+uint8_t
+DnrInstance::getAdnLengthSize() const {
+ if (universe_ == Option::V6) {
+ return (2);
+ }
+ return (1);
+}
+
+uint8_t
+DnrInstance::getAddrLengthSize() const {
+ if (universe_ == Option::V6) {
+ return (2);
+ }
+ return (1);
+}
+
+uint8_t
+DnrInstance::getMinimalLength() const {
+ return (getDnrInstanceDataLengthSize() + SERVICE_PRIORITY_SIZE + getAdnLengthSize());
+}
+
} // namespace dhcp
} // namespace isc
#define OPTION4_DNR_H
#include <asiolink/io_address.h>
+#include <dhcp/dhcp4.h>
#include <dhcp/option.h>
#include <dns/name.h>
class DnrInstance {
public:
- DnrInstance(Option::Universe universe) : universe_(universe) {}
-
- virtual ~DnrInstance() {}
-
/// @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;
+
+ explicit DnrInstance(Option::Universe universe) : universe_(universe) {}
+
+ DnrInstance(Option::Universe universe, const uint16_t service_priority,
+ const std::string& adn,
+ const AddressContainer& ip_addresses,
+ const std::string& svc_params);
+
+ DnrInstance(Option::Universe universe, const uint16_t service_priority,
+ const std::string& adn);
+
+ virtual ~DnrInstance() = default;
+
const AddressContainer& getIpAddresses() const {
return ip_addresses_;
}
/// @return Authentication domain name in the text format.
std::string getAdnAsText() const;
+ std::string getDnrInstanceAsText() const;
+
/// @brief Getter of the @c addr_length_.
///
/// @return Length of enclosed IP addresses in octets.
return svc_params_;
}
+ /// @brief Returns minimal length of the DNR instance data (without headers) in octets.
+ ///
+ /// 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).
+ ///
+ /// @return Minimal length of the DNR instance data (without headers) in octets.
+ uint8_t getMinimalLength() const;
+
+ /// @brief Returns size in octets of Addr Length field.
+ uint8_t getAddrLengthSize() const;
+
+ /// @brief Returns size in octets of DNR Instance Data Length field.
+ uint8_t getDnrInstanceDataLengthSize() const;
+
bool isAdnOnlyMode() const {
return adn_only_mode_;
}
void setAddrLength(uint16_t addr_length) {
addr_length_ = addr_length;
}
- void setSvcParamsLength(uint16_t svc_params_length) {
- svc_params_length_ = svc_params_length;
- }
+// void setSvcParamsLength(uint16_t svc_params_length) {
+// svc_params_length_ = svc_params_length;
+// }
void setAdnOnlyMode(bool adn_only_mode) {
adn_only_mode_ = adn_only_mode;
}
/// following the rules in Section 2.1 of [I-D.ietf-dnsop-svcb-https].
std::string svc_params_;
+ uint16_t dnrInstanceLen() const;
+
private:
std::string getLogPrefix() const;
+
+ /// @brief Returns size in octets of ADN Length field.
+ uint8_t getAdnLengthSize() const;
};
class Option4Dnr : public Option {
public:
- /// @brief Size in octets of Service Priority field.
- static const uint8_t DNR_INSTANCE_DATA_LENGTH_SIZE = 2;
-
- /// @brief Size in octets of Service Priority field.
- static const uint8_t SERVICE_PRIORITY_SIZE = 2;
+ typedef std::vector<DnrInstance> DnrInstanceContainer;
- /// @brief Size in octets of ADN Length field.
- static const uint8_t ADN_LENGTH_SIZE = 1;
+ Option4Dnr(OptionBufferConstIter begin, OptionBufferConstIter end);
- /// @brief Size in octets of Addr Length field.
- static const uint8_t ADDR_LENGTH_SIZE = 1;
+ Option4Dnr() : Option(V4, DHO_V4_DNR) {}
- typedef std::vector<DnrInstance> DnrInstanceContainer;
+ void addDnrInstance(DnrInstance& dnr_instance);
- Option4Dnr(OptionBufferConstIter begin, OptionBufferConstIter end);
+ const DnrInstanceContainer& getDnrInstances() const {
+ return dnr_instances_;
+ }
virtual OptionPtr clone() const;
virtual void pack(util::OutputBuffer& buf, bool check = true) const;
protected:
DnrInstanceContainer dnr_instances_;
-
-private:
- /// @brief Returns minimal length of the option data (without headers) in octets.
- ///
- /// If the ADN-only mode is used, then "Addr Length", "IPv4 Address(es)",
- /// and "Service Parameters (SvcParams)" fields are not present. In this
- /// case minimal length of data is 2 octets for Service Priority plus 1 octet
- /// for ADN Length plus 2 octets for DNR Instance Data Length.
- ///
- /// @return Minimal length of the option data (without headers) in octets.
- static uint8_t getMinimalLength() {
- return (DNR_INSTANCE_DATA_LENGTH_SIZE + SERVICE_PRIORITY_SIZE + ADN_LENGTH_SIZE);
- };
-
- void addDnrInstance(DnrInstance& dnr_instance);
};
/// A pointer to the @c OptionDnr4 object.
#include <config.h>
-#include <asiolink/io_address.h>
-#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/opaque_data_tuple.h>
#include <dhcp/option6_dnr.h>
unpack(begin, end);
}
-Option6Dnr::Option6Dnr(const uint16_t service_priority,
- const std::string& adn,
- const Option6Dnr::AddressContainer& ip_addresses,
- const std::string& svc_params)
- : Option(V6, D6O_V6_DNR), DnrInstance(V6) {
- service_priority_ = service_priority;
- ip_addresses_ = ip_addresses;
- svc_params_ = svc_params;
- setAdn(adn);
- checkFields();
-}
-
-Option6Dnr::Option6Dnr(const uint16_t service_priority, const std::string& adn)
- : Option(V6, D6O_V6_DNR), DnrInstance(V6) {
- service_priority_ = service_priority;
- setAdn(adn);
-}
-
OptionPtr
Option6Dnr::clone() const {
return (cloneInternal<Option6Dnr>());
return;
}
adn_only_mode_ = false;
- if (std::distance(begin, end) < ADDR_LENGTH_SIZE) {
+ if (std::distance(begin, end) < getAddrLengthSize()) {
isc_throw(OutOfRange, "DHCPv6 Encrypted DNS Option (" << type_ << ") malformed: after"
" ADN field, there should be at least "
"2 bytes long Addr Length field");
}
// Next come two octets of Addr Length.
- addr_length_ = isc::util::readUint16(&(*begin), ADDR_LENGTH_SIZE);
- begin += ADDR_LENGTH_SIZE;
+ addr_length_ = isc::util::readUint16(&(*begin), getAddrLengthSize());
+ begin += getAddrLengthSize();
// It MUST be a multiple of 16.
if ((addr_length_ % V6ADDRESS_LEN) != 0) {
isc_throw(OutOfRange, "DHCPv6 Encrypted DNS Option (" << type_ << ")"
std::ostringstream stream;
std::string in(indent, ' '); // base indentation
stream << in << "type=" << type_ << "(V6_DNR), "
- << "len=" << (len() - getHeaderLen()) << ", "
- << "service_priority=" << service_priority_ << ", "
- << "adn_length=" << adn_length_ << ", "
- << "adn='" << getAdnAsText() << "'";
- if (!adn_only_mode_) {
- stream << ", addr_length=" << addr_length_
- << ", address(es):";
- for (const auto& address : ip_addresses_) {
- stream << " " << address.toText();
- }
-
- if (svc_params_length_ > 0) {
- stream << ", svc_params='" << svc_params_ << "'";
- }
- }
-
+ << "len=" << (len() - getHeaderLen()) << ", " << getDnrInstanceAsText();
return (stream.str());
}
uint16_t
Option6Dnr::len() const {
- uint16_t len = OPTION6_HDR_LEN + SERVICE_PRIORITY_SIZE + adn_length_ + ADN_LENGTH_SIZE;
- if (!adn_only_mode_) {
- len += addr_length_ + ADDR_LENGTH_SIZE + svc_params_length_;
- }
- return (len);
+ return (OPTION6_HDR_LEN + dnrInstanceLen());
}
} // namespace dhcp
class Option6Dnr : public Option, public DnrInstance {
public:
- /// @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;
-
/// @brief Constructor of the %Option from on-wire data.
///
/// This constructor creates an instance of the option using a buffer with
/// @param end Iterator pointing to the end of the buffer holding an option.
Option6Dnr(OptionBufferConstIter begin, OptionBufferConstIter end);
- Option6Dnr(const uint16_t service_priority, const std::string& adn, const AddressContainer& ip_addresses, const std::string& svc_params);
+ Option6Dnr(const uint16_t service_priority,
+ const std::string& adn,
+ const Option6Dnr::AddressContainer& ip_addresses,
+ const std::string& svc_params)
+ : Option(V6, D6O_V6_DNR),
+ DnrInstance(V6, service_priority, adn, ip_addresses, svc_params) {}
- Option6Dnr(const uint16_t service_priority, const std::string& adn);
+ Option6Dnr(const uint16_t service_priority, const std::string& adn)
+ : Option(V6, D6O_V6_DNR), DnrInstance(V6, service_priority, adn) {}
virtual OptionPtr clone() const;
virtual void pack(util::OutputBuffer& buf, bool check = false) const;
virtual uint16_t len() const;
virtual void packAddresses(isc::util::OutputBuffer& buf) const;
-
-private:
- /// @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);
- };
};
/// A pointer to the @c Option6Dnr object.
libdhcp___unittests_SOURCES += opaque_data_tuple_unittest.cc
libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option4_client_fqdn_unittest.cc
+libdhcp___unittests_SOURCES += option4_dnr_unittest.cc
libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option6_client_fqdn_unittest.cc
libdhcp___unittests_SOURCES += option6_auth_unittest.cc
+libdhcp___unittests_SOURCES += option6_dnr_unittest.cc
libdhcp___unittests_SOURCES += option6_ia_unittest.cc
libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
libdhcp___unittests_SOURCES += option6_iaprefix_unittest.cc
libdhcp___unittests_SOURCES += option_definition_unittest.cc
libdhcp___unittests_SOURCES += option_copy_unittest.cc
libdhcp___unittests_SOURCES += option_custom_unittest.cc
-libdhcp___unittests_SOURCES += option_dnr_unittest.cc
libdhcp___unittests_SOURCES += option_opaque_data_tuples_unittest.cc
libdhcp___unittests_SOURCES += option_unittest.cc
libdhcp___unittests_SOURCES += option_space_unittest.cc
--- /dev/null
+// Copyright (C) 2015-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/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/opaque_data_tuple.h>
+#include <dhcp/option4_dnr.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <gtest/gtest.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+using boost::scoped_ptr;
+
+namespace {
+
+TEST(Option4DnrTest, emptyCtor) {
+ // Create option instance. Check that constructor doesn't throw.
+ scoped_ptr<Option4Dnr> option;
+ EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ ASSERT_TRUE(option);
+
+ // Check if member variables were correctly set by ctor.
+ EXPECT_EQ(Option::V4, option->getUniverse());
+ EXPECT_EQ(DHO_V4_DNR, option->getType());
+}
+
+TEST(Option4DnrTest, oneDnrOnlyModeInstance) {
+ // Create option instance. Check that constructor doesn't throw.
+ scoped_ptr<Option4Dnr> option;
+ EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ ASSERT_TRUE(option);
+
+ // Prepare example DNR instance to add.
+ DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com.");
+
+ // Add DNR instance.
+ option->addDnrInstance(dnr_1);
+
+ // Check if member variables were correctly set inside DNR instances.
+ EXPECT_EQ(1, option->getDnrInstances().size());
+ EXPECT_EQ(1, option->getDnrInstances()[0].getServicePriority());
+ EXPECT_EQ(21, option->getDnrInstances()[0].getAdnLength());
+ EXPECT_EQ("myhost1.example.com.", option->getDnrInstances()[0].getAdnAsText());
+
+ // This is ADN only mode, so Addr Length and SvcParams Length
+ // are both expected to be zero.
+ EXPECT_EQ(0, option->getDnrInstances()[0].getAddrLength());
+ EXPECT_EQ(0, option->getDnrInstances()[0].getSvcParamsLength());
+
+ // BTW let's check if len() works ok. In ADN only mode, DNR Instance Data Len
+ // is set to ADN Len (21) + 3 = 24.
+ // expected len: 1x(24 (ADN+ADN Len+Service priority) + 2 (DNR Instance Data Len)) + 2 (headers)
+ // = 28
+ EXPECT_EQ(28, option->len());
+
+ // BTW let's check if toText() works ok.
+ // toText() len does not count in headers len.
+ EXPECT_EQ("type=162(V4_DNR), len=26, "
+ "DNR Instance 1(Instance len=24, service_priority=1, "
+ "adn_length=21, adn='myhost1.example.com.')",
+ option->toText());
+}
+
+TEST(Option4DnrTest, multipleDnrOnlyModeInstances) {
+ // Create option instance. Check that constructor doesn't throw.
+ scoped_ptr<Option4Dnr> option;
+ EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ ASSERT_TRUE(option);
+
+ // Check if member variables were correctly set by ctor.
+ EXPECT_EQ(Option::V4, option->getUniverse());
+ EXPECT_EQ(DHO_V4_DNR, option->getType());
+
+ // Prepare example DNR instances to add.
+ DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com.");
+ DnrInstance dnr_2 = DnrInstance(Option::V4, 2, "myhost2.example.com.");
+ DnrInstance dnr_3 = DnrInstance(Option::V4, 3, "myhost3.example.com.");
+
+ // Add DNR instances.
+ option->addDnrInstance(dnr_1);
+ option->addDnrInstance(dnr_2);
+ option->addDnrInstance(dnr_3);
+
+ // Check if member variables were correctly set inside DNR instances.
+ EXPECT_EQ(3, option->getDnrInstances().size());
+ EXPECT_EQ(1, option->getDnrInstances()[0].getServicePriority());
+ EXPECT_EQ(2, option->getDnrInstances()[1].getServicePriority());
+ EXPECT_EQ(3, option->getDnrInstances()[2].getServicePriority());
+ EXPECT_EQ(21, option->getDnrInstances()[0].getAdnLength());
+ EXPECT_EQ(21, option->getDnrInstances()[1].getAdnLength());
+ EXPECT_EQ(21, option->getDnrInstances()[2].getAdnLength());
+ EXPECT_EQ("myhost1.example.com.", option->getDnrInstances()[0].getAdnAsText());
+ EXPECT_EQ("myhost2.example.com.", option->getDnrInstances()[1].getAdnAsText());
+ EXPECT_EQ("myhost3.example.com.", option->getDnrInstances()[2].getAdnAsText());
+
+ // This is ADN only mode, so Addr Length and SvcParams Length
+ // are both expected to be zero.
+ EXPECT_EQ(0, option->getDnrInstances()[0].getAddrLength());
+ EXPECT_EQ(0, option->getDnrInstances()[0].getSvcParamsLength());
+ EXPECT_EQ(0, option->getDnrInstances()[1].getAddrLength());
+ EXPECT_EQ(0, option->getDnrInstances()[1].getSvcParamsLength());
+ EXPECT_EQ(0, option->getDnrInstances()[2].getAddrLength());
+ EXPECT_EQ(0, option->getDnrInstances()[2].getSvcParamsLength());
+
+ // BTW let's check if len() works ok. In ADN only mode, DNR Instance Data Len
+ // is set to ADN Len (21) + 3 = 24.
+ // expected len: 3x(24 (ADN+ADN Len+Service priority) + 2 (DNR Instance Data Len)) + 2 (headers)
+ // = 78 + 2 = 80
+ EXPECT_EQ(80, option->len());
+
+ // BTW let's check if toText() works ok.
+ // toText() len does not count in headers len.
+ EXPECT_EQ("type=162(V4_DNR), len=78, "
+ "DNR Instance 1(Instance len=24, service_priority=1, "
+ "adn_length=21, adn='myhost1.example.com.'), "
+ "DNR Instance 2(Instance len=24, service_priority=2, "
+ "adn_length=21, adn='myhost2.example.com.'), "
+ "DNR Instance 3(Instance len=24, service_priority=3, "
+ "adn_length=21, adn='myhost3.example.com.')",
+ option->toText());
+}
+
+TEST(Option4DnrTest, packOneDnrOnlyModeInstance) {
+ // Create option instance. Check that constructor doesn't throw.
+ scoped_ptr<Option4Dnr> option;
+ EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ ASSERT_TRUE(option);
+
+ // Prepare example DNR instance to add.
+ DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com.");
+
+ // Add DNR instance.
+ option->addDnrInstance(dnr_1);
+
+ // Prepare on-wire format of the option.
+ isc::util::OutputBuffer buf(10);
+ ASSERT_NO_THROW(option->pack(buf));
+
+ // Prepare reference data.
+ const uint8_t ref_data[] = {
+ DHO_V4_DNR, // Option code
+ 26, // Option len=26 dec
+ 0x00, 24, // DNR Instance Data Len
+ 0x00, 0x01, // Service priority is 1 dec
+ 21, // ADN Length is 21 dec
+ 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1.
+ 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example.
+ 0x03, 0x63, 0x6F, 0x6D, 0x00 // com.
+ };
+
+ size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]);
+
+ // Check if the buffer has the same length as the reference data,
+ // so as they can be compared directly.
+ ASSERT_EQ(ref_data_size, buf.getLength());
+ EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
+}
+
+TEST(Option4DnrTest, packMultipleDnrOnlyModeInstances) {
+ // Create option instance. Check that constructor doesn't throw.
+ scoped_ptr<Option4Dnr> option;
+ EXPECT_NO_THROW(option.reset(new Option4Dnr()));
+ ASSERT_TRUE(option);
+
+ // Check if member variables were correctly set by ctor.
+ EXPECT_EQ(Option::V4, option->getUniverse());
+ EXPECT_EQ(DHO_V4_DNR, option->getType());
+
+ // Prepare example DNR instances to add.
+ DnrInstance dnr_1 = DnrInstance(Option::V4, 1, "myhost1.example.com.");
+ DnrInstance dnr_2 = DnrInstance(Option::V4, 2, "myhost2.example.com.");
+ DnrInstance dnr_3 = DnrInstance(Option::V4, 3, "myhost3.example.com.");
+
+ // Add DNR instances.
+ option->addDnrInstance(dnr_1);
+ option->addDnrInstance(dnr_2);
+ option->addDnrInstance(dnr_3);
+
+ // Prepare on-wire format of the option.
+ isc::util::OutputBuffer buf(10);
+ ASSERT_NO_THROW(option->pack(buf));
+
+ // Prepare reference data.
+ const uint8_t ref_data[] = {
+ DHO_V4_DNR, // Option code
+ 78, // Option len=78 dec
+ 0x00, 24, // DNR Instance Data Len
+ 0x00, 0x01, // Service priority is 1 dec
+ 21, // ADN Length is 21 dec
+ 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '1', // FQDN: myhost1.
+ 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example.
+ 0x03, 0x63, 0x6F, 0x6D, 0x00, // com.
+ 0x00, 24, // DNR Instance Data Len
+ 0x00, 0x02, // Service priority is 2 dec
+ 21, // ADN Length is 21 dec
+ 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '2', // FQDN: myhost1.
+ 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example.
+ 0x03, 0x63, 0x6F, 0x6D, 0x00, // com.
+ 0x00, 24, // DNR Instance Data Len
+ 0x00, 0x03, // Service priority is 3 dec
+ 21, // ADN Length is 21 dec
+ 0x07, 0x6D, 0x79, 0x68, 0x6F, 0x73, 0x74, '3', // FQDN: myhost1.
+ 0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, // example.
+ 0x03, 0x63, 0x6F, 0x6D, 0x00 // com.
+ };
+
+ size_t ref_data_size = sizeof(ref_data) / sizeof(ref_data[0]);
+
+ // Check if the buffer has the same length as the reference data,
+ // so as they can be compared directly.
+ ASSERT_EQ(ref_data_size, buf.getLength());
+ EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
+}
+
+} // namespace
\ No newline at end of file
// Provided wire data is in the ADN only mode i.e. only
// Service priority and Authentication domain name FQDN
// fields are present.
-TEST(OptionDnr6Test, onWireCtorAdnOnlyMode) {
+TEST(Option6DnrTest, onWireCtorAdnOnlyMode) {
// Prepare data to decode - ADN only mode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - mandatory fields are truncated.
-TEST(OptionDnr6Test, onWireCtorDataTruncated) {
+TEST(Option6DnrTest, onWireCtorDataTruncated) {
// Prepare data to decode - data too short.
const uint8_t buf_data[] = {
0x80, 0x01 // Service priority is 32769 dec, other data is missing
// Test checks that exception is thrown when trying to unpack malformed wire data
// - ADN FQDN contains only whitespace - non valid FQDN.
-TEST(OptionDnr6Test, onWireCtorOnlyWhitespaceFqdn) {
+TEST(Option6DnrTest, onWireCtorOnlyWhitespaceFqdn) {
// Prepare data to decode - ADN only mode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - ADN Length is 0 and no ADN FQDN at all.
-TEST(OptionDnr6Test, onWireCtorNoAdnFqdn) {
+TEST(Option6DnrTest, onWireCtorNoAdnFqdn) {
// Prepare data to decode - ADN only mode.
const uint8_t buf_data[] = {
0x00, 0x01, // Service priority is 1 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - FQDN data is truncated.
-TEST(OptionDnr6Test, onWireCtorTruncatedFqdn) {
+TEST(Option6DnrTest, onWireCtorTruncatedFqdn) {
// Prepare data to decode - ADN only mode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - Addr Length field truncated.
-TEST(OptionDnr6Test, onWireCtorAddrLenTruncated) {
+TEST(Option6DnrTest, onWireCtorAddrLenTruncated) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - Addr length is 0 and no IPv6 addresses at all.
-TEST(OptionDnr6Test, onWireCtorAddrLenZero) {
+TEST(Option6DnrTest, onWireCtorAddrLenZero) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - Addr length is not a multiple of 16.
-TEST(OptionDnr6Test, onWireCtorAddrLenNot16Modulo) {
+TEST(Option6DnrTest, onWireCtorAddrLenNot16Modulo) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// This test verifies option constructor from wire data.
// Provided wire data contains also IPv6 addresses.
-TEST(OptionDnr6Test, onWireCtorValidIpV6Addresses) {
+TEST(Option6DnrTest, onWireCtorValidIpV6Addresses) {
// Prepare data to decode
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - IPv6 addresses are truncated.
-TEST(OptionDnr6Test, onWireCtorTruncatedIpV6Addresses) {
+TEST(Option6DnrTest, onWireCtorTruncatedIpV6Addresses) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// This test verifies option constructor from wire data.
// Provided wire data contains also IPv6 address and Svc Params.
-TEST(OptionDnr6Test, onWireCtorSvcParamsIncluded) {
+TEST(Option6DnrTest, onWireCtorSvcParamsIncluded) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// Test checks that exception is thrown when trying to unpack malformed wire data
// - SvcParams Key contains char that is not allowed.
-TEST(OptionDnr6Test, onWireCtorSvcParamsInvalidCharKey) {
+TEST(Option6DnrTest, onWireCtorSvcParamsInvalidCharKey) {
// Prepare data to decode with invalid SvcParams.
const uint8_t buf_data[] = {
0x80, 0x01, // Service priority is 32769 dec
// This test verifies option constructor in ADN only mode.
// Service priority and ADN are provided via ctor.
-TEST(OptionDnr6Test, adnOnlyModeCtor) {
+TEST(Option6DnrTest, adnOnlyModeCtor) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that option constructor in ADN only mode throws
// an exception when mandatory ADN is empty.
-TEST(OptionDnr6Test, adnOnlyModeCtorNoFqdn) {
+TEST(Option6DnrTest, adnOnlyModeCtorNoFqdn) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn; // invalid empty ADN
// This test verifies option constructor where all fields
// i.e. Service priority, ADN, IP address(es) and Service params
// are provided as ctor parameters.
-TEST(OptionDnr6Test, allFieldsCtor) {
+TEST(Option6DnrTest, allFieldsCtor) {
// Prepare example parameters
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that option constructor throws
// an exception when option fields provided via ctor are malformed
// - no IPv6 address provided.
-TEST(OptionDnr6Test, allFieldsCtorNoIpAddress) {
+TEST(Option6DnrTest, allFieldsCtorNoIpAddress) {
// Prepare example parameters
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that option constructor throws
// an exception when option fields provided via ctor are malformed
// - Svc Params key=val pair has 2 equal signs.
-TEST(OptionDnr6Test, svcParamsTwoEqualSignsPerParam) {
+TEST(Option6DnrTest, svcParamsTwoEqualSignsPerParam) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that option constructor throws
// an exception when option fields provided via ctor are malformed
// - Svc Params forbidden key provided.
-TEST(OptionDnr6Test, svcParamsForbiddenKey) {
+TEST(Option6DnrTest, svcParamsForbiddenKey) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that option constructor throws
// an exception when option fields provided via ctor are malformed
// - Svc Params key was repeated.
-TEST(OptionDnr6Test, svcParamsKeyRepeated) {
+TEST(Option6DnrTest, svcParamsKeyRepeated) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that option constructor throws
// an exception when option fields provided via ctor are malformed
// - Svc Params key is too long.
-TEST(OptionDnr6Test, svcParamsKeyTooLong) {
+TEST(Option6DnrTest, svcParamsKeyTooLong) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that option constructor throws
// an exception when option fields provided via ctor are malformed
// - Svc Params key has chars that are not allowed.
-TEST(OptionDnr6Test, svcParamsKeyHasInvalidChar) {
+TEST(Option6DnrTest, svcParamsKeyHasInvalidChar) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies that string representation of the option returned by
// toText method is correctly formatted.
-TEST(OptionDnr6Test, toText) {
+TEST(Option6DnrTest, toText) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
}
// This test verifies on-wire format of the option is correctly created in ADN only mode.
-TEST(OptionDnr6Test, packAdnOnlyMode) {
+TEST(Option6DnrTest, packAdnOnlyMode) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";
// This test verifies on-wire format of the option is correctly created when
// IP addresses and Svc Params are also included.
-TEST(OptionDnr6Test, pack) {
+TEST(Option6DnrTest, pack) {
// Prepare example parameters.
const uint16_t service_priority = 9;
const std::string adn = "myhost.example.com.";