mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[3689] Added host reservation tests
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc added tests: TEST_F(Dhcpv6SrvTest, hostReservationWithHostName) TEST_F(Dhcpv6SrvTest, hostReservationWithoutHostName) src/bin/dhcp6/tests/dhcp6_test_utils.h src/bin/dhcp6/tests/dhcp6_test_utils.cc Dhcpv6SrvTest::createHost6() - this method was moved here from FqdnDhcpv6SrvTest() src/bin/dhcp6/tests/fqdn_unittest.cc added tests: TEST_F(FqdnDhcpv6SrvTest, hostnameReservationSuffix) TEST_F(FqdnDhcpv6SrvTest, hostnameReservationNoSuffix) TEST_F(FqdnDhcpv6SrvTest, hostnameReservationDdnsDisabled)
This commit is contained in:
@@ -2094,7 +2094,123 @@ TEST_F(Dhcpv6SrvTest, relayOverrideAndClientClass) {
|
|||||||
EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol));
|
EXPECT_TRUE(subnet1 == srv_.selectSubnet(sol));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that a host reservation is used and that the lease name is set to
|
||||||
|
// the reservation hostname.
|
||||||
|
TEST_F(Dhcpv6SrvTest, hostReservationWithHostName) {
|
||||||
|
// set duid_ for createHost6
|
||||||
|
generateClientId();
|
||||||
|
|
||||||
|
// create host reservation
|
||||||
|
IOAddress res_address("2001:db8:1:1::babe");
|
||||||
|
createHost6(true, IPv6Resrv::TYPE_NA, res_address, "alice");
|
||||||
|
|
||||||
|
// Let's create a REQUEST
|
||||||
|
Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
|
||||||
|
req->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||||
|
req->setIface("eth0");
|
||||||
|
boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
|
||||||
|
|
||||||
|
// with a valid hint
|
||||||
|
IOAddress hint("2001:db8:1:1::dead:beef");
|
||||||
|
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
|
||||||
|
|
||||||
|
OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
|
||||||
|
ia->addOption(hint_opt);
|
||||||
|
req->addOption(ia);
|
||||||
|
|
||||||
|
// Set client id to match duid_
|
||||||
|
OptionPtr clientid = generateClientId();
|
||||||
|
req->addOption(clientid);
|
||||||
|
|
||||||
|
// server-id is mandatory in REQUEST
|
||||||
|
req->addOption(srv_.getServerID());
|
||||||
|
|
||||||
|
// Pass it to the server and hope for a REPLY
|
||||||
|
Pkt6Ptr reply = srv_.processRequest(req);
|
||||||
|
|
||||||
|
// check if we get response at all
|
||||||
|
checkResponse(reply, DHCPV6_REPLY, 1234);
|
||||||
|
|
||||||
|
OptionPtr tmp = reply->getOption(D6O_IA_NA);
|
||||||
|
ASSERT_TRUE(tmp);
|
||||||
|
|
||||||
|
// check that IA_NA was returned and that there's an address included
|
||||||
|
boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234,
|
||||||
|
subnet_->getT1(),
|
||||||
|
subnet_->getT2());
|
||||||
|
ASSERT_TRUE(addr);
|
||||||
|
|
||||||
|
// check that we've got the address we requested
|
||||||
|
checkIAAddr(addr, res_address, Lease::TYPE_NA);
|
||||||
|
|
||||||
|
// check that the lease is really in the database
|
||||||
|
Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
|
||||||
|
ASSERT_TRUE(l);
|
||||||
|
|
||||||
|
// Verify that lease hostname matches the reservation name
|
||||||
|
EXPECT_EQ("alice", l->hostname_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that a host reservation is used and that the lease name is blank
|
||||||
|
// when the reservation hostname is blank.
|
||||||
|
TEST_F(Dhcpv6SrvTest, hostReservationWithoutHostName) {
|
||||||
|
// set duid_ for createHost6
|
||||||
|
generateClientId();
|
||||||
|
|
||||||
|
// create host reservation
|
||||||
|
IOAddress res_address("2001:db8:1:1::babe");
|
||||||
|
createHost6(true, IPv6Resrv::TYPE_NA, res_address, "");
|
||||||
|
|
||||||
|
// Let's create a REQUEST
|
||||||
|
Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
|
||||||
|
req->setRemoteAddr(IOAddress("fe80::abcd"));
|
||||||
|
req->setIface("eth0");
|
||||||
|
boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, 234, 1500, 3000);
|
||||||
|
|
||||||
|
// with a valid hint
|
||||||
|
IOAddress hint("2001:db8:1:1::dead:beef");
|
||||||
|
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, hint));
|
||||||
|
|
||||||
|
OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
|
||||||
|
ia->addOption(hint_opt);
|
||||||
|
req->addOption(ia);
|
||||||
|
|
||||||
|
// Set client id to match duid_
|
||||||
|
OptionPtr clientid = generateClientId();
|
||||||
|
req->addOption(clientid);
|
||||||
|
|
||||||
|
// server-id is mandatory in REQUEST
|
||||||
|
req->addOption(srv_.getServerID());
|
||||||
|
|
||||||
|
// Pass it to the server and hope for a REPLY
|
||||||
|
Pkt6Ptr reply = srv_.processRequest(req);
|
||||||
|
|
||||||
|
// check if we get response at all
|
||||||
|
checkResponse(reply, DHCPV6_REPLY, 1234);
|
||||||
|
|
||||||
|
OptionPtr tmp = reply->getOption(D6O_IA_NA);
|
||||||
|
ASSERT_TRUE(tmp);
|
||||||
|
|
||||||
|
// check that IA_NA was returned and that there's an address included
|
||||||
|
boost::shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234,
|
||||||
|
subnet_->getT1(),
|
||||||
|
subnet_->getT2());
|
||||||
|
ASSERT_TRUE(addr);
|
||||||
|
|
||||||
|
// check that we've got the address we requested
|
||||||
|
checkIAAddr(addr, res_address, Lease::TYPE_NA);
|
||||||
|
|
||||||
|
// check that the lease is really in the database
|
||||||
|
Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
|
||||||
|
ASSERT_TRUE(l);
|
||||||
|
|
||||||
|
// Verify that lease hostname matches the reservation name
|
||||||
|
EXPECT_EQ("", l->hostname_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
|
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
|
||||||
/// to call processX() methods.
|
/// to call processX() methods.
|
||||||
|
|
||||||
|
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
|
@@ -77,6 +77,40 @@ Dhcpv6SrvTest::checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
|
|||||||
return (addr);
|
return (addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Utility function that creates a host reservation (duid)
|
||||||
|
///
|
||||||
|
/// @param add_to_host_mgr true if the reservation should be added
|
||||||
|
/// @param type specifies reservation type (NA or PD)
|
||||||
|
/// @param addr specifies reserved address
|
||||||
|
/// @param hostname specifies hostname to be used in reservation
|
||||||
|
/// @return created Host object.
|
||||||
|
HostPtr
|
||||||
|
Dhcpv6SrvTest::createHost6(bool add_to_host_mgr, IPv6Resrv::Type type,
|
||||||
|
const asiolink::IOAddress& addr, const std::string& hostname) {
|
||||||
|
HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
|
||||||
|
Host::IDENT_DUID, SubnetID(0), subnet_->getID(),
|
||||||
|
asiolink::IOAddress("0.0.0.0"), hostname));
|
||||||
|
|
||||||
|
// Prefix length doesn't matter here, let's assume address is /128 and
|
||||||
|
// prefix is /64
|
||||||
|
IPv6Resrv resv(type, addr, type == IPv6Resrv::TYPE_NA? 128 : 64);
|
||||||
|
host->addReservation(resv);
|
||||||
|
|
||||||
|
if (add_to_host_mgr) {
|
||||||
|
|
||||||
|
// Let's add the host.
|
||||||
|
CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
|
||||||
|
|
||||||
|
// We also need to add existing subnet
|
||||||
|
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
|
||||||
|
|
||||||
|
// Commit this configuration.
|
||||||
|
CfgMgr::instance().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (host);
|
||||||
|
}
|
||||||
|
|
||||||
boost::shared_ptr<Option6IAPrefix>
|
boost::shared_ptr<Option6IAPrefix>
|
||||||
Dhcpv6SrvTest::checkIA_PD(const Pkt6Ptr& rsp, uint32_t expected_iaid,
|
Dhcpv6SrvTest::checkIA_PD(const Pkt6Ptr& rsp, uint32_t expected_iaid,
|
||||||
uint32_t expected_t1, uint32_t expected_t2) {
|
uint32_t expected_t1, uint32_t expected_t2) {
|
||||||
|
@@ -345,6 +345,17 @@ public:
|
|||||||
/// @param srv Server to be configured.
|
/// @param srv Server to be configured.
|
||||||
void configure(const std::string& config, NakedDhcpv6Srv& srv);
|
void configure(const std::string& config, NakedDhcpv6Srv& srv);
|
||||||
|
|
||||||
|
/// @brief Utility function that creates a host reservation (duid)
|
||||||
|
///
|
||||||
|
/// @param add_to_host_mgr true if the reservation should be added
|
||||||
|
/// @param type specifies reservation type (NA or PD)
|
||||||
|
/// @param addr specifies reserved address
|
||||||
|
/// @param hostname specifies hostname to be used in reservation
|
||||||
|
/// @return created Host object.
|
||||||
|
isc::dhcp::HostPtr
|
||||||
|
createHost6(bool add_to_host_mgr, isc::dhcp::IPv6Resrv::Type type,
|
||||||
|
const asiolink::IOAddress& addr, const std::string& hostname);
|
||||||
|
|
||||||
/// @brief Checks that server response (ADVERTISE or REPLY) contains proper
|
/// @brief Checks that server response (ADVERTISE or REPLY) contains proper
|
||||||
/// IA_NA option
|
/// IA_NA option
|
||||||
///
|
///
|
||||||
|
@@ -507,40 +507,6 @@ public:
|
|||||||
ASSERT_NO_THROW(d2_mgr_.runReadyIO());
|
ASSERT_NO_THROW(d2_mgr_.runReadyIO());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Utility function that creates a host reservation (duid)
|
|
||||||
///
|
|
||||||
/// @param add_to_host_mgr true if the reservation should be added
|
|
||||||
/// @param type specifies reservation type (NA or PD)
|
|
||||||
/// @param addr specifies reserved address
|
|
||||||
/// @param hostname specifies hostname to be used in reservation
|
|
||||||
/// @return created Host object.
|
|
||||||
HostPtr
|
|
||||||
createHost6(bool add_to_host_mgr, IPv6Resrv::Type type,
|
|
||||||
const asiolink::IOAddress& addr, const std::string& hostname) {
|
|
||||||
HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
|
|
||||||
Host::IDENT_DUID, SubnetID(0), subnet_->getID(),
|
|
||||||
asiolink::IOAddress("0.0.0.0"),
|
|
||||||
hostname));
|
|
||||||
|
|
||||||
// Prefix length doesn't matter here, let's assume address is /128 and
|
|
||||||
// prefix is /64
|
|
||||||
IPv6Resrv resv(type, addr, type == IPv6Resrv::TYPE_NA? 128 : 64);
|
|
||||||
host->addReservation(resv);
|
|
||||||
|
|
||||||
if (add_to_host_mgr) {
|
|
||||||
|
|
||||||
// Let's add the host.
|
|
||||||
CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
|
|
||||||
|
|
||||||
// We also need to add existing subnet
|
|
||||||
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(subnet_);
|
|
||||||
|
|
||||||
// Commit this configuration.
|
|
||||||
CfgMgr::instance().commit();
|
|
||||||
}
|
|
||||||
return (host);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Holds a lease used by a test.
|
// Holds a lease used by a test.
|
||||||
Lease6Ptr lease_;
|
Lease6Ptr lease_;
|
||||||
|
|
||||||
@@ -1088,15 +1054,114 @@ TEST_F(FqdnDhcpv6SrvTest, processClientDelegation) {
|
|||||||
0, 4000);
|
0, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FqdnDhcpv6SrvTest, hostnameReservation) {
|
// Verify that the host reservation is found and used. Lease host name and
|
||||||
|
// FQDN should be the reservation hostname suffixed by the qualifying suffix.
|
||||||
|
TEST_F(FqdnDhcpv6SrvTest, hostnameReservationSuffix) {
|
||||||
|
// Create host reservation with a partial FQDN for hostname
|
||||||
createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1:1::babe"),
|
createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1:1::babe"),
|
||||||
"alice.example.org.");
|
"alice");
|
||||||
|
|
||||||
|
// Verify that the host reservation is found and lease name/FQDN are
|
||||||
|
// formed properly from the host name and qualifying suffix.
|
||||||
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
|
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
|
||||||
"alice.example.org.", 0, IOAddress("2001:db8:1:1::babe"));
|
"alice.example.com.", 0, IOAddress("2001:db8:1:1::babe"));
|
||||||
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that the host reservation is found and used, rather than dynamic
|
||||||
|
// Address. Lease host name and FQDN should be the reservation hostname
|
||||||
|
// without a qualifying suffix.
|
||||||
|
TEST_F(FqdnDhcpv6SrvTest, hostnameReservationNoSuffix) {
|
||||||
|
|
||||||
|
string config_str = "{ "
|
||||||
|
"\"interfaces-config\": {"
|
||||||
|
" \"interfaces\": [ \"*\" ]"
|
||||||
|
"},"
|
||||||
|
"\"preferred-lifetime\": 3000,"
|
||||||
|
"\"valid-lifetime\": 4000,"
|
||||||
|
"\"rebind-timer\": 2000, "
|
||||||
|
"\"renew-timer\": 1000, "
|
||||||
|
"\"subnet6\": [ { "
|
||||||
|
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||||
|
" \"subnet\": \"2001:db8:1::/64\" } ], "
|
||||||
|
" \"dhcp-ddns\" : {"
|
||||||
|
" \"enable-updates\" : true, "
|
||||||
|
" \"server-ip\" : \"::1\", "
|
||||||
|
" \"server-port\" : 53001, "
|
||||||
|
" \"sender-ip\" : \"::\", "
|
||||||
|
" \"sender-port\" : 0, "
|
||||||
|
" \"max-queue-size\" : 2048, "
|
||||||
|
" \"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\" : \"\" },"
|
||||||
|
"\"valid-lifetime\": 4000 }";
|
||||||
|
|
||||||
|
configure(config_str);
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(srv_->startD2());
|
||||||
|
|
||||||
|
ASSERT_TRUE(CfgMgr::instance().ddnsEnabled());
|
||||||
|
|
||||||
|
createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1:1::babe"),
|
||||||
|
"alice.example.com");
|
||||||
|
|
||||||
|
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
|
||||||
|
"alice.example.com.", 0, IOAddress("2001:db8:1:1::babe"));
|
||||||
|
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the host reservation is found and used, rather than dynamic
|
||||||
|
// Address. Lease host name and FQDN should be the reservation hostname
|
||||||
|
// with the qualifying suffix even though updates are disabled.
|
||||||
|
TEST_F(FqdnDhcpv6SrvTest, hostnameReservationDdnsDisabled) {
|
||||||
|
|
||||||
|
string config_str = "{ "
|
||||||
|
"\"interfaces-config\": {"
|
||||||
|
" \"interfaces\": [ \"*\" ]"
|
||||||
|
"},"
|
||||||
|
"\"preferred-lifetime\": 3000,"
|
||||||
|
"\"valid-lifetime\": 4000,"
|
||||||
|
"\"rebind-timer\": 2000, "
|
||||||
|
"\"renew-timer\": 1000, "
|
||||||
|
"\"subnet6\": [ { "
|
||||||
|
" \"pools\": [ { \"pool\": \"2001:db8:1::/80\" } ],"
|
||||||
|
" \"subnet\": \"2001:db8:1::/64\" } ], "
|
||||||
|
" \"dhcp-ddns\" : {"
|
||||||
|
" \"enable-updates\" : false, "
|
||||||
|
" \"server-ip\" : \"::1\", "
|
||||||
|
" \"server-port\" : 53001, "
|
||||||
|
" \"sender-ip\" : \"::\", "
|
||||||
|
" \"sender-port\" : 0, "
|
||||||
|
" \"max-queue-size\" : 2048, "
|
||||||
|
" \"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\" : \"disabled.example.com\" },"
|
||||||
|
"\"valid-lifetime\": 4000 }";
|
||||||
|
|
||||||
|
configure(config_str);
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(srv_->startD2());
|
||||||
|
|
||||||
|
ASSERT_FALSE(CfgMgr::instance().ddnsEnabled());
|
||||||
|
|
||||||
|
createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1:1::babe"),
|
||||||
|
"alice");
|
||||||
|
|
||||||
|
testProcessMessage(DHCPV6_REQUEST, "myhost.example.com",
|
||||||
|
"alice.disabled.example.com.", 0,
|
||||||
|
IOAddress("2001:db8:1:1::babe"));
|
||||||
|
}
|
||||||
|
|
||||||
} // end of anonymous namespace
|
} // end of anonymous namespace
|
||||||
|
Reference in New Issue
Block a user