nixos/network-interfaces: allow setting virtualOwner to null

null will not set owner, allowing any user to access the virtual
device.  Previously, this behavior can be achieved by using
systemd.network.netdevs.* options direcly and leaving
systemd.network.netdevs.<name>.tapConfig.User unset.  With this patch,
this behavior can be achieved using the generic
networking.interfaces.* options by setting
networking.interfaces.<name>.virtualOwner to null.

If needed, we can change the default value from "root" to null in the
future to be consistent with systemd-networkd's default behavior.
This commit is contained in:
Lin Jian
2026-01-15 20:55:30 +08:00
parent 2ba2183093
commit 17256403d0
3 changed files with 12 additions and 3 deletions
@@ -322,7 +322,9 @@ let
RemainAfterExit = true;
};
script = ''
ip tuntap add dev "${i.name}" mode "${i.virtualType}" user "${i.virtualOwner}"
ip tuntap add dev "${i.name}" mode "${i.virtualType}" ${
lib.optionalString (i.virtualOwner != null) ''user "${i.virtualOwner}"''
}
'';
postStop = ''
ip link del dev ${i.name} || true
+2 -1
View File
@@ -348,9 +348,10 @@ let
virtualOwner = mkOption {
default = "root";
type = types.str;
type = types.nullOr types.str;
description = ''
In case of a virtual device, the user who owns it.
`null` will not set owner, allowing access to any user.
'';
};
@@ -1053,6 +1053,7 @@ let
}
];
virtual = true;
virtualOwner = null;
mtu = 1342;
macAddress = "02:de:ad:be:ef:01";
};
@@ -1070,13 +1071,14 @@ let
}
];
virtual = true;
virtualOwner = "root";
mtu = 1343;
};
};
testScript = ''
targetList = """
tap0: tap persist user 0
tap0: tap persist
tun0: tun persist user 0
""".strip()
@@ -1101,6 +1103,10 @@ let
machine.wait_until_succeeds("ip link show dev tap0 | grep 'mtu 1342'")
machine.wait_until_succeeds("ip link show dev tun0 | grep 'mtu 1343'")
assert "02:de:ad:be:ef:01" in machine.succeed("ip link show dev tap0")
with subtest("Test virtualOwner are configured"):
for interface, expected_owner in [("tap0", "-1"), ("tun0", "0")]:
actual_owner = machine.succeed(f"cat /sys/class/net/{interface}/owner").strip()
assert expected_owner == actual_owner, f"{interface} owner: expect {expected_owner}, got {actual_owner}"
'' # network-addresses-* only exist in scripted networking
+ lib.optionalString (!networkd) ''
with subtest("Test interfaces' addresses clean up"):