From 0b695febb22ea5701eab4aee801e8a861ffdbaa6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 17 Aug 2024 00:00:32 +0900 Subject: [PATCH] network: make IPMasquerade= imply global IP forwarding settings again After 3976c430927e1bfefa0413f80ebac84ab9a64350 (#31423), IPMasquerade= implies only per-interface IP forwarding. That means, nspawn users need to manually enable IPv4/IPv6Forwarding= in networkd.conf when --network-veth or friend is used. Even the change was announced in NEWS, the change itself breaks backward compatibility and extremely reduces usability. Let's make the setting imply the global setting again. Fixes #34010. --- man/networkd.conf.xml | 12 +++++++ man/systemd.network.xml | 18 +++++----- src/network/networkd-sysctl.c | 63 ++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index cac1d3b6e7e..9daa1254b6e 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -131,6 +131,12 @@ for more details about the sysctl options. Defaults to unset and the sysctl options will not be changed. + If an interface is configured with a .network file that enables IPMasquerade= + for IPv4 (that is, ipv4 or both), this setting is implied + unless explicitly specified. See IPMasquerade= in + systemd.network5 + for more details. + @@ -145,6 +151,12 @@ for more details about the sysctl options. Defaults to unset and the sysctl options will not be changed. + If an interface is configured with a .network file that enables IPMasquerade= + for IPv6 (that is, ipv6 or both), this setting is implied + unless explicitly specified. See IPMasquerade= in + systemd.network5 + for more details. + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index ebcb6d04816..0374dc7cdc0 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -888,15 +888,15 @@ DuplicateAddressDetection=none ipv6, both, or no. Defaults to no. Note. Any positive boolean values such as yes or true are now deprecated. Please use one of the values above. Specifying - ipv4 or both implies IPv4Forwarding=, - unless it is explicitly specified. Similarly for IPv6Forwarding= when - ipv6 or both is specified. These implications are only on - this interface. Hence, to make the IP packet forwarding works, - IPv4Forwarding=/IPv6Forwarding= need to be enabled on an - upstream interface, or globally enabled by specifying them in - networkd.conf5. - See IPv4Forwarding=/IPv6Forwarding= in the above for more - details. + ipv4 or both implies IPv4Forwarding= + settings in both .network file for this interface and the global + networkd.conf5 + unless they are explicitly specified. Similarly for IPv6Forwarding= when + ipv6 or both is specified. See + IPv4Forwarding=/IPv6Forwarding= in the above for the per-link + settings, and + networkd.conf5 + for the global settings. diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index 68c23e0eb79..a454322fd0e 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -7,7 +7,9 @@ #include "af-list.h" #include "missing_network.h" #include "networkd-link.h" +#include "networkd-lldp-tx.h" #include "networkd-manager.h" +#include "networkd-ndisc.h" #include "networkd-network.h" #include "networkd-sysctl.h" #include "socket-util.h" @@ -130,7 +132,7 @@ int link_get_ip_forwarding(Link *link, int family) { return link->manager->ip_forwarding[family == AF_INET6]; } -static int link_set_ip_forwarding(Link *link, int family) { +static int link_set_ip_forwarding_impl(Link *link, int family) { int r, t; assert(link); @@ -151,6 +153,65 @@ static int link_set_ip_forwarding(Link *link, int family) { return 0; } +static int link_reapply_ip_forwarding(Link *link, int family) { + int r, ret = 0; + + assert(link); + assert(IN_SET(family, AF_INET, AF_INET6)); + + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) + return 0; + + (void) link_set_ip_forwarding_impl(link, family); + + r = link_lldp_tx_update_capabilities(link); + if (r < 0) + RET_GATHER(ret, log_link_warning_errno(link, r, "Could not update LLDP capabilities, ignoring: %m")); + + if (family == AF_INET6 && !link_ndisc_enabled(link)) { + r = ndisc_stop(link); + if (r < 0) + RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery, ignoring: %m")); + + ndisc_flush(link); + } + + return ret; +} + +static int link_set_ip_forwarding(Link *link, int family) { + int r; + + assert(link); + assert(link->manager); + assert(link->network); + assert(IN_SET(family, AF_INET, AF_INET6)); + + if (!link_is_configured_for_family(link, family)) + return 0; + + /* When IPMasquerade= is enabled and the global setting is unset, enable _global_ IP forwarding, and + * re-apply per-link setting for all links. */ + if (FLAGS_SET(link->network->ip_masquerade, family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6) && + link->manager->ip_forwarding[family == AF_INET6] < 0) { + + link->manager->ip_forwarding[family == AF_INET6] = true; + manager_set_ip_forwarding(link->manager, family); + + Link *other; + HASHMAP_FOREACH(other, link->manager->links_by_index) { + r = link_reapply_ip_forwarding(other, family); + if (r < 0) + link_enter_failed(other); + } + + return 0; + } + + /* Otherwise, apply per-link setting for _this_ link. */ + return link_set_ip_forwarding_impl(link, family); +} + static int link_set_ipv4_rp_filter(Link *link) { assert(link); -- 2.47.3