--- type: technique title: A private netns gives unprivileged, throwaway nftables tags: [testing, nftables] --- `unshare --user --map-root-user --net` gives an unprivileged process a root-mapped uid inside its own empty network namespace. nftables in there is the real kernel subsystem, so a generated ruleset can be applied and queried for real, and nothing reaches the host. Measured on the box: ``` $ cat /proc/sys/user/max_user_namespaces 239220 $ unshare --user --map-root-user --net -- nft add table inet test # works ``` The alternative does not work. `nft -c -f file` refuses outside root: ``` netlink: Error: cache initialization failed: Operation not permitted ``` Check mode needs the netlink cache, so even a dry run wants privilege. Inside the namespace it succeeds. This is why `tests/ruleset.test.sh` runs the whole suite inside one `unshare` rather than checking generated text with grep: leaving the namespace drops the table. Assertions use `nft get element` rather than string matching, so interval matching on a CIDR block is actually exercised instead of assumed. This paid for itself on the first run. The empty-blocklist path emitted `flags interval}` because a heredoc newline was swallowed by a `${var:+...}` expansion, and only a real apply caught it.