]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp-server: fix conditions for checking if static address is assigned to another...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 19 Oct 2025 07:44:44 +0000 (16:44 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Mon, 20 Oct 2025 10:45:45 +0000 (11:45 +0100)
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
src/libsystemd-network/test-dhcp-server.c

index 43c7c241758e526a1a75767a13c621b840b003ba..3a4d3aa202806e217bcec3a7ce9024db0a2ad1e4 100644 (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);
 
index 17c5cddd541e1df5d862d46376fbfbc80258e3b8..705c0e92beb358ac38b2983c1510ff56f9982ec0 100644 (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);