From d19294e92a2963a669cd0e3e89806506b13d6b3a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 19 Oct 2025 16:44:44 +0900 Subject: [PATCH] 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. --- src/libsystemd-network/sd-dhcp-server.c | 6 ++-- src/libsystemd-network/test-dhcp-server.c | 39 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 43c7c241758..3a4d3aa2028 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -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); diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 17c5cddd541..705c0e92beb 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -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); -- 2.47.3