]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp-server: check address conflict more carefully
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 2 Jan 2024 21:06:55 +0000 (06:06 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 3 Jan 2024 20:10:47 +0000 (05:10 +0900)
- Even if we found a matching static lease, check if there is no
  conflicting lease.
- Accept an address request that is different from the previous one.
- Also return NAK if the server address is requested.

src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/test-dhcp-server.c

index b1c35064ce8c24fa50c4df209a762c5bc8b4686f..0e7831f70d92f648a6197c6cb4c53b2e64a8b61e 100644 (file)
@@ -1050,10 +1050,19 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
                         return 0;
 
                 /* for now pick a random free address from the pool */
-                if (static_lease)
+                if (static_lease) {
+                        if (existing_lease != hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(static_lease->address)))
+                                /* The address is already assigned to another host. Refusing. */
+                                return 0;
+
+                        /* Found a matching static lease. */
                         address = static_lease->address;
-                else if (existing_lease)
+
+                } else if (existing_lease && address_is_in_pool(server, existing_lease->address))
+
+                        /* If we previously assigned an address to the host, then reuse it. */
                         address = existing_lease->address;
+
                 else {
                         struct siphash state;
                         uint64_t hash;
@@ -1151,30 +1160,24 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
                 /* Silently ignore Rapid Commit option in REQUEST message. */
                 req->rapid_commit = false;
 
-                /* disallow our own address */
-                if (address == server->address)
-                        return 0;
-
                 if (static_lease) {
-                        /* Found a static lease for the client ID. */
-
                         if (static_lease->address != address)
-                                /* The client requested an address which is different from the static lease. Refuse. */
+                                /* 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)))
+                                /* The requested address is already assigned to another host. Refusing. */
                                 return server_send_nak_or_ignore(server, init_reboot, req);
 
+                        /* Found a static lease for the client ID. */
                         return server_ack_request(server, req, address);
                 }
 
-                if (address_is_in_pool(server, address)) {
+                if (address_is_in_pool(server, address))
                         /* The requested address is in the pool. */
-
-                        if (existing_lease && existing_lease->address != address)
-                                /* We previously assigned an address, but the client requested another one. Refuse. */
-                                return server_send_nak_or_ignore(server, init_reboot, req);
-
                         return server_ack_request(server, req, address);
-                }
 
+                /* Refuse otherwise. */
                 return server_send_nak_or_ignore(server, init_reboot, req);
         }
 
index 9c343f8368d77217052c7071ecbd6ac632d4bec3..a52f788968d9e9b1f5b1ace86e72f968825d41ae 100644 (file)
@@ -184,7 +184,7 @@ static void test_message_handler(void) {
         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL) == 0);
         test.option_server_id.address = htobe32(INADDR_LOOPBACK);
         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 4);
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL) == 0);
+        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL) == DHCP_ACK);
         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL) == DHCP_ACK);
 
@@ -200,7 +200,7 @@ static void test_message_handler(void) {
         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL) == DHCP_ACK);
 
         test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
-        assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL) == 0);
+        assert_se(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';