From: Thomas Markwalder Date: Tue, 17 Mar 2015 19:58:57 +0000 (-0400) Subject: [3689] Added host reservation tests X-Git-Tag: kea-0.9.1~8^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c387c4ca70ad0b0777809b105d5e89e14652a22f;p=thirdparty%2Fkea.git [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) --- diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 983d0f8b2e..34cb9ebd41 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -2094,7 +2094,123 @@ TEST_F(Dhcpv6SrvTest, relayOverrideAndClientClass) { 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 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 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 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 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 /// to call processX() methods. + } // end of anonymous namespace diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.cc b/src/bin/dhcp6/tests/dhcp6_test_utils.cc index 98f043a76f..b225ff5359 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.cc +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.cc @@ -77,6 +77,40 @@ Dhcpv6SrvTest::checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid, 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 Dhcpv6SrvTest::checkIA_PD(const Pkt6Ptr& rsp, uint32_t expected_iaid, uint32_t expected_t1, uint32_t expected_t2) { diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index 4896d5dde1..4fc4753fc4 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h @@ -345,6 +345,17 @@ public: /// @param srv Server to be configured. 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 /// IA_NA option /// diff --git a/src/bin/dhcp6/tests/fqdn_unittest.cc b/src/bin/dhcp6/tests/fqdn_unittest.cc index 3a263b0d33..817fde1582 100644 --- a/src/bin/dhcp6/tests/fqdn_unittest.cc +++ b/src/bin/dhcp6/tests/fqdn_unittest.cc @@ -507,40 +507,6 @@ public: 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. Lease6Ptr lease_; @@ -1088,15 +1054,114 @@ TEST_F(FqdnDhcpv6SrvTest, processClientDelegation) { 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"), + "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", + "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 +// 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.org."); + "alice.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()); } +// 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