Browse Source

[master] Merge branch 'trac3034'

b10-dhcp6 parses and uses ddns-dhcp configuration
Thomas Markwalder 11 years ago
parent
commit
22c667a665

+ 2 - 0
src/bin/dhcp6/config_parser.cc

@@ -640,6 +640,8 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id) {
         parser = new DbAccessParser(config_id);
     } else if (config_id.compare("hooks-libraries") == 0) {
         parser = new HooksLibrariesParser(config_id);
+    } else if (config_id.compare("dhcp-ddns") == 0) {
+        parser = new D2ClientConfigParser(config_id);
     } else {
         isc_throw(NotImplemented,
                 "Parser error: Global configuration parameter not supported: "

+ 88 - 1
src/bin/dhcp6/dhcp6.spec

@@ -352,7 +352,94 @@
                   }
                 } ]
             }
-       }
+      },
+      { "item_name": "dhcp-ddns",
+        "item_type": "map",
+        "item_optional": false,
+        "item_default": {"enable-updates": false},
+        "item_description" : "Contains parameters pertaining DHCP-driven DDNS updates",
+        "map_item_spec": [
+            {
+                "item_name": "enable-updates",
+                "item_type": "boolean",
+                "item_optional": false,
+                "item_default": false,
+                "item_description" : "Enables DDNS update processing"
+            },
+            {
+                "item_name": "server-ip",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": "127.0.0.1",
+                "item_description" : "IP address of b10-dhcp-ddns (IPv4 or IPv6)"
+            },
+            {
+                "item_name": "server-port",
+                "item_type": "integer",
+                "item_optional": true,
+                "item_default": 53001,
+                "item_description" : "port number of b10-dhcp-ddns"
+            },
+            {
+                "item_name": "ncr-protocol",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": "UDP",
+                "item_description" : "Socket protocol to use with b10-dhcp-ddns"
+            },
+            {
+                "item_name": "ncr-format",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": "JSON",
+                "item_description" : "Format of the update request packet"
+            },
+            {
+
+                "item_name": "always-include-fqdn",
+                "item_type": "boolean",
+                "item_optional": true,
+                "item_default": false,
+                "item_description": "Enable always including the FQDN option in its response"
+            },
+            {
+                "item_name": "override-no-update",
+                "item_type": "boolean",
+                "item_optional": true,
+                "item_default": false,
+                "item_description": "Do update, even if client requested no updates with N flag"
+            },
+            {
+                "item_name": "override-client-update",
+                "item_type": "boolean",
+                "item_optional": true,
+                "item_default": false,
+                "item_description": "Server performs an update even if client requested delegation"
+            },
+            {
+                "item_name": "replace-client-name",
+                "item_type": "boolean",
+                "item_optional": true,
+                "item_default": false,
+                "item_description": "Should server replace the domain-name supplied by the client"
+            },
+            {
+                "item_name": "generated-prefix",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": "myhost",
+                "item_description": "Prefix to use when generating the client's name"
+            },
+
+            {
+                "item_name": "qualifying-suffix",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": "example.com",
+                "item_description": "Fully qualified domain-name suffix if partial name provided by client"
+            },
+        ]
+      },
     ],
     "commands": [
         {

+ 20 - 109
src/bin/dhcp6/dhcp6_srv.cc

@@ -102,31 +102,6 @@ namespace dhcp {
 
 const std::string Dhcpv6Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
 
-namespace {
-
-// The following constants describe server's behavior with respect to the
-// DHCPv6 Client FQDN Option sent by a client. They will be removed
-// when DDNS parameters for DHCPv6 are implemented with the ticket #3034.
-
-// Enable AAAA RR update delegation to the client (Disabled).
-const bool FQDN_ALLOW_CLIENT_UPDATE = false;
-// Globally enable updates (Enabled).
-const bool FQDN_ENABLE_UPDATE = true;
-// The partial name generated for the client if empty name has been
-// supplied.
-const char* FQDN_GENERATED_PARTIAL_NAME = "myhost";
-// Do update, even if client requested no updates with N flag (Disabled).
-const bool FQDN_OVERRIDE_NO_UPDATE = false;
-// Server performs an update when client requested delegation (Enabled).
-const bool FQDN_OVERRIDE_CLIENT_UPDATE = true;
-// The fully qualified domain-name suffix if partial name provided by
-// a client.
-const char* FQDN_PARTIAL_SUFFIX = "example.com";
-// Should server replace the domain-name supplied by the client (Disabled).
-const bool FQDN_REPLACE_CLIENT_NAME = false;
-
-}
-
 /// @brief file name of a server-id file
 ///
 /// Server must store its duid in persistent storage that must not change
@@ -1016,69 +991,18 @@ Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer) {
 
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
               DHCP6_DDNS_RECEIVE_FQDN).arg(fqdn->toText());
-
-
-    // Prepare the FQDN option which will be included in the response to
-    // the client.
+    // Create the DHCPv6 Client FQDN Option to be included in the server's
+    // response to a client.
     Option6ClientFqdnPtr fqdn_resp(new Option6ClientFqdn(*fqdn));
-    // RFC 4704, section 6. - all flags set to 0.
-    fqdn_resp->resetFlags();
-
-    // Conditions when N flag has to be set to indicate that server will not
-    // perform DNS updates:
-    // 1. Updates are globally disabled,
-    // 2. Client requested no update and server respects it,
-    // 3. Client requested that the AAAA update is delegated to the client but
-    //    server neither respects delegation of updates nor it is configured
-    //    to send update on its own when client requested delegation.
-    if (!FQDN_ENABLE_UPDATE ||
-        (fqdn->getFlag(Option6ClientFqdn::FLAG_N) &&
-         !FQDN_OVERRIDE_NO_UPDATE) ||
-        (!fqdn->getFlag(Option6ClientFqdn::FLAG_S) &&
-         !FQDN_ALLOW_CLIENT_UPDATE && !FQDN_OVERRIDE_CLIENT_UPDATE)) {
-        fqdn_resp->setFlag(Option6ClientFqdn::FLAG_N, true);
-
-    // Conditions when S flag is set to indicate that server will perform
-    // DNS update on its own:
-    // 1. Client requested that server performs DNS update and DNS updates are
-    //    globally enabled
-    // 2. Client requested that server delegates AAAA update to the client but
-    //    server doesn't respect delegation and it is configured to perform
-    //    an update on its own when client requested delegation.
-    } else if (fqdn->getFlag(Option6ClientFqdn::FLAG_S) ||
-               (!fqdn->getFlag(Option6ClientFqdn::FLAG_S) &&
-                !FQDN_ALLOW_CLIENT_UPDATE && FQDN_OVERRIDE_CLIENT_UPDATE)) {
-        fqdn_resp->setFlag(Option6ClientFqdn::FLAG_S, true);
-    }
-
-    // Server MUST set the O flag if it has overridden the client's setting
-    // of S flag.
-    if (fqdn->getFlag(Option6ClientFqdn::FLAG_S) !=
-        fqdn_resp->getFlag(Option6ClientFqdn::FLAG_S)) {
-        fqdn_resp->setFlag(Option6ClientFqdn::FLAG_O, true);
-    }
-
-    // If client supplied partial or empty domain-name, server should
-    // generate one.
-    if (fqdn->getDomainNameType() == Option6ClientFqdn::PARTIAL) {
-        std::ostringstream name;
-        if (fqdn->getDomainName().empty() || FQDN_REPLACE_CLIENT_NAME) {
-            fqdn->setDomainName("", Option6ClientFqdn::PARTIAL);
 
-        } else {
-            name << fqdn->getDomainName();
-            name << "." << FQDN_PARTIAL_SUFFIX;
-            fqdn_resp->setDomainName(name.str(), Option6ClientFqdn::FULL);
-        }
-
-    // Server may be configured to replace a name supplied by a client,
-    // even if client supplied fully qualified domain-name.
-    } else if (FQDN_REPLACE_CLIENT_NAME) {
-        std::ostringstream name;
-        name << FQDN_GENERATED_PARTIAL_NAME << "." << FQDN_PARTIAL_SUFFIX;
-        fqdn_resp->setDomainName(name.str(), Option6ClientFqdn::FULL);
+    // Set the server S, N, and O flags based on client's flags and
+    // current configuration.
+    D2ClientMgr& d2_mgr = CfgMgr::instance().getD2ClientMgr();
+    d2_mgr.adjustFqdnFlags<Option6ClientFqdn>(*fqdn, *fqdn_resp);
 
-    }
+    // Adjust the domain name based on domain name value and type sent by the
+    // client and current configuration.
+    d2_mgr.adjustDomainName<Option6ClientFqdn>(*fqdn, *fqdn_resp);
 
     // The FQDN has been processed successfully. Let's append it to the
     // response to be sent to a client. Note that the Client FQDN option is
@@ -1090,7 +1014,7 @@ Dhcpv6Srv::processClientFqdn(const Pkt6Ptr& question, const Pkt6Ptr& answer) {
 void
 Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer) {
     // Don't create NameChangeRequests if DNS updates are disabled.
-    if (!FQDN_ENABLE_UPDATE) {
+    if (!CfgMgr::instance().ddnsEnabled()) {
         return;
     }
 
@@ -1177,7 +1101,7 @@ Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer) {
 void
 Dhcpv6Srv::createRemovalNameChangeRequest(const Lease6Ptr& lease) {
     // Don't create NameChangeRequests if DNS updates are disabled.
-    if (!FQDN_ENABLE_UPDATE) {
+    if (!CfgMgr::instance().ddnsEnabled()) {
         return;
     }
 
@@ -1299,14 +1223,11 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
     Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
         Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
     if (fqdn) {
-        // Flag S must not coexist with flag N being set to 1, so if S=1
-        // server takes responsibility for both reverse and forward updates.
-        // Otherwise, we have to check N.
+        /// @todo For now, we assert that if we are doing forward we are also
+        /// doing reverse.
         if (fqdn->getFlag(Option6ClientFqdn::FLAG_S)) {
             do_fwd = true;
             do_rev = true;
-        } else if (!fqdn->getFlag(Option6ClientFqdn::FLAG_N)) {
-            do_rev = true;
         }
     }
     // Set hostname only in case any of the updates is being performed.
@@ -1557,11 +1478,11 @@ Dhcpv6Srv::renewIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
     Option6ClientFqdnPtr fqdn = boost::dynamic_pointer_cast<
         Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
     if (fqdn) {
+        // For now, we assert that if we are doing forward we are also
+        // doing reverse.
         if (fqdn->getFlag(Option6ClientFqdn::FLAG_S)) {
             do_fwd = true;
             do_rev = true;
-        } else if (!fqdn->getFlag(Option6ClientFqdn::FLAG_N)) {
-            do_rev = true;
         }
     }
 
@@ -2501,17 +2422,8 @@ Dhcpv6Srv::generateFqdn(const Pkt6Ptr& answer) {
     }
     // Get the IPv6 address acquired by the client.
     IOAddress addr = iaaddr->getAddress();
-    std::string hostname = addr.toText();
-    // Colons may not be ok for FQDNs so let's replace them with hyphens.
-    std::replace(hostname.begin(), hostname.end(), ':', '-');
-    std::ostringstream stream;
-    // The final FQDN consists of the partial domain name and the suffix.
-    // For example, if the acquired address is 2001:db8:1::2, the generated
-    // FQDN may be:
-    //     host-2001-db8:1--2.example.com.
-    // where prefix 'host' should be configurable. The domain name suffix
-    // should also be configurable.
-    stream << "host-" << hostname << "." << FQDN_PARTIAL_SUFFIX << ".";
+    std::string generated_name =
+        CfgMgr::instance().getD2ClientMgr().generateFqdn(addr);
     try {
         // The lease has been acquired but the FQDN for this lease hasn't
         // been updated in the lease database. We now have new FQDN
@@ -2522,7 +2434,7 @@ Dhcpv6Srv::generateFqdn(const Pkt6Ptr& answer) {
             Lease6Ptr lease =
                 LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
             if (lease) {
-                lease->hostname_ = stream.str();
+                lease->hostname_ = generated_name;
                 LeaseMgrFactory::instance().updateLease6(lease);
 
             } else {
@@ -2533,13 +2445,12 @@ Dhcpv6Srv::generateFqdn(const Pkt6Ptr& answer) {
                           " client");
             }
         }
-
         // Set the generated FQDN in the Client FQDN option.
-        fqdn->setDomainName(stream.str(), Option6ClientFqdn::FULL);
+        fqdn->setDomainName(generated_name, Option6ClientFqdn::FULL);
 
     } catch (const Exception& ex) {
         LOG_ERROR(dhcp6_logger, DHCP6_NAME_GEN_UPDATE_FAIL)
-            .arg(hostname)
+            .arg(addr.toText())
             .arg(ex.what());
     }
 }

+ 2 - 0
src/bin/dhcp6/dhcp6_srv.h

@@ -405,6 +405,7 @@ protected:
     /// objects and store them in the internal queue. Requests created by this
     /// function are only adding or updating DNS records. In order to generate
     /// requests for DNS records removal, use @c createRemovalNameChangeRequest.
+    /// If ddns updates are disabled, this method returns immediately.
     ///
     /// @todo Add support for multiple IAADDR options in the IA_NA.
     ///
@@ -422,6 +423,7 @@ protected:
     /// Note that this function will not remove the entries which server hadn't
     /// added. This is the case, when client performs forward DNS update on its
     /// own.
+    /// If ddns updates are disabled, this method returns immediately.
     ///
     /// @param lease A lease for which the the removal of corresponding DNS
     /// records will be performed.

+ 109 - 0
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -347,6 +347,7 @@ public:
             "\"renew-timer\": 1000, "
             "\"valid-lifetime\": 4000, "
             "\"subnet6\": [ ], "
+            "\"dhcp-ddns\": { \"enable-updates\" : false }, "
             "\"option-def\": [ ], "
             "\"option-data\": [ ] }";
         static_cast<void>(executeConfiguration(config,
@@ -3091,5 +3092,113 @@ TEST_F(Dhcp6ParserTest, classifySubnets) {
     EXPECT_TRUE (subnets->at(3)->clientSupported(classes));
 }
 
+// This test checks the ability of the server to parse a configuration
+// containing a full, valid dhcp-ddns (D2ClientConfig) entry.
+TEST_F(Dhcp6ParserTest, d2ClientConfig) {
+    ConstElementPtr status;
+
+    // Verify that the D2 configuraiton can be fetched and is set to disabled.
+    D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig();
+    EXPECT_FALSE(d2_client_config->getEnableUpdates());
+
+    // Verify that the convenience method agrees.
+    ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
+
+    string config_str = "{ \"interfaces\": [ \"*\" ],"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/80\" ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ], "
+        " \"dhcp-ddns\" : {"
+        "     \"enable-updates\" : true, "
+        "     \"server-ip\" : \"192.168.2.1\", "
+        "     \"server-port\" : 777, "
+        "     \"ncr-protocol\" : \"UDP\", "
+        "     \"ncr-format\" : \"JSON\", "
+        "     \"always-include-fqdn\" : true, "
+        "     \"allow-client-update\" : true, "
+        "     \"override-no-update\" : true, "
+        "     \"override-client-update\" : true, "
+        "     \"replace-client-name\" : true, "
+        "     \"generated-prefix\" : \"test.prefix\", "
+        "     \"qualifying-suffix\" : \"test.suffix.\" },"
+        "\"valid-lifetime\": 4000 }";
+
+    // Convert the JSON string to configuration elements.
+    ElementPtr config;
+    ASSERT_NO_THROW(config = Element::fromJSON(config_str));
+
+    // Pass the configuration in for parsing.
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, config));
+
+    // check if returned status is OK
+    checkResult(status, 0);
+
+    // Verify that DHCP-DDNS updating is enabled.
+    EXPECT_TRUE(CfgMgr::instance().ddnsEnabled());
+
+    // Verify that the D2 configuration can be retrieved.
+    d2_client_config = CfgMgr::instance().getD2ClientConfig();
+    ASSERT_TRUE(d2_client_config);
+
+    // Verify that the configuration values are correct.
+    EXPECT_TRUE(d2_client_config->getEnableUpdates());
+    EXPECT_EQ("192.168.2.1", d2_client_config->getServerIp().toText());
+    EXPECT_EQ(777, d2_client_config->getServerPort());
+    EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol());
+    EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat());
+    EXPECT_TRUE(d2_client_config->getAlwaysIncludeFqdn());
+    EXPECT_TRUE(d2_client_config->getOverrideNoUpdate());
+    EXPECT_TRUE(d2_client_config->getOverrideClientUpdate());
+    EXPECT_TRUE(d2_client_config->getReplaceClientName());
+    EXPECT_EQ("test.prefix", d2_client_config->getGeneratedPrefix());
+    EXPECT_EQ("test.suffix.", d2_client_config->getQualifyingSuffix());
+}
+
+// This test checks the ability of the server to handle a configuration
+// containing an invalid dhcp-ddns (D2ClientConfig) entry.
+TEST_F(Dhcp6ParserTest, invalidD2ClientConfig) {
+    ConstElementPtr status;
+
+    // Configuration string with an invalid D2 client config,
+    // "server-ip" is missing.
+    string config_str = "{ \"interfaces\": [ \"*\" ],"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pool\": [ \"2001:db8:1::/80\" ],"
+        "    \"subnet\": \"2001:db8:1::/64\" } ], "
+        " \"dhcp-ddns\" : {"
+        "     \"enable-updates\" : true, "
+        "     \"server-port\" : 5301, "
+        "     \"ncr-protocol\" : \"UDP\", "
+        "     \"ncr-format\" : \"JSON\", "
+        "     \"always-include-fqdn\" : true, "
+        "     \"allow-client-update\" : true, "
+        "     \"override-no-update\" : true, "
+        "     \"override-client-update\" : true, "
+        "     \"replace-client-name\" : true, "
+        "     \"generated-prefix\" : \"test.prefix\", "
+        "     \"qualifying-suffix\" : \"test.suffix.\" },"
+        "\"valid-lifetime\": 4000 }";
+
+    // Convert the JSON string to configuration elements.
+    ElementPtr config;
+    ASSERT_NO_THROW(config = Element::fromJSON(config_str));
+
+    // Configuration should not throw, but should fail.
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, config));
+
+    // check if returned status is failed.
+    checkResult(status, 1);
+
+    // Verify that the D2 configuraiton can be fetched and is set to disabled.
+    D2ClientConfigPtr d2_client_config = CfgMgr::instance().getD2ClientConfig();
+    EXPECT_FALSE(d2_client_config->getEnableUpdates());
+
+    // Verify that the convenience method agrees.
+    ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
+}
 
 };

+ 105 - 5
src/bin/dhcp6/tests/fqdn_unittest.cc

@@ -43,20 +43,63 @@ namespace {
 /// @brief A test fixture class for testing DHCPv6 Client FQDN Option handling.
 class FqdnDhcpv6SrvTest : public Dhcpv6SrvTest {
 public:
+    // Reference to D2ClientMgr singleton
+    D2ClientMgr& d2_mgr_;
+
+    // Bit Constants for turning on and off DDNS configuration options.
+    // (Defined here as these are only meaningful to this class.)
+    static const uint16_t ALWAYS_INCLUDE_FQDN = 1;
+    static const uint16_t OVERRIDE_NO_UPDATE = 2;
+    static const uint16_t OVERRIDE_CLIENT_UPDATE = 4;
+    static const uint16_t REPLACE_CLIENT_NAME = 8;
 
     /// @brief Constructor
     FqdnDhcpv6SrvTest()
-        : Dhcpv6SrvTest() {
+        : Dhcpv6SrvTest(), d2_mgr_(CfgMgr::instance().getD2ClientMgr()) {
         // generateClientId assigns DUID to duid_.
         generateClientId();
         lease_.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
                                 duid_, 1234, 501, 502, 503,
                                 504, 1, 0));
-
+        // Config DDNS to be enabled, all controls off
+        enableD2();
     }
 
     /// @brief Destructor
     virtual ~FqdnDhcpv6SrvTest() {
+        // Default constructor creates a config with DHCP-DDNS updates
+        // disabled.
+        D2ClientConfigPtr cfg(new D2ClientConfig());
+        CfgMgr::instance().setD2ClientConfig(cfg);
+    }
+
+    /// @brief Sets the server's DDNS configuration to ddns updates disabled.
+    void disableD2() {
+        // Default constructor creates a config with DHCP-DDNS updates
+        // disabled.
+        D2ClientConfigPtr cfg(new D2ClientConfig());
+        CfgMgr::instance().setD2ClientConfig(cfg);
+    }
+
+    /// @brief Enables DHCP-DDNS updates with the given options enabled.
+    ///
+    /// Replaces the current D2ClientConfiguration with a configuration
+    /// which as updates enabled and the control options set based upon
+    /// the bit mask of options.
+    ///
+    /// @param mask Bit mask of configuration options that should be enabled.
+    void enableD2(const uint16_t mask = 0) {
+        D2ClientConfigPtr cfg;
+
+        ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 53001,
+                                  dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+                                  (mask & ALWAYS_INCLUDE_FQDN),
+                                  (mask & OVERRIDE_NO_UPDATE),
+                                  (mask & OVERRIDE_CLIENT_UPDATE),
+                                  (mask & REPLACE_CLIENT_NAME),
+                                  "myhost", "example.com")));
+        ASSERT_NO_THROW(CfgMgr::instance().setD2ClientConfig(cfg));
     }
 
     /// @brief Construct the DHCPv6 Client FQDN option using flags and
@@ -376,6 +419,13 @@ public:
     /// @param addr A string representation of the IPv6 address held in the
     /// NameChangeRequest.
     /// @param dhcid An expected DHCID value.
+    /// @note This value is the value that is produced by
+    /// dhcp_ddns::D2Dhcid::crateDigest() with the appropriate arguments. This
+    /// method uses encryption tools to produce the value which cannot be
+    /// easily duplicated by hand.  It is more or less necessary to generate
+    /// these values programmatically and place them here. Should the
+    /// underlying implementation of createDigest() change these test values
+    /// will likely need to be updated as well.
     /// @param expires A timestamp when the lease associated with the
     /// NameChangeRequest expires.
     /// @param len A valid lifetime of the lease associated with the
@@ -443,6 +493,7 @@ TEST_F(FqdnDhcpv6SrvTest, noUpdate) {
 // Test server's response when client requests that server delegates the AAAA
 // update to the client and this delegation is not allowed.
 TEST_F(FqdnDhcpv6SrvTest, clientAAAAUpdateNotAllowed) {
+    enableD2(OVERRIDE_CLIENT_UPDATE);
     testFqdn(DHCPV6_SOLICIT, 0, "myhost.example.com.",
              Option6ClientFqdn::FULL,
              Option6ClientFqdn::FLAG_S | Option6ClientFqdn::FLAG_O,
@@ -545,6 +596,34 @@ TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequests) {
 
 }
 
+// Checks that NameChangeRequests to add entries are not
+// created when ddns updates are disabled.
+TEST_F(FqdnDhcpv6SrvTest, noAddRequestsWhenDisabled) {
+    NakedDhcpv6Srv srv(0);
+
+    // Disable DDNS udpates.
+    disableD2();
+
+    // Create Reply message with Client Id and Server id.
+    Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY, srv);
+
+    // Create three IAs, each having different address.
+    addIA(1234, IOAddress("2001:db8:1::1"), answer);
+
+    // Use domain name in upper case. It should be converted to lower-case
+    // before DHCID is calculated. So, we should get the same result as if
+    // we typed domain name in lower-case.
+    Option6ClientFqdnPtr fqdn = createClientFqdn(Option6ClientFqdn::FLAG_S,
+                                                 "MYHOST.EXAMPLE.COM",
+                                                 Option6ClientFqdn::FULL);
+    answer->addOption(fqdn);
+
+    // Create NameChangeRequest for the first allocated address.
+    ASSERT_NO_THROW(srv.createNameChangeRequests(answer));
+    ASSERT_TRUE(srv.name_change_reqs_.empty());
+}
+
+
 // Test creation of the NameChangeRequest to remove both forward and reverse
 // mapping for the given lease.
 TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestFwdRev) {
@@ -569,6 +648,27 @@ TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestFwdRev) {
 
 }
 
+// Checks that NameChangeRequests to remove entries are not created
+// when ddns updates are disabled.
+TEST_F(FqdnDhcpv6SrvTest, noRemovalsWhenDisabled) {
+    NakedDhcpv6Srv srv(0);
+
+    // Disable DDNS updates.
+    disableD2();
+
+    lease_->fqdn_fwd_ = true;
+    lease_->fqdn_rev_ = true;
+    // Part of the domain name is in upper case, to test that it gets converted
+    // to lower case before DHCID is computed. So, we should get the same DHCID
+    // as if we typed domain-name in lower case.
+    lease_->hostname_ = "MYHOST.example.com.";
+
+    ASSERT_NO_THROW(srv.createRemovalNameChangeRequest(lease_));
+
+    ASSERT_TRUE(srv.name_change_reqs_.empty());
+}
+
+
 // Test creation of the NameChangeRequest to remove reverse mapping for the
 // given lease.
 TEST_F(FqdnDhcpv6SrvTest, createRemovalNameChangeRequestRev) {
@@ -821,13 +921,13 @@ TEST_F(FqdnDhcpv6SrvTest, processRequestEmptyFqdn) {
     NakedDhcpv6Srv srv(0);
 
     testProcessMessage(DHCPV6_REQUEST, "",
-                       "host-2001-db8-1-1--dead-beef.example.com.",
+                       "myhost-2001-db8-1-1--dead-beef.example.com.",
                        srv, false);
     ASSERT_EQ(1, srv.name_change_reqs_.size());
     verifyNameChangeRequest(srv, isc::dhcp_ddns::CHG_ADD, true, true,
                             "2001:db8:1:1::dead:beef",
-                            "0002018D6874B105A5C92DBBD6E4F6C80A93161"
-                            "BC03996F0CD0EB75800DEF997C29961",
+                            "000201C905E54BE12DE6AF92ADE72752B9F362"
+                            "13B5A8BC9D217548CD739B4CF31AFB1B",
                             0, 4000);
 
 }