Merge pull request #19729 from poettering/networkctl-netns-check
networkctl: check that client netns matches networkd netns
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -4,3 +4,4 @@ Name=test1
|
||||
[Network]
|
||||
Address=192.168.10.30/24
|
||||
Gateway=192.168.10.1
|
||||
IPv6AcceptRA=no
|
||||
|
||||
@@ -3,6 +3,7 @@ Name=dummy98
|
||||
|
||||
[Network]
|
||||
Address=192.168.20.20/24
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[NextHop]
|
||||
Id=20
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -3,3 +3,4 @@ Name=wg99
|
||||
|
||||
[Network]
|
||||
Address=192.168.124.1/24
|
||||
IPv6AcceptRA=no
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Match]
|
||||
Name=client
|
||||
|
||||
[Network]
|
||||
DHCP=yes
|
||||
IPForward=ipv4
|
||||
IPv6AcceptRA=no
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[Match]
|
||||
Name=server-peer
|
||||
|
||||
[Network]
|
||||
Address=192.168.5.2/24
|
||||
IPForward=ipv4
|
||||
IPv6AcceptRA=no
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
[Match]
|
||||
Name=server
|
||||
|
||||
[Network]
|
||||
Address=192.168.5.1/24
|
||||
IPForward=ipv4
|
||||
DHCPServer=yes
|
||||
IPv6AcceptRA=no
|
||||
|
||||
[DHCPServer]
|
||||
BindToInterface=no
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user