]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2536] Implementing DNRv4v6 Option with TDD
authorPiotrek Zadroga <piotrek@isc.org>
Thu, 20 Apr 2023 11:49:56 +0000 (13:49 +0200)
committerPiotrek Zadroga <piotrek@isc.org>
Thu, 4 May 2023 21:17:18 +0000 (23:17 +0200)
src/lib/dhcp/option4_dnr.cc
src/lib/dhcp/option4_dnr.h
src/lib/dhcp/option6_dnr.cc
src/lib/dhcp/option6_dnr.h
src/lib/dhcp/tests/option4_dnr_unittest.cc
src/lib/dhcp/tests/option6_dnr_unittest.cc

index c1c9c0dee86ac5dd8cd417c6ce1bf64c45c3852b..15ec7b50600e715ddcae9b181380a2f3a6707901 100644 (file)
@@ -6,15 +6,10 @@
 
 #include <config.h>
 
-#include <asiolink/io_address.h>
-#include <dhcp/dhcp4.h>
-#include <dhcp/dhcp6.h>
-#include <dhcp/opaque_data_tuple.h>
 #include <dhcp/option4_dnr.h>
-#include <dhcp/option6_dnr.h>
-#include <dhcp/option_data_types.h>
 #include <dns/labelsequence.h>
 #include <util/strutil.h>
+
 #include <set>
 
 using namespace isc::asiolink;
@@ -34,7 +29,7 @@ Option4Dnr::clone() const {
 }
 
 void
-Option4Dnr::pack(util::OutputBuffer& buf, bool check) const {
+Option4Dnr::pack(OutputBuffer& buf, bool check) const {
     packHeader(buf, check);
     for (const DnrInstance& dnr_instance : dnr_instances_) {
         buf.writeUint16(dnr_instance.getDnrInstanceDataLength());
@@ -62,7 +57,7 @@ Option4Dnr::unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
         }
 
         // Unpack DnrInstanceDataLength.
-        dnr_instance.unpackDnrInstanceDataLength(begin);
+        dnr_instance.unpackDnrInstanceDataLength(begin, end);
 
         const OptionBufferConstIter dnr_instance_end = begin +
                                                        dnr_instance.getDnrInstanceDataLength();
@@ -413,9 +408,15 @@ DnrInstance::addIpAddress(const IOAddress& ip_address) {
 }
 
 void
-DnrInstance::unpackDnrInstanceDataLength(OptionBufferConstIter& begin) {
+DnrInstance::unpackDnrInstanceDataLength(OptionBufferConstIter& begin, OptionBufferConstIter end) {
     dnr_instance_data_length_ = readUint16(&*begin, getDnrInstanceDataLengthSize());
     begin += getDnrInstanceDataLengthSize();
+    if (std::distance(begin, end) < dnr_instance_data_length_) {
+        isc_throw(OutOfRange, getLogPrefix()
+                                  << " malformed: DNR instance data truncated to size "
+                                  << std::distance(begin, end) << " but it was supposed to be "
+                                  << dnr_instance_data_length_);
+    }
 }
 
 void
@@ -438,8 +439,9 @@ DnrInstance::unpackAddresses(OptionBufferConstIter& begin, const OptionBufferCon
     // If additional data is supplied (i.e. not ADN only mode),
     // the option includes at least one valid IP address.
     if (addr_length_ == 0) {
-        isc_throw(OutOfRange, getLogPrefix() << " malformed: Addr Len=" << addr_length_
-                                             << " is not greater than 0");
+        isc_throw(OutOfRange, getLogPrefix()
+                                  << " malformed: Addr Len=" << addr_length_
+                                  << " but it must contain at least one valid IP address");
     }
 
     begin += getAddrLengthSize();
index d2bcc2e8794c0697fdb7ebe88ad655e2a8ed3a50..3062f69c232a82aaabf631c9cef4cc81b557733e 100644 (file)
@@ -9,12 +9,30 @@
 
 #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>
 
 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.
 ///
@@ -208,24 +226,37 @@ public:
 
     /// @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
-    void unpackDnrInstanceDataLength(OptionBufferConstIter& begin);
+    /// @param end end of the buffer from which the field will be read
+    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
     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
     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);
index ca48bd761e05096e108b67d4c490658b107fee46..4893fbf3222badf54475df372dbf669401becefa 100644 (file)
@@ -6,8 +6,6 @@
 
 #include <config.h>
 
-#include <dhcp/dhcp6.h>
-#include <dhcp/opaque_data_tuple.h>
 #include <dhcp/option6_dnr.h>
 
 using namespace isc::asiolink;
@@ -111,8 +109,9 @@ Option6Dnr::unpackAddresses(OptionBufferConstIter& begin, OptionBufferConstIter
     // If additional data is supplied (i.e. not ADN only mode),
     // the option includes at least one valid IP address.
     if (addr_length_ == 0) {
-        isc_throw(OutOfRange, getLogPrefix() << " malformed: Addr Len=" << addr_length_
-                                             << " is not greater than 0");
+        isc_throw(OutOfRange, getLogPrefix()
+                                  << " malformed: Addr Len=" << addr_length_
+                                  << " but it must contain at least one valid IP address");
     }
 
     // Check if IPv6 Address(es) field is not truncated.
index 5a55cb36c52897130090f2e76de642400a8f1b4a..f76b4018298a8d5ca82bccda7b9dfbdfb3f6fcd3 100644 (file)
@@ -7,28 +7,11 @@
 #ifndef OPTION6_DNR_H
 #define OPTION6_DNR_H
 
-#include <dhcp/option.h>
 #include <dhcp/option4_dnr.h>
 
 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 DHCPv6 Encrypted DNS %Option (code 144).
 ///
 /// This option has been defined in the @c draft-ietf-add-dnr (to be replaced
index 93c5650b8df83f9dc4d32c4018a07e8493090840..2af6e51e0301f7ba09c49cce5ae4f4afc5cc347a 100644 (file)
@@ -6,13 +6,9 @@
 
 #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;
@@ -22,6 +18,7 @@ using boost::scoped_ptr;
 
 namespace {
 
+// This test verifies constructor of the empty Option4Dnr class.
 TEST(Option4DnrTest, emptyCtor) {
     // Create option instance. Check that constructor doesn't throw.
     scoped_ptr<Option4Dnr> option;
@@ -33,7 +30,9 @@ TEST(Option4DnrTest, emptyCtor) {
     EXPECT_EQ(DHO_V4_DNR, option->getType());
 }
 
-TEST(Option4DnrTest, oneDnrOnlyModeInstance) {
+// This test verifies constructor of the empty Option4Dnr class together
+// with adding ADN-only-mode DNR instance to option's DNR instances.
+TEST(Option4DnrTest, oneAdnOnlyModeInstance) {
     // Create option instance. Check that constructor doesn't throw.
     scoped_ptr<Option4Dnr> option;
     EXPECT_NO_THROW(option.reset(new Option4Dnr()));
@@ -70,7 +69,9 @@ TEST(Option4DnrTest, oneDnrOnlyModeInstance) {
               option->toText());
 }
 
-TEST(Option4DnrTest, multipleDnrOnlyModeInstances) {
+// This test verifies constructor of the empty Option4Dnr class together
+// with adding multiple ADN-only-mode DNR instances to option's DNR instances.
+TEST(Option4DnrTest, multipleAdnOnlyModeInstances) {
     // Create option instance. Check that constructor doesn't throw.
     scoped_ptr<Option4Dnr> option;
     EXPECT_NO_THROW(option.reset(new Option4Dnr()));
@@ -129,6 +130,10 @@ TEST(Option4DnrTest, multipleDnrOnlyModeInstances) {
               option->toText());
 }
 
+// This test verifies constructor of the empty Option4Dnr class together
+// with adding to option's DNR instances:
+// 1. ADN-only-mode DNR instance
+// 2. All fields included (IP addresses and service params also) DNR instance.
 TEST(Option4DnrTest, mixedDnrInstances) {
     // Create option instance. Check that constructor doesn't throw.
     scoped_ptr<Option4Dnr> option;
@@ -186,7 +191,10 @@ TEST(Option4DnrTest, mixedDnrInstances) {
               option->toText());
 }
 
-TEST(Option4DnrTest, packOneDnrOnlyModeInstance) {
+// This test verifies option packing into wire data.
+// Provided data to pack contains 1 DNR instance:
+// 1. ADN only mode
+TEST(Option4DnrTest, packOneAdnOnlyModeInstance) {
     // Create option instance. Check that constructor doesn't throw.
     scoped_ptr<Option4Dnr> option;
     EXPECT_NO_THROW(option.reset(new Option4Dnr()));
@@ -222,7 +230,12 @@ TEST(Option4DnrTest, packOneDnrOnlyModeInstance) {
     EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
 }
 
-TEST(Option4DnrTest, packMultipleDnrOnlyModeInstances) {
+// This test verifies option packing into wire data.
+// Provided data to pack contains 3 DNR instances:
+// 1. ADN only mode
+// 2. ADN only mode
+// 3. ADN only mode
+TEST(Option4DnrTest, packMultipleAdnOnlyModeInstances) {
     // Create option instance. Check that constructor doesn't throw.
     scoped_ptr<Option4Dnr> option;
     EXPECT_NO_THROW(option.reset(new Option4Dnr()));
@@ -278,6 +291,10 @@ TEST(Option4DnrTest, packMultipleDnrOnlyModeInstances) {
     EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
 }
 
+// This test verifies option packing into wire data.
+// Provided data to pack contains 2 DNR instances:
+// 1. ADN only mode
+// 2. All fields included (IP addresses and service params also).
 TEST(Option4DnrTest, packMixedDnrInstances) {
     // Create option instance. Check that constructor doesn't throw.
     scoped_ptr<Option4Dnr> option;
@@ -334,6 +351,7 @@ TEST(Option4DnrTest, packMixedDnrInstances) {
     EXPECT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
 }
 
+// This test verifies option constructor from wire data.
 TEST(Option4DnrTest, onWireDataCtor) {
     // Prepare data to decode - ADN only mode 1 DNR instance.
     const uint8_t buf_data[] = {
@@ -351,6 +369,10 @@ TEST(Option4DnrTest, onWireDataCtor) {
     ASSERT_TRUE(option);
 }
 
+// This test verifies option constructor from wire data in terms
+// of proper data unpacking.
+// Provided wire data contains 1 DNR instance:
+// 1. ADN only mode
 TEST(Option4DnrTest, unpackOneAdnOnly) {
     // Prepare data to decode - ADN only mode 1 DNR instance.
     const uint8_t buf_data[] = {
@@ -396,6 +418,10 @@ TEST(Option4DnrTest, unpackOneAdnOnly) {
               option->toText());
 }
 
+// This test verifies option constructor from wire data in terms
+// of proper data unpacking.
+// Provided wire data contains 1 DNR instance:
+// 1. All fields included (IP addresses and service params also).
 TEST(Option4DnrTest, unpackOneDnrInstance) {
     // Prepare data to decode - 1 DNR instance.
     const uint8_t buf_data[] = {
@@ -438,6 +464,11 @@ TEST(Option4DnrTest, unpackOneDnrInstance) {
     EXPECT_EQ(66, option->len());
 }
 
+// This test verifies option constructor from wire data in terms
+// of proper data unpacking.
+// Provided wire data contains 2 DNR instances:
+// 1. ADN only mode
+// 2. All fields included (IP addresses and service params also).
 TEST(Option4DnrTest, unpackMixedDnrInstances) {
     // Prepare data to decode - 2 DNR instances.
     const uint8_t buf_data[] = {
@@ -495,4 +526,257 @@ TEST(Option4DnrTest, unpackMixedDnrInstances) {
     EXPECT_EQ(92, option->len());
 }
 
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - mandatory fields are truncated - Service Priority and ADN Len truncated.
+TEST(Option4DnrTest, unpackTruncatedDnrInstanceDataLen) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 62                                         // DNR Instance Data Len truncated
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - DNR instance data truncated when compared to DNR Instance Data Len field.
+TEST(Option4DnrTest, unpackTruncatedDnrInstanceData) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 62,                                        // DNR Instance Data Len
+        0x00, 0x02,                                      // Service priority is 2 dec
+        21                                               // ADN Length is 21 dec
+        // the rest of DNR instance data is truncated
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - ADN field data truncated.
+TEST(Option4DnrTest, unpackTruncatedAdn) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 3,                                         // DNR Instance Data Len
+        0x00, 0x02,                                      // Service priority is 2 dec
+        21                                               // ADN Length is 21 dec
+        // ADN data is missing.
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OpaqueDataTupleError);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - ADN FQDN contains only whitespace - non valid FQDN.
+TEST(Option4DnrTest, unpackInvalidFqdnAdn) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 4,                                         // DNR Instance Data Len
+        0x00, 0x02,                                      // Service priority is 2 dec
+        1,                                               // ADN Length is 1 dec
+        ' '                                              // ADN contains only whitespace
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), InvalidOptionDnrDomainName);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - ADN Length is 0 and no ADN FQDN at all.
+TEST(Option4DnrTest, unpackNoFqdnAdn) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 3,                                         // DNR Instance Data Len
+        0x00, 0x02,                                      // Service priority is 2 dec
+        0                                                // ADN Length is 0 dec
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), InvalidOptionDnrDomainName);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - IPv4 address(es) field data truncated.
+TEST(Option4DnrTest, unpackTruncatedIpAddress) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 25,                                        // 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: myhost2.
+        0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65,  // example.
+        0x03, 0x63, 0x6F, 0x6D, 0x00,                    // com.
+        8                                                // Addr Len
+        // the rest of DNR instance data is truncated.
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OpaqueDataTupleError);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - Addr length is 0 and no IPv4 addresses at all.
+TEST(Option4DnrTest, unpackNoIpAddress) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 25,                                        // 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: myhost2.
+        0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65,  // example.
+        0x03, 0x63, 0x6F, 0x6D, 0x00,                    // com.
+        0                                                // Addr Len = 0
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - Addr length is not a multiple of 4.
+TEST(Option4DnrTest, unpackIpAddressNon4Modulo) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 32,                                        // 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: myhost2.
+        0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65,  // example.
+        0x03, 0x63, 0x6F, 0x6D, 0x00,                    // com.
+        7,                                               // Addr Len
+        192,  168,  0,    1,                             // IP address 1
+        192,  168,  0                                    // IP address 2 truncated
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), OutOfRange);
+    ASSERT_FALSE(option);
+}
+
+// Test checks that exception is thrown when trying to unpack malformed wire data
+// - SvcParams Key contains char that is not allowed.
+TEST(Option4DnrTest, unpackvcParamsInvalidCharKey) {
+    // Prepare malformed data to decode.
+    const uint8_t buf_data[] = {
+        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, 39,                                        // 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: myhost2.
+        0x07, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65,  // example.
+        0x03, 0x63, 0x6F, 0x6D, 0x00,                    // com.
+        8,                                               // Addr Len
+        192,  168,  0,    1,                             // IP address 1
+        192,  168,  0,    2,                             // IP address 2 truncated
+        'k',  'e',  'y',  '+',  '2',  '3'                // Svc Params key has forbidden char +
+    };
+    OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
+
+    // Create option instance. Check that constructor throws an exception while doing unpack.
+    scoped_ptr<Option4Dnr> option;
+    EXPECT_THROW(option.reset(new Option4Dnr(buf.begin(), buf.end())), InvalidOptionDnrSvcParams);
+    ASSERT_FALSE(option);
+}
+
+// This test verifies that string representation of the option returned by
+// toText method is correctly formatted.
+TEST(Option4DnrTest, toText) {
+    // 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);
+
+    // Let's check if toText() works ok.
+    // toText() len does not count in headers len.
+    const int indent = 4;
+    std::string expected = "    type=162(V4_DNR), len=26, "  // the indentation of 4 spaces
+                           "DNR Instance 1(Instance len=24, service_priority=1, "
+                           "adn_length=21, adn='myhost1.example.com.')";
+    EXPECT_EQ(expected, option->toText(indent));
+}
+
 }  // namespace
\ No newline at end of file
index d13eaebfd8141408bdc4517408f6e4c7e6dd1790..3868c8384f93175659bed6e52651fe97fa4c6769 100644 (file)
@@ -6,9 +6,6 @@
 
 #include <config.h>
 
-#include <asiolink/io_address.h>
-#include <dhcp/dhcp6.h>
-#include <dhcp/opaque_data_tuple.h>
 #include <dhcp/option6_dnr.h>
 
 #include <boost/scoped_ptr.hpp>