From 8f8dc32cc98386097586451fea3c4c89d033d17f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 9 Dec 2021 15:18:34 +0900 Subject: [PATCH 1/4] network: address: do not adjust user specified scope This reverts cd1caf30c0bd0d0c6e8df7610c614f52a7345c40. I cannot remember why such change was made. At least, the kernel does not refuse to set IPv4 localhost address with non-host scope, e.g. global. --- src/network/networkd-address.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 6eea4ff0bd..f9d21af158 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1916,19 +1916,8 @@ static int address_section_verify(Address *address) { address->label = mfree(address->label); } - if (in_addr_is_localhost(address->family, &address->in_addr) > 0 && - (address->family == AF_INET || !address->scope_set)) { - /* For IPv4, scope must be always RT_SCOPE_HOST. - * For IPv6, use RT_SCOPE_HOST only when it is not explicitly specified. */ - - if (address->scope_set && address->scope != RT_SCOPE_HOST) - log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: non-host scope is set for localhost address. " - "Ignoring Scope= setting in the [Address] section from line %u. ", - address->section->filename, address->section->line); - + if (!address->scope_set && in_addr_is_localhost(address->family, &address->in_addr) > 0) address->scope = RT_SCOPE_HOST; - } if (address->family == AF_INET6 && !FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV6)) From 20228b6d9630b953fdc0863b669dce1fad647d68 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 9 Dec 2021 15:23:32 +0900 Subject: [PATCH 2/4] network: address: also adjust scope when address is link local address But again only when Scope= is not explicitly specified. --- src/network/networkd-address.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index f9d21af158..618c278abf 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1916,8 +1916,12 @@ static int address_section_verify(Address *address) { address->label = mfree(address->label); } - if (!address->scope_set && in_addr_is_localhost(address->family, &address->in_addr) > 0) - address->scope = RT_SCOPE_HOST; + if (!address->scope_set) { + if (in_addr_is_localhost(address->family, &address->in_addr) > 0) + address->scope = RT_SCOPE_HOST; + else if (in_addr_is_link_local(address->family, &address->in_addr) > 0) + address->scope = RT_SCOPE_LINK; + } if (address->family == AF_INET6 && !FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV6)) From 78ef25a5aa80515177fa86adbe5883ca409d4263 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 9 Dec 2021 15:28:06 +0900 Subject: [PATCH 3/4] network: address: add scope in debugging logs --- src/network/networkd-address.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 618c278abf..3712671272 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -600,7 +600,7 @@ const char* format_lifetime(char *buf, size_t l, usec_t lifetime_usec) { } static void log_address_debug(const Address *address, const char *str, const Link *link) { - _cleanup_free_ char *state = NULL, *addr = NULL, *peer = NULL, *flags_str = NULL; + _cleanup_free_ char *state = NULL, *addr = NULL, *peer = NULL, *flags_str = NULL, *scope_str = NULL; assert(address); assert(str); @@ -615,13 +615,14 @@ static void log_address_debug(const Address *address, const char *str, const Lin (void) in_addr_to_string(address->family, &address->in_addr_peer, &peer); (void) address_flags_to_string_alloc(address->flags, address->family, &flags_str); + (void) route_scope_to_string_alloc(address->scope, &scope_str); - log_link_debug(link, "%s %s address (%s): %s%s%s/%u (valid %s, preferred %s), flags: %s", + log_link_debug(link, "%s %s address (%s): %s%s%s/%u (valid %s, preferred %s), flags: %s, scope: %s", str, strna(network_config_source_to_string(address->source)), strna(state), strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen, FORMAT_LIFETIME(address->lifetime_valid_usec), FORMAT_LIFETIME(address->lifetime_preferred_usec), - strna(flags_str)); + strna(flags_str), strna(scope_str)); } static int address_set_netlink_message(const Address *address, sd_netlink_message *req, Link *link) { From e096cab2f3b5750a14b40bc9fbab229196f16bd8 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 9 Dec 2021 15:43:57 +0900 Subject: [PATCH 4/4] network: wireguard: allow to run NDisc and RADV when IPv6LL address is manually configured Fixes #17380. --- src/network/networkd-address.c | 2 +- src/network/networkd-link.c | 37 ++++++++++++++++++++++++++++++++++ src/network/networkd-link.h | 1 + src/network/networkd-ndisc.c | 2 +- src/network/networkd-radv.c | 2 +- 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 3712671272..7cd4d27c07 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -752,7 +752,7 @@ int link_drop_ipv6ll_addresses(Link *link) { /* IPv6LL address may be in the tentative state, and in that case networkd has not received it. * So, we need to dump all IPv6 addresses. */ - if (link_ipv6ll_enabled(link)) + if (link_may_have_ipv6ll(link)) return 0; r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_GETADDR, link->ifindex, AF_INET6); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9a2061baec..956e2984bc 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -126,6 +126,43 @@ bool link_ipv6ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV6; } +bool link_may_have_ipv6ll(Link *link) { + assert(link); + + /* + * This is equivalent to link_ipv6ll_enabled() for non-WireGuard interfaces. + * + * For WireGuard interface, the kernel does not assign any IPv6LL addresses, but we can assign + * it manually. It is necessary to set an IPv6LL address manually to run NDisc or RADV on + * WireGuard interface. Note, also Multicast=yes must be set. See #17380. + * + * TODO: May be better to introduce GenerateIPv6LinkLocalAddress= setting, and use algorithms + * used in networkd-address-generation.c + */ + + if (link_ipv6ll_enabled(link)) + return true; + + /* IPv6LL address can be manually assigned on WireGuard interface. */ + if (streq_ptr(link->kind, "wireguard")) { + Address *a; + + if (!link->network) + return false; + + ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) { + if (a->family != AF_INET6) + continue; + if (in6_addr_is_set(&a->in_addr_peer.in6)) + continue; + if (in6_addr_is_link_local(&a->in_addr.in6)) + return true; + } + } + + return false; +} + bool link_ipv6_enabled(Link *link) { assert(link); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 5895240674..4ef86f485b 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -215,6 +215,7 @@ bool link_has_carrier(Link *link); bool link_ipv6_enabled(Link *link); bool link_ipv6ll_enabled(Link *link); +bool link_may_have_ipv6ll(Link *link); int link_ipv6ll_gained(Link *link); bool link_ipv4ll_enabled(Link *link); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index df5e580aef..32cb536ee5 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -37,7 +37,7 @@ bool link_ipv6_accept_ra_enabled(Link *link) { if (!link->network) return false; - if (!link_ipv6ll_enabled(link)) + if (!link_may_have_ipv6ll(link)) return false; assert(link->network->ipv6_accept_ra >= 0); diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 6fabd8f5c5..59b0922a4c 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -54,7 +54,7 @@ void network_adjust_radv(Network *network) { bool link_radv_enabled(Link *link) { assert(link); - if (!link_ipv6ll_enabled(link)) + if (!link_may_have_ipv6ll(link)) return false; return link->network->router_prefix_delegation;