summaryrefslogtreecommitdiff
path: root/src/network/networkd-address.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-05-19 10:29:43 +0900
committerGitHub <noreply@github.com>2021-05-19 10:29:43 +0900
commite7901aba1480db21e06e21cef4f6486ad71b2ec5 (patch)
tree7f8e63d41219effe9fc45dff6864b52fa376fdcb /src/network/networkd-address.c
parent734b3115d631fb0f2943f80843468dd692246547 (diff)
parent72ffb9133d686bef6d9d79e9d2899571651d5c1b (diff)
downloadsystemd-e7901aba1480db21e06e21cef4f6486ad71b2ec5.tar.gz
Merge pull request #19611 from yuwata/network-dhcp-server-introduce-server-address
network: dhcp-server: introduce ServerAddress= setting
Diffstat (limited to 'src/network/networkd-address.c')
-rw-r--r--src/network/networkd-address.c131
1 files changed, 97 insertions, 34 deletions
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index daf959ec5f..2bc860954b 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -146,12 +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) {
@@ -161,9 +187,6 @@ 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 @@ int address_get(Link *link, const Address *in, Address **ret) {
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;
@@ -482,10 +505,10 @@ int link_has_ipv6_address(Link *link, const struct in6_addr *address) {
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);
@@ -506,7 +529,35 @@ static int link_get_ipv4_address(Set *addresses, const struct in_addr *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;
@@ -514,18 +565,12 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
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 @@ 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;
@@ -847,16 +891,10 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
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);
@@ -867,8 +905,8 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
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 @@ int link_request_static_addresses(Link *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);
@@ -1960,10 +2024,9 @@ static int address_section_verify(Address *address) {
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);