From 473680be325d9c849f5d344f682adc94b729b355 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 17 May 2021 19:31:55 +0900 Subject: network: introduce address_set_broadcast() --- src/network/networkd-address.c | 57 ++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 21 deletions(-) (limited to 'src/network/networkd-address.c') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 5a3388c3c4..c350b6e933 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 a->family == AF_INET && - in4_addr_is_null(&a->in_addr_peer.in) && - a->prefixlen <= 30; + return true; /* Defaults to true. */ +} + +void address_set_broadcast(Address *a) { + assert(a); + + if (!address_may_have_broadcast(a)) + return; + + /* 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"); } @@ -825,7 +848,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 +869,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 +883,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) @@ -1957,10 +1973,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); -- cgit v1.2.1 From 998545a7d9607b49facd0e9868b893ac24942c51 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 14 May 2021 17:33:32 +0900 Subject: network: address: introduce link_get_ipv4/ipv6_address() --- src/network/networkd-address.c | 48 ++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'src/network/networkd-address.c') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index c350b6e933..462907439a 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -489,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; @@ -505,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); @@ -529,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; @@ -537,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) -- cgit v1.2.1 From 0017ba3165f69e8afb7f73127281bb9a7e5b5641 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 14 May 2021 20:27:33 +0900 Subject: network: dhcp-server: introduce ServerAddress= setting This may be useful when the link which DHCP server running on has multiple static addresses. --- src/network/networkd-address.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'src/network/networkd-address.c') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 462907439a..29ab83a425 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1157,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); -- cgit v1.2.1