sd-dhcp-server: fix conditions for checking if static address is assigned to another host

Even if a static lease may be configured for a host, another address may
be previously assigned to the host. Let's not refuse to assign the
static lease to the host even in that case.

Fixes an issue reported at
https://github.com/systemd/systemd/issues/35781#issuecomment-3369545753.
This commit is contained in:
Yu Watanabe
2025-10-19 16:44:44 +09:00
committed by Luca Boccassi
parent 85eae6ba35
commit d19294e92a
2 changed files with 43 additions and 2 deletions

View File

@@ -1072,7 +1072,8 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
/* for now pick a random free address from the pool */
if (static_lease) {
if (existing_lease != hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(static_lease->address)))
sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(static_lease->address));
if (l && l != existing_lease)
/* The address is already assigned to another host. Refusing. */
return 0;
@@ -1186,7 +1187,8 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
/* The client requested an address which is different from the static lease. Refusing. */
return server_send_nak_or_ignore(server, init_reboot, req);
if (existing_lease != hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address)))
sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address));
if (l && l != existing_lease)
/* The requested address is already assigned to another host. Refusing. */
return server_send_nak_or_ignore(server, init_reboot, req);

View File

@@ -214,6 +214,45 @@ static void test_message_handler(void) {
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
/* add the static lease for the client ID */
ASSERT_OK(sd_dhcp_server_stop(server));
ASSERT_OK(sd_dhcp_server_set_static_lease(server, &(struct in_addr){ .s_addr = htobe32(INADDR_LOOPBACK + 31) },
(uint8_t[7]){ 0x01, 'A', 'B', 'C', 'D', 'E', 'F' }, 7));
ASSERT_OK(sd_dhcp_server_start(server));
/* discover */
test.option_type.type = DHCP_DISCOVER;
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
/* request neither bound nor static address */
test.option_type.type = DHCP_REQUEST;
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 29);
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
/* request the currently assigned address */
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
/* request the new static address */
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 31);
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
/* release the bound static lease */
test.message.ciaddr = htobe32(INADDR_LOOPBACK + 31);
test.option_type.type = DHCP_RELEASE;
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
/* drop the static lease for the client ID */
ASSERT_OK(sd_dhcp_server_stop(server));
ASSERT_OK(sd_dhcp_server_set_static_lease(server, NULL, (uint8_t[7]){ 0x01, 'A', 'B', 'C', 'D', 'E', 'F' }, 7));
ASSERT_OK(sd_dhcp_server_start(server));
/* request a new non-static address */
test.message.ciaddr = 0;
test.option_type.type = DHCP_REQUEST;
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 29);
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
/* request address reserved for static lease (unmatching client ID) */
test.option_client_id.id[6] = 'H';
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42);