#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>
namespace {
- class NameDhcpv4SrvTest : public Dhcpv4SrvFakeIfaceTest {
+ class NameDhcpv4SrvTest : public Dhcpv4SrvTest {
public:
-
+ // 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() : Dhcpv4SrvFakeIfaceTest() {
+ NameDhcpv4SrvTest() : Dhcpv4SrvTest() {
srv_ = new NakedDhcpv4Srv(0);
+ // Config DDNS to be enabled, all controls off
+ enableD2();
}
+
virtual ~NameDhcpv4SrvTest() {
delete srv_;
}
srv_->name_change_reqs_.pop();
}
+
+ /// @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);
+
+ // 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, srv_->name_change_reqs_.size());
+ } else {
+ // Verify that there is one NameChangeRequest generated as expected.
+ ASSERT_EQ(1, srv_->name_change_reqs_.size());
+ 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_;
};
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) {
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.",
// The lease has been removed, so there should be a NameChangeRequest to
// remove corresponding DNS entries.
ASSERT_EQ(1, srv_->name_change_reqs_.size());
+ 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.
+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);
+
+ // With DDNS updates disabled, there should be not be a NameChangeRequest
+ // for the add.
+ ASSERT_EQ(0, srv_->name_change_reqs_.size());
+
+ // 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));
+
+ // With DDNS updates disabled, there should be not be a NameChangeRequest
+ // for the remove.
+ ASSERT_EQ(0, srv_->name_change_reqs_.size());
}
+
} // end of anonymous namespace