]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/address: acquire address from DHCP server lease file
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 12 Mar 2024 09:21:38 +0000 (18:21 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 18 Mar 2024 13:33:14 +0000 (22:33 +0900)
If the DHCP server on an interface is configured with its server
address is null, then let's reuse the previous server address if
possible.

Otherwise, if networkd is restarted or the host is rebooted, then
possibly new subnet is picked, and clients that already have addresses
in the previous subnet cannot access the server.

Prompted by https://github.com/systemd/systemd/pull/30021#discussion_r1518478633.

src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp-server.h

index d9c3dae85c58b9d6a3ab8088b1f451827a73d401..70fe1e50387d94cafee8b3836e19900ba5dbcc50 100644 (file)
@@ -1495,6 +1495,10 @@ static int address_acquire(Link *link, const Address *address, union in_addr_uni
         assert(address);
         assert(ret);
 
+        r = address_acquire_from_dhcp_server_leases_file(link, address, ret);
+        if (r != -ENOENT)
+                return r;
+
         r = address_pool_acquire(link->manager, address->family, address->prefixlen, &a);
         if (r < 0)
                 return r;
index 3efbe6f48e6d56e13661127287af8ba37f47fd92..ac6179a9248f4770ae9d3e270497937842afb7dc 100644 (file)
@@ -57,6 +57,7 @@ struct Address {
         bool scope_set:1;
         bool ip_masquerade_done:1;
         bool requested_as_null:1;
+        bool used_by_dhcp_server:1;
 
         /* duplicate_address_detection is only used by static or IPv4 dynamic addresses.
          * To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
index a1869a855998b2c5666c4626a7eba1f73eb3e0df..292022f32283978aff6b11cc1376edf9ad537c44 100644 (file)
@@ -7,6 +7,7 @@
 #include "sd-dhcp-server.h"
 
 #include "dhcp-protocol.h"
+#include "dhcp-server-lease-internal.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "network-common.h"
@@ -82,6 +83,7 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
                         /* TODO: check if the prefix length is small enough for the pool. */
 
                         network->dhcp_server_address = address;
+                        address->used_by_dhcp_server = true;
                         break;
                 }
                 if (!network->dhcp_server_address) {
@@ -128,6 +130,7 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
                 a->prefixlen = network->dhcp_server_address_prefixlen;
                 a->in_addr.in = network->dhcp_server_address_in_addr;
                 a->requested_as_null = !in4_addr_is_set(&network->dhcp_server_address_in_addr);
+                a->used_by_dhcp_server = true;
 
                 r = address_section_verify(a);
                 if (r < 0)
@@ -144,6 +147,49 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
         return 0;
 }
 
+int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret) {
+        struct in_addr a;
+        uint8_t prefixlen;
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(address);
+        assert(ret);
+
+        /* If the DHCP server address is configured as a null address, reuse the server address of the
+         * previous instance. */
+        if (address->family != AF_INET)
+                return -ENOENT;
+
+        if (!address->used_by_dhcp_server)
+                return -ENOENT;
+
+        if (!link_dhcp4_server_enabled(link))
+                return -ENOENT;
+
+        if (link->manager->persistent_storage_fd < 0)
+                return -EBUSY; /* The persistent storage is not ready, try later again. */
+
+        _cleanup_free_ char *lease_file = path_join("dhcp-server-lease", link->ifname);
+        if (!lease_file)
+                return -ENOMEM;
+
+        r = dhcp_server_leases_file_get_server_address(
+                        link->manager->persistent_storage_fd,
+                        lease_file,
+                        &a,
+                        &prefixlen);
+        if (r < 0)
+                return r;
+
+        if (prefixlen != address->prefixlen)
+                return -ENOENT;
+
+        ret->in = a;
+        return 0;
+}
+
 int link_start_dhcp4_server(Link *link) {
         int r;
 
index dbc7d95cadba470a3f94f01f8ba99f19c5e607a5..e839fac00b44675b4251779bc8799213c7c78bd6 100644 (file)
@@ -2,14 +2,16 @@
 #pragma once
 
 #include "conf-parser.h"
+#include "in-addr-util.h"
 #include "set.h"
 
+typedef struct Address Address;
 typedef struct Link Link;
 typedef struct Manager Manager;
 typedef struct Network Network;
 
 int network_adjust_dhcp_server(Network *network, Set **addresses);
-
+int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret);
 int link_request_dhcp_server(Link *link);
 
 int link_start_dhcp4_server(Link *link);