mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-05 08:25:16 +00:00
[#1386] ddns-use-conflict-resolution works end-to-end
kea-dhcp<4/6> now populate NameChangeRequest::conflict_resolution_ with the appropriate value. src/bin/dhcp6/dhcp6_srv.cc Dhcpv6Srv::createNameChangeRequests() - set use conflict resolution in explictly created NameChangeRequest src/lib/dhcpsrv/ncr_generator.cc queueNCRCommon() - added use_conflict_resolution parameter queueNCR(const NameChangeType& chg_type, const Lease4Ptr& lease) queueNCR(const NameChangeType& chg_type, const Lease6Ptr& lease) - set conflict resolution flag from lease's subnet src/bin/dhcp4/tests/fqdn_unittest.cc TEST_F(NameDhcpv4SrvTest, noConflictResolution) src/bin/dhcp6/tests/fqdn_unittest.cc TEST_F(FqdnDhcpv6SrvTest, noConflictResolution) src/lib/dhcpsrv/tests/ncr_generator_unittest.cc udpated to create subnets and attach them to leases TEST_F(NCRGenerator6Test, useConflictResolution) TEST_F(NCRGenerator4Test, useConflictResolution) - new tests
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
1824. [func] tmark
|
||||
Added a new parameter, ddns-use-conflict-resolution, to
|
||||
kea-dhcp4 and kea-dhcp6. This parameter is passed per request
|
||||
to kea-dhcp-ddns which uses it to determine whether or not
|
||||
conflict resolution rules (see RFC 4703) are followed for that
|
||||
request. The default value is true. Disabling conflict
|
||||
resolution should only be used after careful consideration.
|
||||
(Gitlab #1386)
|
||||
|
||||
1823. [doc] tomek
|
||||
Updated options documentation for DHCPv4 and DHCPv6.
|
||||
(Gitlab #1436, #1460)
|
||||
|
@@ -384,6 +384,7 @@ public:
|
||||
: D2ClientConfig::RCM_NEVER);
|
||||
subnet_->setDdnsGeneratedPrefix("myhost");
|
||||
subnet_->setDdnsQualifyingSuffix("example.com");
|
||||
subnet_->setDdnsUseConflictResolution(true);
|
||||
|
||||
ASSERT_NO_THROW(srv_->startD2());
|
||||
}
|
||||
@@ -756,7 +757,8 @@ public:
|
||||
const std::string& dhcid,
|
||||
const time_t cltt,
|
||||
const uint16_t len,
|
||||
const bool not_strict_expire_check = false) {
|
||||
const bool not_strict_expire_check = false,
|
||||
const bool exp_use_cr = true) {
|
||||
NameChangeRequestPtr ncr;
|
||||
ASSERT_NO_THROW(ncr = d2_mgr_.peekAt(0));
|
||||
ASSERT_TRUE(ncr);
|
||||
@@ -783,6 +785,7 @@ public:
|
||||
}
|
||||
EXPECT_EQ(len, ncr->getLeaseLength());
|
||||
EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr->getStatus());
|
||||
EXPECT_EQ(exp_use_cr, ncr->useConflictResolution());
|
||||
|
||||
// Process the message off the queue
|
||||
ASSERT_NO_THROW(d2_mgr_.runReadyIO());
|
||||
@@ -1072,6 +1075,27 @@ TEST_F(NameDhcpv4SrvTest, createNameChangeRequestsNewLease) {
|
||||
lease->cltt_, 100);
|
||||
}
|
||||
|
||||
// Verify that conflict resolution is disabled in the NCR when it is
|
||||
// disabled for the lease's subnet.
|
||||
TEST_F(NameDhcpv4SrvTest, noConflictResolution) {
|
||||
Lease4Ptr lease = createLease(IOAddress("192.0.2.3"), "myhost.example.com.",
|
||||
true, true);
|
||||
Lease4Ptr old_lease;
|
||||
|
||||
ASSERT_TRUE(getDdnsParams()->getEnableUpdates());
|
||||
subnet_->setDdnsUseConflictResolution(false);
|
||||
|
||||
ASSERT_NO_THROW(srv_->createNameChangeRequests(lease, old_lease, *getDdnsParams()));
|
||||
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
||||
|
||||
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
||||
"192.0.2.3", "myhost.example.com.",
|
||||
"00010132E91AA355CFBB753C0F0497A5A940436965"
|
||||
"B68B6D438D98E680BF10B09F3BCF",
|
||||
lease->cltt_, 100, false, false);
|
||||
}
|
||||
|
||||
|
||||
// Verifies that createNameChange request only generates requests
|
||||
// if the situation dictates that it should. It checks:
|
||||
//
|
||||
|
@@ -1931,8 +1931,8 @@ Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer,
|
||||
do_fwd, do_rev,
|
||||
opt_fqdn->getDomainName(),
|
||||
iaaddr->getAddress().toText(),
|
||||
dhcid, 0, iaaddr->getValid()));
|
||||
|
||||
dhcid, 0, iaaddr->getValid(),
|
||||
ctx.getDdnsParams()->getUseConflictResolution()));
|
||||
LOG_DEBUG(ddns6_logger, DBG_DHCP6_DETAIL,
|
||||
DHCP6_DDNS_CREATE_ADD_NAME_CHANGE_REQUEST).arg(ncr->toText());
|
||||
|
||||
|
@@ -132,6 +132,7 @@ public:
|
||||
subnet_->setDdnsQualifyingSuffix("example.com");
|
||||
subnet_->setHostnameCharSet("[^A-Za-z0-9-]");
|
||||
subnet_->setHostnameCharReplacement("x");
|
||||
subnet_->setDdnsUseConflictResolution(true);
|
||||
|
||||
ASSERT_NO_THROW(srv_->startD2());
|
||||
}
|
||||
@@ -595,13 +596,15 @@ public:
|
||||
/// NameChangeRequest.
|
||||
/// @param fqdn The expected string value of the FQDN, if blank the
|
||||
/// check is skipped
|
||||
/// @param exp_use_cr expected value of NCR::conflict_resolution_
|
||||
void verifyNameChangeRequest(const isc::dhcp_ddns::NameChangeType type,
|
||||
const bool reverse, const bool forward,
|
||||
const std::string& addr,
|
||||
const std::string& dhcid,
|
||||
const uint64_t expires,
|
||||
const uint16_t len,
|
||||
const std::string& fqdn="") {
|
||||
const std::string& fqdn = "",
|
||||
const bool exp_use_cr = true) {
|
||||
NameChangeRequestPtr ncr;
|
||||
ASSERT_NO_THROW(ncr = d2_mgr_.peekAt(0));
|
||||
ASSERT_TRUE(ncr);
|
||||
@@ -625,6 +628,7 @@ public:
|
||||
EXPECT_EQ(fqdn, ncr->getFqdn());
|
||||
}
|
||||
|
||||
EXPECT_EQ(exp_use_cr, ncr->useConflictResolution());
|
||||
|
||||
// Process the message off the queue
|
||||
ASSERT_NO_THROW(d2_mgr_.runReadyIO());
|
||||
@@ -835,6 +839,39 @@ TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequests) {
|
||||
0, 500);
|
||||
}
|
||||
|
||||
// Verify that conflict resolution is turned off when the
|
||||
// subnet has it disabled.
|
||||
TEST_F(FqdnDhcpv6SrvTest, noConflictResolution) {
|
||||
// Create Reply message with Client Id and Server id.
|
||||
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
||||
|
||||
// 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.
|
||||
AllocEngine::ClientContext6 ctx;
|
||||
subnet_->setDdnsUseConflictResolution(false);
|
||||
ctx.subnet_ = subnet_;
|
||||
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
||||
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
||||
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
||||
|
||||
// Verify that NameChangeRequest is correct.
|
||||
verifyNameChangeRequest(isc::dhcp_ddns::CHG_ADD, true, true,
|
||||
"2001:db8:1::1",
|
||||
"000201415AA33D1187D148275136FA30300478"
|
||||
"FAAAA3EBD29826B5C907B2C9268A6F52",
|
||||
0, 500, "", false);
|
||||
}
|
||||
|
||||
// Checks that NameChangeRequests to add entries are not
|
||||
// created when ddns updates are disabled.
|
||||
TEST_F(FqdnDhcpv6SrvTest, noAddRequestsWhenDisabled) {
|
||||
|
@@ -30,12 +30,15 @@ namespace {
|
||||
/// identifier. For DHCPv6 it will be a DUID.
|
||||
/// @param label Client identification information in the textual format.
|
||||
/// This is used for logging purposes.
|
||||
/// @param use_conflict_resolution flag that tells D2 whether or not to
|
||||
/// use conflict resolution.
|
||||
///
|
||||
/// @tparam LeasePtrType Pointer to a lease.
|
||||
/// @tparam IdentifierType HW Address, Client Identifier or DUID.
|
||||
template<typename LeasePtrType, typename IdentifierType>
|
||||
void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease,
|
||||
const IdentifierType& identifier, const std::string& label) {
|
||||
const IdentifierType& identifier, const std::string& label,
|
||||
const bool use_conflict_resolution = true) {
|
||||
|
||||
// Check if there is a need for update.
|
||||
if (lease->hostname_.empty() || (!lease->fqdn_fwd_ && !lease->fqdn_rev_)
|
||||
@@ -44,7 +47,7 @@ void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease,
|
||||
DHCPSRV_QUEUE_NCR_SKIP)
|
||||
.arg(label)
|
||||
.arg(lease->addr_.toText());
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -53,13 +56,12 @@ void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease,
|
||||
std::vector<uint8_t> hostname_wire;
|
||||
OptionDataTypeUtil::writeFqdn(lease->hostname_, hostname_wire, true);
|
||||
D2Dhcid dhcid = D2Dhcid(identifier, hostname_wire);
|
||||
|
||||
// Create name change request.
|
||||
NameChangeRequestPtr ncr
|
||||
(new NameChangeRequest(chg_type, lease->fqdn_fwd_, lease->fqdn_rev_,
|
||||
lease->hostname_, lease->addr_.toText(),
|
||||
dhcid, lease->cltt_ + lease->valid_lft_,
|
||||
lease->valid_lft_));
|
||||
lease->valid_lft_, use_conflict_resolution));
|
||||
|
||||
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA, DHCPSRV_QUEUE_NCR)
|
||||
.arg(label)
|
||||
@@ -85,16 +87,26 @@ namespace dhcp {
|
||||
|
||||
void queueNCR(const NameChangeType& chg_type, const Lease4Ptr& lease) {
|
||||
if (lease) {
|
||||
// Figure out from the lease's subnet if we should use conflict resolution.
|
||||
// If there's no subnet, something hinky is going on so we'll set it true.
|
||||
bool use_cr = true;
|
||||
Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg()
|
||||
->getCfgSubnets4()->getSubnet(lease->subnet_id_);
|
||||
if (subnet) {
|
||||
// We should always have subnet.
|
||||
use_cr = subnet->getDdnsUseConflictResolution();
|
||||
}
|
||||
|
||||
// Client id takes precedence over HW address.
|
||||
if (lease->client_id_) {
|
||||
queueNCRCommon(chg_type, lease, lease->client_id_->getClientId(),
|
||||
Pkt4::makeLabel(lease->hwaddr_, lease->client_id_));
|
||||
Pkt4::makeLabel(lease->hwaddr_, lease->client_id_), use_cr);
|
||||
|
||||
} else {
|
||||
// Client id is not specified for the lease. Use HW address
|
||||
// instead.
|
||||
queueNCRCommon(chg_type, lease, lease->hwaddr_,
|
||||
Pkt4::makeLabel(lease->hwaddr_, lease->client_id_));
|
||||
Pkt4::makeLabel(lease->hwaddr_, lease->client_id_), use_cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,8 +114,18 @@ void queueNCR(const NameChangeType& chg_type, const Lease4Ptr& lease) {
|
||||
void queueNCR(const NameChangeType& chg_type, const Lease6Ptr& lease) {
|
||||
// DUID is required to generate NCR.
|
||||
if (lease && (lease->type_ != Lease::TYPE_PD) && lease->duid_) {
|
||||
// Figure out from the lease's subnet if we should use conflict resolution.
|
||||
// If there's no subnet, something hinky is going on so we'll set it true.
|
||||
bool use_cr = true;
|
||||
Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()
|
||||
->getCfgSubnets6()->getSubnet(lease->subnet_id_);
|
||||
if (subnet) {
|
||||
// We should always have subnet.
|
||||
use_cr = subnet->getDdnsUseConflictResolution();
|
||||
}
|
||||
|
||||
queueNCRCommon(chg_type, lease, *(lease->duid_),
|
||||
Pkt6::makeLabel(lease->duid_, lease->hwaddr_));
|
||||
Pkt6::makeLabel(lease->duid_, lease->hwaddr_), use_cr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,9 @@ public:
|
||||
/// @brief Pointer to the lease object used by the tests.
|
||||
LeasePtrType lease_;
|
||||
|
||||
/// @brief Pointer to the lease's subnet
|
||||
SubnetPtr subnet_;
|
||||
|
||||
/// @brief Constructor.
|
||||
NCRGeneratorTest()
|
||||
: d2_mgr_(CfgMgr::instance().getD2ClientMgr()), lease_() {
|
||||
@@ -70,6 +73,8 @@ public:
|
||||
disableD2();
|
||||
// Base class TearDown.
|
||||
::testing::Test::TearDown();
|
||||
|
||||
CfgMgr::instance().clear();
|
||||
}
|
||||
|
||||
/// @brief Enables DHCP-DDNS updates.
|
||||
@@ -133,7 +138,8 @@ public:
|
||||
const std::string& dhcid,
|
||||
const uint64_t expires,
|
||||
const uint16_t len,
|
||||
const std::string& fqdn="") {
|
||||
const std::string& fqdn="",
|
||||
const bool use_conflict_resolution = true) {
|
||||
NameChangeRequestPtr ncr;
|
||||
ASSERT_NO_THROW(ncr = CfgMgr::instance().getD2ClientMgr().peekAt(0));
|
||||
ASSERT_TRUE(ncr);
|
||||
@@ -146,6 +152,7 @@ public:
|
||||
EXPECT_EQ(expires, ncr->getLeaseExpiresOn());
|
||||
EXPECT_EQ(len, ncr->getLeaseLength());
|
||||
EXPECT_EQ(isc::dhcp_ddns::ST_NEW, ncr->getStatus());
|
||||
EXPECT_EQ(use_conflict_resolution, ncr->useConflictResolution());
|
||||
|
||||
if (!fqdn.empty()) {
|
||||
EXPECT_EQ(fqdn, ncr->getFqdn());
|
||||
@@ -214,7 +221,8 @@ public:
|
||||
/// @param fqdn Hostname.
|
||||
/// @param exp_dhcid Expected DHCID.
|
||||
void testNCR(const NameChangeType chg_type, const bool fwd, const bool rev,
|
||||
const std::string& fqdn, const std::string exp_dhcid) {
|
||||
const std::string& fqdn, const std::string exp_dhcid,
|
||||
const bool conflict_resolution = true) {
|
||||
// Queue NCR.
|
||||
ASSERT_NO_FATAL_FAILURE(sendNCR(chg_type, fwd, rev, fqdn));
|
||||
// Expecting one NCR be generated.
|
||||
@@ -222,7 +230,7 @@ public:
|
||||
// Check the details of the NCR.
|
||||
verifyNameChangeRequest(chg_type, rev, fwd, lease_->addr_.toText(), exp_dhcid,
|
||||
lease_->cltt_ + lease_->valid_lft_,
|
||||
lease_->valid_lft_);
|
||||
lease_->valid_lft_, fqdn, conflict_resolution);
|
||||
}
|
||||
|
||||
/// @brief Test that calling queueNCR for NULL lease doesn't cause
|
||||
@@ -234,6 +242,7 @@ public:
|
||||
ASSERT_NO_FATAL_FAILURE(queueNCR(chg_type, lease_));
|
||||
EXPECT_EQ(0, d2_mgr_.getQueueSize());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// @brief Test fixture class implementation for DHCPv6.
|
||||
@@ -253,8 +262,21 @@ public:
|
||||
|
||||
/// @brief Implementation of the method creating DHCPv6 lease instance.
|
||||
virtual void initLease() {
|
||||
Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64, 100, 200, 300, 400));
|
||||
// Normally, this would be set via defaults
|
||||
subnet->setDdnsUseConflictResolution(true);
|
||||
|
||||
Pool6Ptr pool(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
|
||||
IOAddress("2001:db8:1::200")));
|
||||
subnet->addPool(pool);
|
||||
subnet_ = subnet;
|
||||
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet);
|
||||
cfg_mgr.commit();
|
||||
|
||||
lease_.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
|
||||
duid_, 1234, 501, 502, 1, HWAddrPtr(), 0));
|
||||
duid_, 1234, 501, 502, subnet_->getID(), HWAddrPtr()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -415,6 +437,24 @@ TEST_F(NCRGenerator6Test, nullLease) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that conflict resolution is set correctly by v6 queueNCR()
|
||||
TEST_F(NCRGenerator6Test, useConflictResolution) {
|
||||
{
|
||||
SCOPED_TRACE("Subnet flag is false");
|
||||
subnet_->setDdnsUseConflictResolution(false);
|
||||
testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
|
||||
"000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3D0ECCEA5E0DD71730F392119A",
|
||||
false);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("Subnet flag is true");
|
||||
subnet_->setDdnsUseConflictResolution(true);
|
||||
testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
|
||||
"000201BE0D7A66F8AB6C4082E7F8B81E2656667A102E3D0ECCEA5E0DD71730F392119A",
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Test fixture class implementation for DHCPv4.
|
||||
class NCRGenerator4Test : public NCRGeneratorTest<Lease4Ptr> {
|
||||
public:
|
||||
@@ -431,9 +471,24 @@ public:
|
||||
|
||||
/// @brief Implementation of the method creating DHCPv4 lease instance.
|
||||
virtual void initLease() {
|
||||
|
||||
Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
|
||||
// Normally, this would be set via defaults
|
||||
subnet->setDdnsUseConflictResolution(true);
|
||||
|
||||
Pool4Ptr pool(new Pool4(IOAddress("192.0.2.100"),
|
||||
IOAddress("192.0.2.200")));
|
||||
subnet->addPool(pool);
|
||||
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet);
|
||||
cfg_mgr.commit();
|
||||
|
||||
subnet_ = subnet;
|
||||
lease_.reset(new Lease4(IOAddress("192.0.2.1"), hwaddr_, ClientIdPtr(),
|
||||
100, time(NULL), 1));
|
||||
100, time(NULL), subnet_->getID()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Test creation of the NameChangeRequest for both forward and reverse
|
||||
@@ -599,4 +654,22 @@ TEST_F(NCRGenerator4Test, nullLease) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that conflict resolution is set correctly by v4 queueNCR()
|
||||
TEST_F(NCRGenerator4Test, useConflictResolution) {
|
||||
{
|
||||
SCOPED_TRACE("Subnet flag is false");
|
||||
subnet_->setDdnsUseConflictResolution(false);
|
||||
testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
|
||||
"000001E356D43E5F0A496D65BCA24D982D646140813E3"
|
||||
"B03AB370BFF46BFA309AE7BFD", false);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("Subnet flag is true");
|
||||
subnet_->setDdnsUseConflictResolution(true);
|
||||
testNCR(CHG_REMOVE, true, true, "MYHOST.example.com.",
|
||||
"000001E356D43E5F0A496D65BCA24D982D646140813E3"
|
||||
"B03AB370BFF46BFA309AE7BFD", true);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
Reference in New Issue
Block a user