2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 05:55:28 +00:00

[#3758] [#3565] Prevent declining expired and released

This commit is contained in:
Marcin Siodelski
2024-09-23 10:36:09 +02:00
committed by Francis Dupont
parent eb5e5952ea
commit 1a9c21a21b
4 changed files with 169 additions and 3 deletions

View File

@@ -4021,8 +4021,13 @@ Dhcpv4Srv::processDecline(Pkt4Ptr& decline, AllocEngine::ClientContext4Ptr& cont
client_id.reset(new ClientId(opt_clientid->getData()));
}
// Check if the client attempted to decline a lease it doesn't own.
if (!lease->belongsToClient(decline->getHWAddr(), client_id)) {
// Check if the client attempted to decline an expired lease or a lease
// it doesn't own. Declining expired leases is typically a client
// misbehavior and may lead to pool exhaustion in case of a storm of
// such declines. Only decline the lease if the lease has been recently
// allocated to the client.
if (lease->expired() || lease->state_ != Lease::STATE_DEFAULT ||
!lease->belongsToClient(decline->getHWAddr(), client_id)) {
// Get printable hardware addresses
string client_hw = decline->getHWAddr() ?

View File

@@ -364,4 +364,77 @@ TEST_F(DeclineTest, declineNonMatchingIPAddress) {
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
}
// Test that the released lease cannot be declined.
TEST_F(DeclineTest, declineAfterRelease) {
Dhcp4Client client(Dhcp4Client::SELECTING);
// Configure DHCP server.
configure(DECLINE_CONFIGS[0], *client.getServer(), true, true, true, false, LEASE_AFFINITY_ENABLED);
// Perform 4-way exchange to obtain a new lease.
acquireLease(client);
// Remember the acquired address.
IOAddress leased_address = client.config_.lease_.addr_;
// Release the acquired lease.
client.doRelease();
// Try to decline the released address.
client.config_.lease_.addr_ = leased_address;
ASSERT_NO_THROW(client.doDecline());
// The address should not be declined. It should still be in the
// released state.
Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(leased_address);
ASSERT_TRUE(lease);
EXPECT_EQ(Lease::STATE_RELEASED, lease->state_);
}
// Test that the expired lease cannot be declined.
TEST_F(DeclineTest, declineAfterExpire) {
Dhcp4Client client(Dhcp4Client::SELECTING);
// Configure DHCP server.
configure(DECLINE_CONFIGS[0], *client.getServer());
// Perform 4-way exchange to obtain a new lease.
acquireLease(client);
// Age the lease (expire it).
auto lease = LeaseMgrFactory::instance().getLease4(client.config_.lease_.addr_);
ASSERT_TRUE(lease);
lease->cltt_ -= 7200;
LeaseMgrFactory::instance().updateLease4(lease);
// Try to decline the expired lease.
ASSERT_NO_THROW(client.doDecline());
// The address should not be declined. It should still be in the
// default state.
lease = LeaseMgrFactory::instance().getLease4(lease->addr_);
ASSERT_TRUE(lease);
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
}
// Test that expired-reclaimed lease cannot be declined.
TEST_F(DeclineTest, declineAfterReclamation) {
Dhcp4Client client(Dhcp4Client::SELECTING);
// Configure DHCP server.
configure(DECLINE_CONFIGS[0], *client.getServer());
// Perform 4-way exchange to obtain a new lease.
acquireLease(client);
// Reclaim the lease.
auto lease = LeaseMgrFactory::instance().getLease4(client.config_.lease_.addr_);
ASSERT_TRUE(lease);
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
LeaseMgrFactory::instance().updateLease4(lease);
// Try to decline the reclaimed lease.
ASSERT_NO_THROW(client.doDecline());
// The address should not be declined. It should still be in the
// reclaimed state.
lease = LeaseMgrFactory::instance().getLease4(lease->addr_);
ASSERT_TRUE(lease);
EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
}
} // end of anonymous namespace

View File

@@ -4069,7 +4069,7 @@ Dhcpv6Srv::declineIA(const Pkt6Ptr& decline, const DuidPtr& duid,
Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
decline_addr->getAddress());
if (!lease) {
if (!lease || lease->expired() || lease->state_ != Lease::STATE_DEFAULT) {
// Client trying to decline a lease that we don't know about.
LOG_INFO(lease6_logger, DHCP6_DECLINE_FAIL_NO_LEASE)
.arg(decline->getLabel()).arg(decline_addr->getAddress().toText());

View File

@@ -329,4 +329,92 @@ TEST_F(DeclineTest, noIAs) {
NO_IA, SHOULD_FAIL);
}
// Test that the released lease cannot be declined.
TEST_F(DeclineTest, declineAfterRelease) {
Dhcp6Client client;
uint32_t iaid = 1;
client.requestAddress(iaid);
// Configure DHCP server.
configure(DECLINE_CONFIGS[0], *client.getServer());
// Perform 4-way exchange to obtain a new lease.
client.doSARR();
auto leases = client.getLeasesByType(Lease::TYPE_NA);
ASSERT_EQ(1, leases.size());
EXPECT_EQ(STATUS_Success, client.getStatusCode(iaid));
// Release the acquired lease.
auto lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, leases[0].addr_);
lease->state_ = Lease::STATE_RELEASED;
LeaseMgrFactory::instance().updateLease6(lease);
// Try to decline the released address.
ASSERT_NO_THROW(client.doDecline());
// The address should not be declined. It should still be in the
// released state.
lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, lease->addr_);
ASSERT_TRUE(lease);
EXPECT_EQ(Lease::STATE_RELEASED, lease->state_);
}
// Test that the released lease cannot be declined.
TEST_F(DeclineTest, declineAfterExpire) {
Dhcp6Client client;
uint32_t iaid = 1;
client.requestAddress(iaid);
// Configure DHCP server.
configure(DECLINE_CONFIGS[0], *client.getServer());
// Perform 4-way exchange to obtain a new lease.
client.doSARR();
auto leases = client.getLeasesByType(Lease::TYPE_NA);
ASSERT_EQ(1, leases.size());
EXPECT_EQ(STATUS_Success, client.getStatusCode(iaid));
// Release the acquired lease.
auto lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, leases[0].addr_);
lease->cltt_ -= 7200;
LeaseMgrFactory::instance().updateLease6(lease);
// Try to decline the expired lease.
ASSERT_NO_THROW(client.doDecline());
// The address should not be declined. It should still be in the
// default state.
lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, lease->addr_);
ASSERT_TRUE(lease);
EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
}
// Test that expired-reclaimed lease cannot be declined.
TEST_F(DeclineTest, declineAfterReclamation) {
Dhcp6Client client;
uint32_t iaid = 1;
client.requestAddress(iaid);
// Configure DHCP server.
configure(DECLINE_CONFIGS[0], *client.getServer());
// Perform 4-way exchange to obtain a new lease.
client.doSARR();
auto leases = client.getLeasesByType(Lease::TYPE_NA);
ASSERT_EQ(1, leases.size());
EXPECT_EQ(STATUS_Success, client.getStatusCode(iaid));
// Release the acquired lease.
auto lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, leases[0].addr_);
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
LeaseMgrFactory::instance().updateLease6(lease);
// Try to decline the reclaimed lease.
ASSERT_NO_THROW(client.doDecline());
// The address should not be declined. It should still be in the
// reclaimed state.
lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, lease->addr_);
ASSERT_TRUE(lease);
EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
}
} // end of anonymous namespace