diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 9d3e3f033b..619ef91288 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -2993,6 +2993,45 @@ static int networkctl_main(int argc, char *argv[]) { return dispatch_verb(argc, argv, verbs, NULL); } +static int check_netns_match(void) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + struct stat st; + uint64_t id; + int r; + + r = sd_bus_open_system(&bus); + if (r < 0) + return log_error_errno(r, "Failed to connect system bus: %m"); + + r = sd_bus_get_property_trivial( + bus, + "org.freedesktop.network1", + "/org/freedesktop/network1", + "org.freedesktop.network1.Manager", + "NamespaceId", + &error, + 't', + &id); + if (r < 0) { + log_debug_errno(r, "Failed to query network namespace of networkd, ignoring: %s", bus_error_message(&error, r)); + return 0; + } + if (id == 0) { + log_debug("systemd-networkd.service not running in a network namespace (?), skipping netns check."); + return 0; + } + + if (stat("/proc/self/ns/net", &st) < 0) + return log_error_errno(r, "Failed to determine our own network namespace ID: %m"); + + if (id != st.st_ino) + return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), + "networkctl must be invoked in same network namespace as systemd-networkd.service."); + + return 0; +} + static void warn_networkd_missing(void) { if (access("/run/systemd/netif/state", F_OK) >= 0) @@ -3010,6 +3049,10 @@ static int run(int argc, char* argv[]) { if (r <= 0) return r; + r = check_netns_match(); + if (r < 0) + return r; + warn_networkd_missing(); return networkctl_main(argc, argv); diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 23c1fb57c6..1c6230b393 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -263,6 +263,34 @@ static int bus_method_describe(sd_bus_message *message, void *userdata, sd_bus_e return sd_bus_send(NULL, reply, NULL); } +static int property_get_namespace_id( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + uint64_t id = 0; + struct stat st; + + assert(bus); + assert(reply); + + /* Returns our own network namespace ID, i.e. the inode number of /proc/self/ns/net. This allows + * unprivileged clients to determine whether they are in the same network namespace as us (note that + * access to that path is restricted, thus they can't check directly unless privileged). */ + + if (stat("/proc/self/ns/net", &st) < 0) { + log_warning_errno(errno, "Failed to stat network namespace, ignoring: %m"); + id = 0; + } else + id = st.st_ino; + + return sd_bus_message_append(reply, "t", id); +} + const sd_bus_vtable manager_vtable[] = { SD_BUS_VTABLE_START(0), @@ -272,6 +300,7 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Manager, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Manager, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("OnlineState", "s", property_get_online_state, offsetof(Manager, online_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NamespaceId", "t", property_get_namespace_id, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD_WITH_ARGS("ListLinks", SD_BUS_NO_ARGS, diff --git a/test/test-network/conf/25-activation-policy.network b/test/test-network/conf/25-activation-policy.network index c53e0919c4..873e260ebf 100644 --- a/test/test-network/conf/25-activation-policy.network +++ b/test/test-network/conf/25-activation-policy.network @@ -4,3 +4,4 @@ Name=test1 [Network] Address=192.168.10.30/24 Gateway=192.168.10.1 +IPv6AcceptRA=no diff --git a/test/test-network/conf/25-nexthop-dummy.network b/test/test-network/conf/25-nexthop-dummy.network index e494aca8e3..9d754bf25a 100644 --- a/test/test-network/conf/25-nexthop-dummy.network +++ b/test/test-network/conf/25-nexthop-dummy.network @@ -3,6 +3,7 @@ Name=dummy98 [Network] Address=192.168.20.20/24 +IPv6AcceptRA=no [NextHop] Id=20 diff --git a/test/test-network/conf/25-wireguard-23-peers.network b/test/test-network/conf/25-wireguard-23-peers.network index 033ffa155d..ee70e3c5e8 100644 --- a/test/test-network/conf/25-wireguard-23-peers.network +++ b/test/test-network/conf/25-wireguard-23-peers.network @@ -4,6 +4,7 @@ Name=wg98 [Network] Address=192.168.123.123/24 Address=fd8d:4d6d:3ccb:0500::1/64 +IPv6AcceptRA=no # nat64 via 1 [Route] diff --git a/test/test-network/conf/25-wireguard.network b/test/test-network/conf/25-wireguard.network index 163a56ff29..565e85ea8d 100644 --- a/test/test-network/conf/25-wireguard.network +++ b/test/test-network/conf/25-wireguard.network @@ -3,3 +3,4 @@ Name=wg99 [Network] Address=192.168.124.1/24 +IPv6AcceptRA=no diff --git a/test/test-network/conf/agent-client-peer.network b/test/test-network/conf/agent-client-peer.network index 4142938056..b053c2c6b4 100644 --- a/test/test-network/conf/agent-client-peer.network +++ b/test/test-network/conf/agent-client-peer.network @@ -1,9 +1,12 @@ [Match] Name=client-peer + [Network] Address=192.168.6.2/24 DHCPServer=yes IPForward=ipv4 +IPv6AcceptRA=no + [DHCPServer] RelayTarget=192.168.5.1 BindToInterface=no diff --git a/test/test-network/conf/agent-client.network b/test/test-network/conf/agent-client.network index 773dc8a4fb..7787bb631f 100644 --- a/test/test-network/conf/agent-client.network +++ b/test/test-network/conf/agent-client.network @@ -1,5 +1,7 @@ [Match] Name=client + [Network] DHCP=yes IPForward=ipv4 +IPv6AcceptRA=no diff --git a/test/test-network/conf/agent-server-peer.network b/test/test-network/conf/agent-server-peer.network index fdb235e1ff..6aec2974a8 100644 --- a/test/test-network/conf/agent-server-peer.network +++ b/test/test-network/conf/agent-server-peer.network @@ -1,5 +1,7 @@ [Match] Name=server-peer + [Network] Address=192.168.5.2/24 IPForward=ipv4 +IPv6AcceptRA=no diff --git a/test/test-network/conf/agent-server.network b/test/test-network/conf/agent-server.network index 65bcc54dc1..c8da15c3ec 100644 --- a/test/test-network/conf/agent-server.network +++ b/test/test-network/conf/agent-server.network @@ -1,9 +1,11 @@ [Match] Name=server + [Network] Address=192.168.5.1/24 IPForward=ipv4 DHCPServer=yes +IPv6AcceptRA=no [DHCPServer] BindToInterface=no diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index d6b790bc35..0c5fe461f4 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2785,7 +2785,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): for iteration in range(4): with self.subTest(iteration=iteration, expect_up=expect_up): operstate = 'routable' if expect_up else 'off' - setup_state = 'configured' if expect_up else None + setup_state = 'configured' if expect_up else ('configuring' if iteration == 0 else None) self.wait_operstate('test1', operstate, setup_state=setup_state, setup_timeout=20) if expect_up: