From: Yu Watanabe Date: Tue, 2 Jan 2024 21:06:55 +0000 (+0900) Subject: sd-dhcp-server: check address conflict more carefully X-Git-Tag: v256-rc1~1202^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0596f5939fa4d583756054cdfe8028146f52d4b4;p=thirdparty%2Fsystemd.git sd-dhcp-server: check address conflict more carefully - 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. --- diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index b1c35064ce8..0e7831f70d9 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -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); } diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 9c343f8368d..a52f788968d 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -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';