summaryrefslogtreecommitdiffstats
path: root/src/bin/dhcp6/tests/decline_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/dhcp6/tests/decline_unittest.cc')
-rw-r--r--src/bin/dhcp6/tests/decline_unittest.cc332
1 files changed, 332 insertions, 0 deletions
diff --git a/src/bin/dhcp6/tests/decline_unittest.cc b/src/bin/dhcp6/tests/decline_unittest.cc
new file mode 100644
index 0000000..92f511d
--- /dev/null
+++ b/src/bin/dhcp6/tests/decline_unittest.cc
@@ -0,0 +1,332 @@
+// Copyright (C) 2015-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <asiolink/io_address.h>
+#include <cc/data.h>
+#include <dhcp/testutils/iface_mgr_test_config.h>
+#include <dhcp6/json_config_parser.h>
+#include <dhcp6/tests/dhcp6_message_test.h>
+#include <dhcpsrv/lease.h>
+#include <stats/stats_mgr.h>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::stats;
+
+namespace {
+
+/// @brief Set of JSON configurations used throughout the Renew tests.
+///
+/// - Configuration 0:
+/// - only addresses (no prefixes)
+/// - 1 subnet with 2001:db8:1::/64 pool
+const char* DECLINE_CONFIGS[] = {
+// Configuration 0
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"id\": 1, "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface-id\": \"\","
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 }",
+// Configuration 1 - only use when mysql is enabled
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"lease-database\": {"
+ "\"type\": \"mysql\","
+ "\"name\": \"keatest\","
+ "\"user\": \"keatest\","
+ "\"password\": \"keatest\""
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"id\": 1, "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface-id\": \"\","
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 }",
+// Configuration 2 - only use when pgsql is enabled
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"lease-database\": {"
+ "\"type\": \"postgresql\","
+ "\"name\": \"keatest\","
+ "\"user\": \"keatest\","
+ "\"password\": \"keatest\""
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"id\": 1, "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface-id\": \"\","
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 }"
+};
+
+/// @brief Test fixture class for testing Renew.
+class DeclineTest : public Dhcpv6MessageTest {
+public:
+
+ /// @brief Constructor.
+ ///
+ /// Sets up fake interfaces.
+ DeclineTest()
+ : Dhcpv6MessageTest(), na_iaid_(1234) {
+ }
+
+ /// @brief IAID used for IA_NA.
+ uint32_t na_iaid_;
+};
+
+}
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+void
+Dhcpv6SrvTest::acquireAndDecline(Dhcp6Client& client,
+ const std::string& duid1,
+ const uint32_t iaid1,
+ const std::string& duid2,
+ const uint32_t iaid2,
+ AddressInclusion addr_type,
+ ExpectedResult expected_result,
+ uint8_t config_index) {
+ // Set this global statistic explicitly to zero.
+ StatsMgr::instance().setValue("declined-addresses", static_cast<int64_t>(0));
+
+ client.setDUID(duid1);
+ client.requestAddress(iaid1);
+
+ // Configure the server with a configuration.
+ ASSERT_NO_THROW(configure(DECLINE_CONFIGS[config_index], *client.getServer()));
+
+ // Let's get the subnet-id and generate statistics name out of it.
+ const Subnet6Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
+ ASSERT_EQ(1, subnets->size());
+
+ // Let's generate the subnet specific statistic
+ std::string name = StatsMgr::generateName("subnet",
+ (*subnets->begin())->getID(),
+ "declined-addresses");
+
+ // Set this statistic explicitly to zero.
+ StatsMgr::instance().setValue(name, static_cast<int64_t>(0));
+
+ // Perform 4-way exchange.
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Make sure that the client has acquired NA lease.
+ std::vector<Lease6> leases_client_na = client.getLeasesByType(Lease::TYPE_NA);
+ ASSERT_EQ(1, leases_client_na.size());
+ EXPECT_EQ(STATUS_Success, client.getStatusCode(iaid1));
+
+ // Remember the acquired address.
+ IOAddress acquired_address = leases_client_na[0].addr_;
+
+ // Check the declined-addresses (subnet) before the Decline operation.
+ ObservationPtr declined_cnt = StatsMgr::instance().getObservation(name);
+ ASSERT_TRUE(declined_cnt);
+ uint64_t before = declined_cnt->getInteger().first;
+
+ // Check the global declined-addresses statistic before the Decline.
+ ObservationPtr declined_global = StatsMgr::instance()
+ .getObservation("declined-addresses");
+ ASSERT_TRUE(declined_global);
+ uint64_t before_global = declined_cnt->getInteger().first;
+
+ /// Determines if the client will include address in the messages it sends.
+ bool include_address_ = true;
+
+ // Let's tamper with the address if necessary.
+ switch (addr_type) {
+ case VALID_ADDR:
+ // Nothing to do, client will do its job correctly by default
+ break;
+ case BOGUS_ADDR:
+ // Simple increase by one.
+ client.config_.leases_[0].addr_ =
+ IOAddress::increase(client.config_.leases_[0].addr_);
+ break;
+ case NO_ADDR:
+ // Tell the client to not include an address in its IA_NA
+ include_address_ = false;
+ break;
+ case NO_IA:
+ // Tell the client to not include IA_NA at all
+ client.config_.clear();
+ client.clearRequestedIAs();
+ }
+
+ // Use the second duid
+ client.setDUID(duid2);
+
+ // Use the second IAID (but not in NO_IA which has cleared leases)
+ if (addr_type != NO_IA) {
+ ASSERT_NE(0, client.config_.leases_.size());
+ client.config_.leases_[0].iaid_ = iaid2;
+ }
+
+ // Ok, let's decline the lease.
+ ASSERT_NO_THROW(client.doDecline(include_address_));
+
+ // Let's check if there's a lease
+ Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ acquired_address);
+ ASSERT_TRUE(lease);
+
+ declined_cnt = StatsMgr::instance().getObservation(name);
+ ASSERT_TRUE(declined_cnt);
+ uint64_t after = declined_cnt->getInteger().first;
+
+ declined_global = StatsMgr::instance().getObservation("declined-addresses");
+ ASSERT_TRUE(declined_global);
+ uint64_t after_global = declined_global->getInteger().first;
+
+ // We check if the decline process was successful by checking if the
+ // lease is in the database and what is its state.
+ if (expected_result == SHOULD_PASS) {
+ ASSERT_EQ(Lease::STATE_DECLINED, lease->state_);
+
+ ASSERT_FALSE(lease->hwaddr_);
+ ASSERT_TRUE(lease->duid_);
+ ASSERT_EQ(*lease->duid_, DUID::EMPTY());
+ ASSERT_EQ(lease->preferred_lft_, 0);
+ ASSERT_TRUE(lease->hostname_.empty());
+ ASSERT_FALSE(lease->fqdn_fwd_);
+ ASSERT_FALSE(lease->fqdn_rev_);
+
+ // The decline succeeded, so the declined-addresses statistic should
+ // be increased by one
+ ASSERT_EQ(after, before + 1);
+ ASSERT_EQ(after_global, before_global + 1);
+ } else {
+ // the decline was supposed, to be rejected.
+ ASSERT_EQ(Lease::STATE_DEFAULT, lease->state_);
+
+ ASSERT_TRUE(lease->hwaddr_);
+ ASSERT_TRUE(lease->duid_);
+ ASSERT_NE(*lease->duid_, DUID::EMPTY());
+ ASSERT_NE(lease->preferred_lft_, 0);
+ ASSERT_FALSE(lease->fqdn_fwd_);
+ ASSERT_FALSE(lease->fqdn_rev_);
+
+ // The decline failed, so the declined-addresses should be the same
+ // as before
+ ASSERT_EQ(before, after);
+ ASSERT_EQ(before_global, after_global);
+ }
+}
+
+// This test checks that the client can acquire and decline the lease.
+TEST_F(DeclineTest, basicMemfile) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
+ 1234, VALID_ADDR, SHOULD_PASS);
+}
+
+#ifdef HAVE_MYSQL
+// This test checks that the client can acquire and decline the lease.
+TEST_F(DeclineTest, basicMySQL) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
+ 1234, VALID_ADDR, SHOULD_PASS, 1);
+}
+#endif
+
+#ifdef HAVE_PGSQL
+TEST_F(DeclineTest, basicPgSQL) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
+ 1234, VALID_ADDR, SHOULD_PASS, 2);
+}
+#endif
+
+}
+}
+}
+
+namespace {
+
+// This test verifies the decline is rejected in the following case:
+// - Client acquires new lease using duid, iaid
+// - Client sends the DECLINE with duid, iaid, but uses wrong address.
+// - The server rejects Decline due to address mismatch
+TEST_F(DeclineTest, addressMismatch) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
+ 1234, BOGUS_ADDR, SHOULD_FAIL);
+}
+
+// This test verifies the decline is rejected in the following case:
+// - Client acquires new lease using duid, iaid1
+// - Client sends the DECLINE with duid, iaid2
+// - The server rejects Decline due to IAID mismatch
+TEST_F(DeclineTest, iaidMismatch) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234, "01:02:03:04:05:06",
+ 1235, VALID_ADDR, SHOULD_FAIL);
+}
+
+// This test verifies the decline correctness in the following case:
+// - Client acquires new lease using duid1, iaid
+// - Client sends the DECLINE using duid2, iaid
+// - The server rejects the Decline due to DUID mismatch
+TEST_F(DeclineTest, duidMismatch) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234,
+ "01:02:03:04:05:07", 1234,
+ VALID_ADDR, SHOULD_FAIL);
+}
+
+// This test verifies the decline correctness in the following case:
+// - Client acquires new lease using duid1, iaid
+// - Client sends the DECLINE using valid duid/iaid, but does not
+// include the address in it
+// - The server rejects the Decline due to missing address
+TEST_F(DeclineTest, noAddrsSent) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234,
+ "01:02:03:04:05:06", 1234,
+ NO_ADDR, SHOULD_FAIL);
+}
+
+// This test verifies the decline correctness in the following case:
+// - Client acquires new lease using duid1, iaid
+// - Client sends the DECLINE using valid duid, but does not
+// include IA_NA at all
+// - The server rejects the Decline due to missing IA_NA
+TEST_F(DeclineTest, noIAs) {
+ Dhcp6Client client;
+ acquireAndDecline(client, "01:02:03:04:05:06", 1234,
+ "01:02:03:04:05:06", 1234,
+ NO_IA, SHOULD_FAIL);
+}
+
+} // end of anonymous namespace