|
@@ -1,4 +1,4 @@
|
|
|
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
|
|
|
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
|
|
|
//
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
@@ -16,8 +16,10 @@
|
|
|
#include <asiolink/io_address.h>
|
|
|
#include <dhcp/option4_client_fqdn.h>
|
|
|
#include <dhcp/option_int_array.h>
|
|
|
+#include <dhcp/tests/iface_mgr_test_config.h>
|
|
|
#include <dhcp4/tests/dhcp4_test_utils.h>
|
|
|
#include <dhcp_ddns/ncr_msg.h>
|
|
|
+#include <dhcpsrv/cfgmgr.h>
|
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
#include <boost/scoped_ptr.hpp>
|
|
@@ -30,13 +32,59 @@ using namespace isc::dhcp_ddns;
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
-class NameDhcpv4SrvTest : public Dhcpv4SrvFakeIfaceTest {
|
|
|
+class NameDhcpv4SrvTest : public Dhcpv4SrvTest {
|
|
|
public:
|
|
|
- NameDhcpv4SrvTest() : Dhcpv4SrvFakeIfaceTest() {
|
|
|
+ // Reference to D2ClientMgr singleton
|
|
|
+ D2ClientMgr& d2_mgr_;
|
|
|
+
|
|
|
+ // Bit Constants for turning on and off DDNS configuration options.
|
|
|
+ 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;
|
|
|
+
|
|
|
+ NameDhcpv4SrvTest() : Dhcpv4SrvTest(),
|
|
|
+ d2_mgr_(CfgMgr::instance().getD2ClientMgr()) {
|
|
|
srv_ = new NakedDhcpv4Srv(0);
|
|
|
+ // Config DDNS to be enabled, all controls off
|
|
|
+ enableD2();
|
|
|
}
|
|
|
+
|
|
|
virtual ~NameDhcpv4SrvTest() {
|
|
|
delete srv_;
|
|
|
+ // CfgMgr singleton doesn't get wiped between tests, so we'll
|
|
|
+ // disable D2 explictly between tests.
|
|
|
+ disableD2();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// @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));
|
|
|
+ ASSERT_NO_THROW(srv_->startD2());
|
|
|
}
|
|
|
|
|
|
// Create a lease to be used by various tests.
|
|
@@ -78,15 +126,18 @@ public:
|
|
|
return (opt_hostname);
|
|
|
}
|
|
|
|
|
|
- // Generates partial hostname from the address. The format of the
|
|
|
- // generated address is: host-A-B-C-D, where A.B.C.D is an IP
|
|
|
- // address.
|
|
|
+ /// @brief Convenience method for generating an FQDN from an IP address.
|
|
|
+ ///
|
|
|
+ /// This is just a wrapper method around the D2ClientMgr's method for
|
|
|
+ /// generating domain names from the configured prefix, suffix, and a
|
|
|
+ /// given IP address. This is useful for verifying that fully generated
|
|
|
+ /// names are correct.
|
|
|
+ ///
|
|
|
+ /// @param addr IP address used in the lease.
|
|
|
+ ///
|
|
|
+ /// @return An std::string contained the generated FQDN.
|
|
|
std::string generatedNameFromAddress(const IOAddress& addr) {
|
|
|
- std::string gen_name = addr.toText();
|
|
|
- std::replace(gen_name.begin(), gen_name.end(), '.', '-');
|
|
|
- std::ostringstream hostname;
|
|
|
- hostname << "host-" << gen_name;
|
|
|
- return (hostname.str());
|
|
|
+ return(CfgMgr::instance().getD2ClientMgr().generateFqdn(addr));
|
|
|
}
|
|
|
|
|
|
// Get the Client FQDN Option from the given message.
|
|
@@ -110,7 +161,7 @@ public:
|
|
|
const bool include_clientid = true) {
|
|
|
Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(msg_type, 1234));
|
|
|
pkt->setRemoteAddr(IOAddress("192.0.2.3"));
|
|
|
- pkt->setIface("eth0");
|
|
|
+ pkt->setIface("eth1");
|
|
|
// For DISCOVER we don't include server id, because client broadcasts
|
|
|
// the message to all servers.
|
|
|
if (msg_type != DHCPDISCOVER) {
|
|
@@ -182,6 +233,21 @@ public:
|
|
|
Option4ClientFqdnPtr fqdn = getClientFqdnOption(answer);
|
|
|
ASSERT_TRUE(fqdn);
|
|
|
|
|
|
+ checkFqdnFlags(answer, exp_flags);
|
|
|
+
|
|
|
+ EXPECT_EQ(exp_domain_name, fqdn->getDomainName());
|
|
|
+ EXPECT_EQ(exp_domain_type, fqdn->getDomainNameType());
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /// @brief Checks the packet's FQDN option flags against a given mask
|
|
|
+ ///
|
|
|
+ /// @param pkt IPv4 packet whose FQDN flags should be checked.
|
|
|
+ /// @param exp_flags Bit mask of flags that are expected to be true.
|
|
|
+ void checkFqdnFlags(const Pkt4Ptr& pkt, const uint8_t exp_flags) {
|
|
|
+ Option4ClientFqdnPtr fqdn = getClientFqdnOption(pkt);
|
|
|
+ ASSERT_TRUE(fqdn);
|
|
|
+
|
|
|
const bool flag_n = (exp_flags & Option4ClientFqdn::FLAG_N) != 0;
|
|
|
const bool flag_s = (exp_flags & Option4ClientFqdn::FLAG_S) != 0;
|
|
|
const bool flag_o = (exp_flags & Option4ClientFqdn::FLAG_O) != 0;
|
|
@@ -191,12 +257,9 @@ public:
|
|
|
EXPECT_EQ(flag_s, fqdn->getFlag(Option4ClientFqdn::FLAG_S));
|
|
|
EXPECT_EQ(flag_o, fqdn->getFlag(Option4ClientFqdn::FLAG_O));
|
|
|
EXPECT_EQ(flag_e, fqdn->getFlag(Option4ClientFqdn::FLAG_E));
|
|
|
-
|
|
|
- EXPECT_EQ(exp_domain_name, fqdn->getDomainName());
|
|
|
- EXPECT_EQ(exp_domain_type, fqdn->getDomainNameType());
|
|
|
-
|
|
|
}
|
|
|
|
|
|
+
|
|
|
// Processes the Hostname option in the client's message and returns
|
|
|
// the hostname option which would be sent to the client. It will
|
|
|
// throw NULL pointer if the hostname option is not to be included
|
|
@@ -221,8 +284,8 @@ public:
|
|
|
|
|
|
}
|
|
|
|
|
|
- // Test that the client message holding an FQDN is processed and the
|
|
|
- // NameChangeRequests are generated.
|
|
|
+ // Test that the client message holding an FQDN is processed and
|
|
|
+ // that the response packet is as expected.
|
|
|
void testProcessMessageWithFqdn(const uint8_t msg_type,
|
|
|
const std::string& hostname) {
|
|
|
Pkt4Ptr req = generatePktWithFqdn(msg_type, Option4ClientFqdn::FLAG_S |
|
|
@@ -261,16 +324,19 @@ public:
|
|
|
const time_t cltt,
|
|
|
const uint16_t len,
|
|
|
const bool not_strict_expire_check = false) {
|
|
|
- NameChangeRequest ncr = srv_->name_change_reqs_.front();
|
|
|
- EXPECT_EQ(type, ncr.getChangeType());
|
|
|
- EXPECT_EQ(forward, ncr.isForwardChange());
|
|
|
- EXPECT_EQ(reverse, ncr.isReverseChange());
|
|
|
- EXPECT_EQ(addr, ncr.getIpAddress());
|
|
|
- EXPECT_EQ(fqdn, ncr.getFqdn());
|
|
|
+ NameChangeRequestPtr ncr;
|
|
|
+ ASSERT_NO_THROW(ncr = d2_mgr_.peekAt(0));
|
|
|
+ ASSERT_TRUE(ncr);
|
|
|
+
|
|
|
+ EXPECT_EQ(type, ncr->getChangeType());
|
|
|
+ EXPECT_EQ(forward, ncr->isForwardChange());
|
|
|
+ EXPECT_EQ(reverse, ncr->isReverseChange());
|
|
|
+ EXPECT_EQ(addr, ncr->getIpAddress());
|
|
|
+ EXPECT_EQ(fqdn, ncr->getFqdn());
|
|
|
// Compare dhcid if it is not empty. In some cases, the DHCID is
|
|
|
// not known in advance and can't be compared.
|
|
|
if (!dhcid.empty()) {
|
|
|
- EXPECT_EQ(dhcid, ncr.getDhcid().toStr());
|
|
|
+ EXPECT_EQ(dhcid, ncr->getDhcid().toStr());
|
|
|
}
|
|
|
// In some cases, the test doesn't have access to the last transmission
|
|
|
// time for the particular client. In such cases, the test can use the
|
|
@@ -278,15 +344,68 @@ public:
|
|
|
// for equality but rather check that the lease expiration time is not
|
|
|
// greater than the current time + lease lifetime.
|
|
|
if (not_strict_expire_check) {
|
|
|
- EXPECT_GE(cltt + len, ncr.getLeaseExpiresOn());
|
|
|
+ EXPECT_GE(cltt + len, ncr->getLeaseExpiresOn());
|
|
|
} else {
|
|
|
- EXPECT_EQ(cltt + len, ncr.getLeaseExpiresOn());
|
|
|
+ EXPECT_EQ(cltt + len, ncr->getLeaseExpiresOn());
|
|
|
}
|
|
|
- EXPECT_EQ(len, ncr.getLeaseLength());
|
|
|
- EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr.getStatus());
|
|
|
- srv_->name_change_reqs_.pop();
|
|
|
+ EXPECT_EQ(len, ncr->getLeaseLength());
|
|
|
+ EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr->getStatus());
|
|
|
+
|
|
|
+ // Process the message off the queue
|
|
|
+ ASSERT_NO_THROW(d2_mgr_.runReadyIO());
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /// @brief Tests processing a request with the given client flags
|
|
|
+ ///
|
|
|
+ /// This method creates a request with its FQDN flags set to the given
|
|
|
+ /// value and submits it to the server for processing. It then checks
|
|
|
+ /// the following:
|
|
|
+ /// 1. Did the server generate an ACK with the correct FQDN flags
|
|
|
+ /// 2. If the server should have generated an NCR, did it? and If
|
|
|
+ /// so was it correct?
|
|
|
+ ///
|
|
|
+ /// @param client_flags Mask of client FQDN flags which are true
|
|
|
+ /// @param response_flags Mask of expected FQDN flags in the response
|
|
|
+ void flagVsConfigScenario(const uint8_t client_flags,
|
|
|
+ const uint8_t response_flags) {
|
|
|
+ // Create fake interfaces and open fake sockets.
|
|
|
+ IfaceMgrTestConfig iface_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
+ Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, client_flags,
|
|
|
+ "myhost.example.com.",
|
|
|
+ Option4ClientFqdn::FULL, true);
|
|
|
+
|
|
|
+ // Process the request.
|
|
|
+ Pkt4Ptr reply;
|
|
|
+ ASSERT_NO_THROW(reply = srv_->processRequest(req));
|
|
|
+
|
|
|
+ // Verify the response and flags.
|
|
|
+ checkResponse(reply, DHCPACK, 1234);
|
|
|
+ checkFqdnFlags(reply, response_flags);
|
|
|
+
|
|
|
+ // NCRs cannot be sent to the d2_mgr unless updates are enabled.
|
|
|
+ if (d2_mgr_.ddnsEnabled()) {
|
|
|
+ // There should be an NCR only if response S flag is 1.
|
|
|
+ /// @todo This logic will need to change if forward and reverse
|
|
|
+ /// updates are ever controlled independently.
|
|
|
+ if ((response_flags & Option4ClientFqdn::FLAG_S) == 0) {
|
|
|
+ ASSERT_EQ(0, d2_mgr_.getQueueSize());
|
|
|
+ } else {
|
|
|
+ // Verify that there is one NameChangeRequest as expected.
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
+ verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
|
|
+ reply->getYiaddr().toText(),
|
|
|
+ "myhost.example.com.",
|
|
|
+ "", // empty DHCID means don't check it
|
|
|
+ time(NULL) + subnet_->getValid(),
|
|
|
+ subnet_->getValid(), true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
NakedDhcpv4Srv* srv_;
|
|
|
|
|
|
};
|
|
@@ -348,21 +467,101 @@ TEST_F(NameDhcpv4SrvTest, dhcidComputeFromHWAddr) {
|
|
|
EXPECT_EQ(dhcid_ref, dhcid.toStr());
|
|
|
}
|
|
|
|
|
|
+// Tests the following scenario:
|
|
|
+// - Updates are enabled
|
|
|
+// - All overrides are off
|
|
|
+// - Client requests forward update (N = 0, S = 1)
|
|
|
+//
|
|
|
+// Server should perform the update:
|
|
|
+// - Reponse flags should N = 0, S = 1, O = 0
|
|
|
+// - Should queue an NCR
|
|
|
+TEST_F(NameDhcpv4SrvTest, updatesEnabled) {
|
|
|
+ flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_S),
|
|
|
+ (Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_S));
|
|
|
+}
|
|
|
|
|
|
-// Test that server confirms to perform the forward and reverse DNS update,
|
|
|
-// when client asks for it.
|
|
|
-TEST_F(NameDhcpv4SrvTest, serverUpdateForwardFqdn) {
|
|
|
- Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
|
|
|
- Option4ClientFqdn::FLAG_E |
|
|
|
- Option4ClientFqdn::FLAG_S,
|
|
|
- "myhost.example.com.",
|
|
|
- Option4ClientFqdn::FULL,
|
|
|
- true);
|
|
|
+// Tests the following scenario
|
|
|
+// - Updates are disabled
|
|
|
+// - Client requests forward update (N = 0, S = 1)
|
|
|
+//
|
|
|
+// Server should NOT perform updates:
|
|
|
+// - Response flags should N = 1, S = 0, O = 1
|
|
|
+// - Should not queue any NCRs
|
|
|
+TEST_F(NameDhcpv4SrvTest, updatesDisabled) {
|
|
|
+ disableD2();
|
|
|
+ flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_S),
|
|
|
+ (Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_N |
|
|
|
+ Option4ClientFqdn::FLAG_O));
|
|
|
+}
|
|
|
|
|
|
- testProcessFqdn(query,
|
|
|
- Option4ClientFqdn::FLAG_E | Option4ClientFqdn::FLAG_S,
|
|
|
- "myhost.example.com.");
|
|
|
+// Tests the following scenario:
|
|
|
+// - Updates are enabled
|
|
|
+// - All overrides are off.
|
|
|
+// - Client requests no updates (N = 1, S = 0)
|
|
|
+//
|
|
|
+// Server should NOT perform updates:
|
|
|
+// - Response flags should N = 1, S = 0, O = 0
|
|
|
+// - Should not queue any NCRs
|
|
|
+TEST_F(NameDhcpv4SrvTest, respectNoUpdate) {
|
|
|
+ flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_N),
|
|
|
+ (Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_N));
|
|
|
+}
|
|
|
+
|
|
|
+// Tests the following scenario:
|
|
|
+// - Updates are enabled
|
|
|
+// - override-no-update is on
|
|
|
+// - Client requests no updates (N = 1, S = 0)
|
|
|
+//
|
|
|
+// Server should override "no update" request and perform updates:
|
|
|
+// - Response flags should be N = 0, S = 1, O = 1
|
|
|
+// - Should queue an NCR
|
|
|
+TEST_F(NameDhcpv4SrvTest, overrideNoUpdate) {
|
|
|
+ enableD2(OVERRIDE_NO_UPDATE);
|
|
|
+ flagVsConfigScenario((Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_N),
|
|
|
+ (Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_S |
|
|
|
+ Option4ClientFqdn::FLAG_O));
|
|
|
+}
|
|
|
+
|
|
|
+// Tests the following scenario:
|
|
|
+// - Updates are enabled
|
|
|
+// - All overrides are off.
|
|
|
+// - Client requests delegation (N = 0, S = 0)
|
|
|
+//
|
|
|
+// Server should respect client's delegation request and NOT do updates:
|
|
|
|
|
|
+// - Response flags should be N = 1, S = 0, O = 0
|
|
|
+// - Should not queue any NCRs
|
|
|
+TEST_F(NameDhcpv4SrvTest, respectClientDelegation) {
|
|
|
+
|
|
|
+ flagVsConfigScenario(Option4ClientFqdn::FLAG_E,
|
|
|
+ (Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_N));
|
|
|
+}
|
|
|
+
|
|
|
+// Tests the following scenario:
|
|
|
+// - Updates are enabled
|
|
|
+// - override-client-update is on.
|
|
|
+// - Client requests delegation (N = 0, S = 0)
|
|
|
+//
|
|
|
+// Server should override client's delegation request and do updates:
|
|
|
+// - Response flags should be N = 0, S = 1, O = 1
|
|
|
+// - Should queue an NCR
|
|
|
+TEST_F(NameDhcpv4SrvTest, overrideClientDelegation) {
|
|
|
+ // Turn on override-client-update.
|
|
|
+ enableD2(OVERRIDE_CLIENT_UPDATE);
|
|
|
+
|
|
|
+ flagVsConfigScenario(Option4ClientFqdn::FLAG_E,
|
|
|
+ (Option4ClientFqdn::FLAG_E |
|
|
|
+ Option4ClientFqdn::FLAG_S |
|
|
|
+ Option4ClientFqdn::FLAG_O));
|
|
|
}
|
|
|
|
|
|
// Test that server processes the Hostname option sent by a client and
|
|
@@ -447,34 +646,6 @@ TEST_F(NameDhcpv4SrvTest, serverUpdateForwardNoNameFqdn) {
|
|
|
|
|
|
}
|
|
|
|
|
|
-// Test server's response when client requests no DNS update.
|
|
|
-TEST_F(NameDhcpv4SrvTest, noUpdateFqdn) {
|
|
|
- Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
|
|
|
- Option4ClientFqdn::FLAG_E |
|
|
|
- Option4ClientFqdn::FLAG_N,
|
|
|
- "myhost.example.com.",
|
|
|
- Option4ClientFqdn::FULL,
|
|
|
- true);
|
|
|
- testProcessFqdn(query, Option4ClientFqdn::FLAG_E |
|
|
|
- Option4ClientFqdn::FLAG_N,
|
|
|
- "myhost.example.com.");
|
|
|
-}
|
|
|
-
|
|
|
-// Test that server does not accept delegation of the forward DNS update
|
|
|
-// to a client.
|
|
|
-TEST_F(NameDhcpv4SrvTest, clientUpdateNotAllowedFqdn) {
|
|
|
- Pkt4Ptr query = generatePktWithFqdn(DHCPREQUEST,
|
|
|
- Option4ClientFqdn::FLAG_E,
|
|
|
- "myhost.example.com.",
|
|
|
- Option4ClientFqdn::FULL,
|
|
|
- true);
|
|
|
-
|
|
|
- testProcessFqdn(query, Option4ClientFqdn::FLAG_E |
|
|
|
- Option4ClientFqdn::FLAG_S | Option4ClientFqdn::FLAG_O,
|
|
|
- "myhost.example.com.");
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
// Test that exactly one NameChangeRequest is generated when the new lease
|
|
|
// has been acquired (old lease is NULL).
|
|
|
TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNewLease) {
|
|
@@ -483,7 +654,7 @@ TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNewLease) {
|
|
|
Lease4Ptr old_lease;
|
|
|
|
|
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(lease, old_lease));
|
|
|
- ASSERT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
|
|
"192.0.2.3", "myhost.example.com.",
|
|
@@ -502,7 +673,7 @@ TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsRenewNoChange) {
|
|
|
old_lease->valid_lft_ += 100;
|
|
|
|
|
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(lease, old_lease));
|
|
|
- EXPECT_TRUE(srv_->name_change_reqs_.empty());
|
|
|
+ ASSERT_EQ(0, d2_mgr_.getQueueSize());
|
|
|
}
|
|
|
|
|
|
// Test that no NameChangeRequest is generated when forward and reverse
|
|
@@ -515,7 +686,7 @@ TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNoUpdate) {
|
|
|
"lease2.example.com.",
|
|
|
false, false);
|
|
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(lease2, lease1));
|
|
|
- EXPECT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ EXPECT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
|
|
|
"192.0.2.3", "lease1.example.com.",
|
|
@@ -527,7 +698,7 @@ TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNoUpdate) {
|
|
|
lease2->fqdn_rev_ = true;
|
|
|
lease2->fqdn_fwd_ = true;
|
|
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(lease2, lease1));
|
|
|
- EXPECT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ EXPECT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
|
|
|
}
|
|
|
|
|
@@ -541,7 +712,7 @@ TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsRenew) {
|
|
|
"lease2.example.com.",
|
|
|
true, true);
|
|
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(lease2, lease1));
|
|
|
- ASSERT_EQ(2, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(2, d2_mgr_.getQueueSize());
|
|
|
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
|
|
|
"192.0.2.3", "lease1.example.com.",
|
|
@@ -574,6 +745,9 @@ TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsLeaseMismatch) {
|
|
|
// Test that the OFFER message generated as a result of the DISCOVER message
|
|
|
// processing will not result in generation of the NameChangeRequests.
|
|
|
TEST_F(NameDhcpv4SrvTest, processDiscover) {
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
Pkt4Ptr req = generatePktWithFqdn(DHCPDISCOVER, Option4ClientFqdn::FLAG_S |
|
|
|
Option4ClientFqdn::FLAG_E,
|
|
|
"myhost.example.com.",
|
|
@@ -583,12 +757,15 @@ TEST_F(NameDhcpv4SrvTest, processDiscover) {
|
|
|
ASSERT_NO_THROW(reply = srv_->processDiscover(req));
|
|
|
checkResponse(reply, DHCPOFFER, 1234);
|
|
|
|
|
|
- EXPECT_TRUE(srv_->name_change_reqs_.empty());
|
|
|
+ EXPECT_EQ(0, d2_mgr_.getQueueSize());
|
|
|
}
|
|
|
|
|
|
// Test that server generates client's hostname from the IP address assigned
|
|
|
// to it when DHCPv4 Client FQDN option specifies an empty domain-name.
|
|
|
TEST_F(NameDhcpv4SrvTest, processRequestFqdnEmptyDomainName) {
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
|
|
|
Option4ClientFqdn::FLAG_E,
|
|
|
"", Option4ClientFqdn::PARTIAL, true);
|
|
@@ -599,25 +776,56 @@ TEST_F(NameDhcpv4SrvTest, processRequestFqdnEmptyDomainName) {
|
|
|
checkResponse(reply, DHCPACK, 1234);
|
|
|
|
|
|
// Verify that there is one NameChangeRequest generated.
|
|
|
- ASSERT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
+
|
|
|
// The hostname is generated from the IP address acquired (yiaddr).
|
|
|
- std::ostringstream hostname;
|
|
|
- hostname << generatedNameFromAddress(reply->getYiaddr())
|
|
|
- << ".example.com.";
|
|
|
+ std::string hostname = generatedNameFromAddress(reply->getYiaddr());
|
|
|
+
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
|
|
- reply->getYiaddr().toText(), hostname.str(),
|
|
|
+ reply->getYiaddr().toText(), hostname,
|
|
|
"", // empty DHCID forces that it is not checked
|
|
|
time(NULL) + subnet_->getValid(),
|
|
|
subnet_->getValid(), true);
|
|
|
}
|
|
|
|
|
|
// Test that server generates client's hostname from the IP address assigned
|
|
|
+// to it when DHCPv4 Client FQDN option specifies an empty domain-name AND
|
|
|
+// ddns updates are disabled.
|
|
|
+TEST_F(NameDhcpv4SrvTest, processRequestEmptyDomainNameDisabled) {
|
|
|
+ // Create fake interfaces and open fake sockets.
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
+ disableD2();
|
|
|
+ Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
|
|
|
+ Option4ClientFqdn::FLAG_E,
|
|
|
+ "", Option4ClientFqdn::PARTIAL, true);
|
|
|
+ Pkt4Ptr reply;
|
|
|
+ ASSERT_NO_THROW(reply = srv_->processRequest(req));
|
|
|
+
|
|
|
+ checkResponse(reply, DHCPACK, 1234);
|
|
|
+
|
|
|
+ Option4ClientFqdnPtr fqdn = getClientFqdnOption(reply);
|
|
|
+ ASSERT_TRUE(fqdn);
|
|
|
+
|
|
|
+ // The hostname is generated from the IP address acquired (yiaddr).
|
|
|
+ std::string hostname = generatedNameFromAddress(reply->getYiaddr());
|
|
|
+
|
|
|
+ EXPECT_EQ(hostname, fqdn->getDomainName());
|
|
|
+ EXPECT_EQ(Option4ClientFqdn::FULL, fqdn->getDomainNameType());
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// Test that server generates client's hostname from the IP address assigned
|
|
|
// to it when Hostname option carries the top level domain-name.
|
|
|
TEST_F(NameDhcpv4SrvTest, processRequestEmptyHostname) {
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
Pkt4Ptr req = generatePktWithHostname(DHCPREQUEST, ".");
|
|
|
// Set interface for the incoming packet. The server requires it to
|
|
|
// generate client id.
|
|
|
- req->setIface("eth0");
|
|
|
+ req->setIface("eth1");
|
|
|
|
|
|
Pkt4Ptr reply;
|
|
|
ASSERT_NO_THROW(reply = srv_->processRequest(req));
|
|
@@ -625,12 +833,13 @@ TEST_F(NameDhcpv4SrvTest, processRequestEmptyHostname) {
|
|
|
checkResponse(reply, DHCPACK, 1234);
|
|
|
|
|
|
// Verify that there is one NameChangeRequest generated.
|
|
|
- ASSERT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
+
|
|
|
// The hostname is generated from the IP address acquired (yiaddr).
|
|
|
- std::ostringstream hostname;
|
|
|
- hostname << generatedNameFromAddress(reply->getYiaddr()) << ".example.com.";
|
|
|
+ std::string hostname = generatedNameFromAddress(reply->getYiaddr());
|
|
|
+
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
|
|
- reply->getYiaddr().toText(), hostname.str(),
|
|
|
+ reply->getYiaddr().toText(), hostname,
|
|
|
"", // empty DHCID forces that it is not checked
|
|
|
time(NULL), subnet_->getValid(), true);
|
|
|
}
|
|
@@ -640,6 +849,9 @@ TEST_F(NameDhcpv4SrvTest, processRequestEmptyHostname) {
|
|
|
// request but modify the DNS entries for the lease according to the contents
|
|
|
// of the FQDN sent in the second request.
|
|
|
TEST_F(NameDhcpv4SrvTest, processTwoRequestsFqdn) {
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
Pkt4Ptr req1 = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
|
|
|
Option4ClientFqdn::FLAG_E,
|
|
|
"myhost.example.com.",
|
|
@@ -651,7 +863,7 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsFqdn) {
|
|
|
checkResponse(reply, DHCPACK, 1234);
|
|
|
|
|
|
// Verify that there is one NameChangeRequest generated.
|
|
|
- ASSERT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
|
|
reply->getYiaddr().toText(), "myhost.example.com.",
|
|
|
"00010132E91AA355CFBB753C0F0497A5A940436"
|
|
@@ -671,7 +883,7 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsFqdn) {
|
|
|
checkResponse(reply, DHCPACK, 1234);
|
|
|
|
|
|
// There should be two NameChangeRequests. Verify that they are valid.
|
|
|
- ASSERT_EQ(2, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(2, d2_mgr_.getQueueSize());
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
|
|
|
reply->getYiaddr().toText(),
|
|
|
"myhost.example.com.",
|
|
@@ -692,11 +904,14 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsFqdn) {
|
|
|
// but modify the DNS entries for the lease according to the contents of the
|
|
|
// Hostname sent in the second request.
|
|
|
TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
Pkt4Ptr req1 = generatePktWithHostname(DHCPREQUEST, "myhost.example.com.");
|
|
|
|
|
|
// Set interface for the incoming packet. The server requires it to
|
|
|
// generate client id.
|
|
|
- req1->setIface("eth0");
|
|
|
+ req1->setIface("eth1");
|
|
|
|
|
|
|
|
|
Pkt4Ptr reply;
|
|
@@ -705,7 +920,7 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
|
|
|
checkResponse(reply, DHCPACK, 1234);
|
|
|
|
|
|
// Verify that there is one NameChangeRequest generated.
|
|
|
- ASSERT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
|
|
reply->getYiaddr().toText(), "myhost.example.com.",
|
|
|
"00010132E91AA355CFBB753C0F0497A5A940436"
|
|
@@ -719,14 +934,14 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
|
|
|
|
|
|
// Set interface for the incoming packet. The server requires it to
|
|
|
// generate client id.
|
|
|
- req2->setIface("eth0");
|
|
|
+ req2->setIface("eth1");
|
|
|
|
|
|
ASSERT_NO_THROW(reply = srv_->processRequest(req2));
|
|
|
|
|
|
checkResponse(reply, DHCPACK, 1234);
|
|
|
|
|
|
// There should be two NameChangeRequests. Verify that they are valid.
|
|
|
- ASSERT_EQ(2, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(2, d2_mgr_.getQueueSize());
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
|
|
|
reply->getYiaddr().toText(),
|
|
|
"myhost.example.com.",
|
|
@@ -742,40 +957,83 @@ TEST_F(NameDhcpv4SrvTest, processTwoRequestsHostname) {
|
|
|
time(NULL), subnet_->getValid(), true);
|
|
|
}
|
|
|
|
|
|
-// Test that when the Release message is sent for the previously acquired
|
|
|
-// lease, then server genenerates a NameChangeRequest to remove the entries
|
|
|
-// corresponding to the lease being released.
|
|
|
+// Test that when a release message is sent for a previously acquired lease,
|
|
|
+// DDNS updates are enabled that the server genenerates a NameChangeRequest
|
|
|
+// to remove entries corresponding to the released lease.
|
|
|
TEST_F(NameDhcpv4SrvTest, processRequestRelease) {
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
+ // Verify the updates are enabled.
|
|
|
+ ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
|
|
|
+
|
|
|
+ // Create and process a lease request so we have a lease to release.
|
|
|
Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
|
|
|
Option4ClientFqdn::FLAG_E,
|
|
|
"myhost.example.com.",
|
|
|
Option4ClientFqdn::FULL, true);
|
|
|
-
|
|
|
Pkt4Ptr reply;
|
|
|
ASSERT_NO_THROW(reply = srv_->processRequest(req));
|
|
|
-
|
|
|
checkResponse(reply, DHCPACK, 1234);
|
|
|
|
|
|
- // Verify that there is one NameChangeRequest generated.
|
|
|
- ASSERT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ // Verify that there is one NameChangeRequest generated for lease.
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
|
|
reply->getYiaddr().toText(), "myhost.example.com.",
|
|
|
"00010132E91AA355CFBB753C0F0497A5A940436"
|
|
|
"965B68B6D438D98E680BF10B09F3BCF",
|
|
|
time(NULL), subnet_->getValid(), true);
|
|
|
|
|
|
- // Create a Release message.
|
|
|
+ // Create and process the Release message.
|
|
|
Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
|
|
|
rel->setCiaddr(reply->getYiaddr());
|
|
|
rel->setRemoteAddr(IOAddress("192.0.2.3"));
|
|
|
rel->addOption(generateClientId());
|
|
|
rel->addOption(srv_->getServerID());
|
|
|
-
|
|
|
ASSERT_NO_THROW(srv_->processRelease(rel));
|
|
|
|
|
|
// The lease has been removed, so there should be a NameChangeRequest to
|
|
|
// remove corresponding DNS entries.
|
|
|
- ASSERT_EQ(1, srv_->name_change_reqs_.size());
|
|
|
+ ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
|
|
+ verifyNameChangeRequest(isc::dhcp_ddns::CHG_REMOVE, true, true,
|
|
|
+ reply->getYiaddr().toText(), "myhost.example.com.",
|
|
|
+ "00010132E91AA355CFBB753C0F0497A5A940436"
|
|
|
+ "965B68B6D438D98E680BF10B09F3BCF",
|
|
|
+ time(NULL), subnet_->getValid(), true);
|
|
|
+}
|
|
|
+
|
|
|
+// Test that when the Release message is sent for a previously acquired lease
|
|
|
+// and DDNS updates are disabled that server does NOT generate a
|
|
|
+// NameChangeRequest to remove entries corresponding to the released lease.
|
|
|
+// Queue size is not available when updates are not enabled, however,
|
|
|
+// attempting to send a NCR when updates disabled will result in a throw.
|
|
|
+// If no throws are experienced then no attempt was made to send a NCR.
|
|
|
+TEST_F(NameDhcpv4SrvTest, processRequestReleaseUpdatesDisabled) {
|
|
|
+ // Create fake interfaces and open fake sockets.
|
|
|
+ IfaceMgrTestConfig test_config(true);
|
|
|
+ IfaceMgr::instance().openSockets4();
|
|
|
+
|
|
|
+ // Disable DDNS.
|
|
|
+ disableD2();
|
|
|
+ ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
|
|
|
+
|
|
|
+ // Create and process a lease request so we have a lease to release.
|
|
|
+ Pkt4Ptr req = generatePktWithFqdn(DHCPREQUEST, Option4ClientFqdn::FLAG_S |
|
|
|
+ Option4ClientFqdn::FLAG_E,
|
|
|
+ "myhost.example.com.",
|
|
|
+ Option4ClientFqdn::FULL, true);
|
|
|
+ Pkt4Ptr reply;
|
|
|
+ ASSERT_NO_THROW(reply = srv_->processRequest(req));
|
|
|
+ checkResponse(reply, DHCPACK, 1234);
|
|
|
+
|
|
|
+ // Create and process the Release message.
|
|
|
+ Pkt4Ptr rel = Pkt4Ptr(new Pkt4(DHCPRELEASE, 1234));
|
|
|
+ rel->setCiaddr(reply->getYiaddr());
|
|
|
+ rel->setRemoteAddr(IOAddress("192.0.2.3"));
|
|
|
+ rel->addOption(generateClientId());
|
|
|
+ rel->addOption(srv_->getServerID());
|
|
|
+ ASSERT_NO_THROW(srv_->processRelease(rel));
|
|
|
}
|
|
|
|
|
|
+
|
|
|
} // end of anonymous namespace
|