]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #19611 from yuwata/network-dhcp-server-introduce-server-address
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 19 May 2021 01:29:43 +0000 (10:29 +0900)
committerGitHub <noreply@github.com>
Wed, 19 May 2021 01:29:43 +0000 (10:29 +0900)
network: dhcp-server: introduce ServerAddress= setting

1  2 
src/network/networkd-address.c

index daf959ec5f3d75dcbcb50bd93545f269dd771a6c,29ab83a425fd5d3d8fbbb39b21a8ea53ea83b31d..2bc860954bd30563367d76f35b4711c8a0efe72d
@@@ -146,12 -146,38 +146,38 @@@ Address *address_free(Address *address
  static bool address_may_have_broadcast(const Address *a) {
          assert(a);
  
+         if (a->family != AF_INET)
+                 return false;
+         if (in4_addr_is_set(&a->in_addr_peer.in))
+                 return false;
          /* A /31 or /32 IPv4 address does not have a broadcast address.
           * See https://tools.ietf.org/html/rfc3021 */
+         if (a->prefixlen > 30)
+                 return false;
+         if (a->set_broadcast >= 0)
+                 return a->set_broadcast;
+         return true; /* Defaults to true. */
+ }
+ void address_set_broadcast(Address *a) {
+         assert(a);
+         if (!address_may_have_broadcast(a))
+                 return;
  
-         return a->family == AF_INET &&
-                 in4_addr_is_null(&a->in_addr_peer.in) &&
-                 a->prefixlen <= 30;
+         /* If explicitly configured, do not update the address. */
+         if (in4_addr_is_set(&a->broadcast))
+                 return;
+         /* If Address= is 0.0.0.0, then the broadcast address will be set later in address_acquire(). */
+         if (in4_addr_is_null(&a->in_addr.in))
+                 return;
+         a->broadcast.s_addr = a->in_addr.in.s_addr | htobe32(UINT32_C(0xffffffff) >> a->prefixlen);
  }
  
  static bool address_may_set_broadcast(const Address *a, const Link *link) {
          if (!address_may_have_broadcast(a))
                  return false;
  
-         if (a->set_broadcast >= 0)
-                 return a->set_broadcast;
          /* Typical configuration for wireguard does not set broadcast. */
          return !streq_ptr(link->kind, "wireguard");
  }
@@@ -466,7 -489,7 +489,7 @@@ int address_get(Link *link, const Addre
          return -ENOENT;
  }
  
- int link_has_ipv6_address(Link *link, const struct in6_addr *address) {
+ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **ret) {
          _cleanup_(address_freep) Address *a = NULL;
          int r;
  
          a->family = AF_INET6;
          a->in_addr.in6 = *address;
  
-         return address_get(link, a, NULL) >= 0;
+         return address_get(link, a, ret);
  }
  
- static int link_get_ipv4_address(Set *addresses, const struct in_addr *address, Address **ret) {
+ static int addresses_get_ipv4_address(Set *addresses, const struct in_addr *address, Address **ret) {
          Address *a;
  
          assert(address);
          return -ENOENT;
  }
  
+ int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret) {
+         int r;
+         assert(link);
+         assert(address);
+         if (prefixlen != 0) {
+                 _cleanup_(address_freep) Address *a = NULL;
+                 /* If prefixlen is set, then we can use address_get(). */
+                 r = address_new(&a);
+                 if (r < 0)
+                         return r;
+                 a->family = AF_INET;
+                 a->in_addr.in = *address;
+                 a->prefixlen = prefixlen;
+                 return address_get(link, a, ret);
+         }
+         if (addresses_get_ipv4_address(link->addresses, address, ret) >= 0)
+                 return 0;
+         return addresses_get_ipv4_address(link->addresses_foreign, address, ret);
+ }
  int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
+         Address *a;
          Link *link;
          int r;
  
          assert(IN_SET(family, AF_INET, AF_INET6));
          assert(address);
  
-         if (family == AF_INET)
-                 HASHMAP_FOREACH(link, manager->links) {
-                         Address *a;
-                         if (link_get_ipv4_address(link->addresses, &address->in, &a) >= 0)
-                                 return !check_ready || address_is_ready(a);
-                         if (link_get_ipv4_address(link->addresses_foreign, &address->in, &a) >= 0)
+         if (family == AF_INET) {
+                 HASHMAP_FOREACH(link, manager->links)
+                         if (link_get_ipv4_address(link, &address->in, 0, &a) >= 0)
                                  return !check_ready || address_is_ready(a);
-                 }
-         else {
+         } else {
                  _cleanup_(address_freep) Address *tmp = NULL;
-                 Address *a;
  
                  r = address_new(&tmp);
                  if (r < 0)
@@@ -825,7 -870,6 +870,6 @@@ int link_drop_addresses(Link *link) 
  
  static int address_acquire(Link *link, const Address *original, Address **ret) {
          union in_addr_union in_addr = IN_ADDR_NULL;
-         struct in_addr broadcast = {};
          _cleanup_(address_freep) Address *na = NULL;
          int r;
  
          if (r == 0)
                  return -EBUSY;
  
-         if (original->family == AF_INET) {
-                 /* Pick first address in range for ourselves ... */
+         /* Pick first address in range for ourselves. */
+         if (original->family == AF_INET)
                  in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
-                 /* .. and use last as broadcast address */
-                 if (original->prefixlen > 30)
-                         broadcast.s_addr = 0;
-                 else
-                         broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
-         } else if (original->family == AF_INET6)
+         else if (original->family == AF_INET6)
                  in_addr.in6.s6_addr[15] |= 1;
  
          r = address_new(&na);
          if (r < 0)
                  return r;
  
-         na->broadcast = broadcast;
          na->in_addr = in_addr;
+         address_set_broadcast(na);
  
          r = set_ensure_put(&link->pool_addresses, &address_hash_ops, na);
          if (r < 0)
@@@ -1119,6 -1157,32 +1157,32 @@@ int link_request_static_addresses(Link 
                  req->after_configure = static_address_after_configure;
          }
  
+         if (in4_addr_is_set(&link->network->dhcp_server_address)) {
+                 _cleanup_(address_freep) Address *address = NULL;
+                 r = address_new(&address);
+                 if (r < 0)
+                         return log_oom();
+                 address->family = AF_INET;
+                 address->in_addr.in = link->network->dhcp_server_address;
+                 address->prefixlen = link->network->dhcp_server_address_prefixlen;
+                 address_set_broadcast(address);
+                 /* The same address may be explicitly configured in [Address] or [Network] section.
+                  * Configure the DHCP server address only when it is not. */
+                 if (!link_is_static_address_configured(link, address)) {
+                         Request *req;
+                         r = link_request_address(link, TAKE_PTR(address), true, &link->static_address_messages,
+                                                  static_address_handler, &req);
+                         if (r < 0)
+                                 return r;
+                         req->after_configure = static_address_after_configure;
+                 }
+         }
          if (link->static_address_messages == 0) {
                  link->static_addresses_configured = true;
                  link_check_ready(link);
@@@ -1149,9 -1213,6 +1213,9 @@@ int request_process_address(Request *re
          if (r < 0)
                  return r;
  
 +        /* To prevent a double decrement on failure in after_configure(). */
 +        req->message_counter = NULL;
 +
          if (req->after_configure) {
                  r = req->after_configure(req, ret);
                  if (r < 0)
@@@ -1960,10 -2021,9 +2024,9 @@@ static int address_section_verify(Addre
                                           address->section->filename, address->section->line);
          }
  
-         if (address_may_have_broadcast(address)) {
-                 if (address->broadcast.s_addr == 0 && address->set_broadcast != 0)
-                         address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen);
-         } else if (address->broadcast.s_addr != 0) {
+         if (address_may_have_broadcast(address))
+                 address_set_broadcast(address);
+         else if (address->broadcast.s_addr != 0) {
                  log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. "
                              "Ignoring Broadcast= setting in the [Address] section from line %u.",
                              address->section->filename, address->section->line);