diff --git a/CLAUDE.md b/CLAUDE.md index 3baccd7..251f2c5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -315,7 +315,8 @@ container is created once by a very long function where a dropped capability is - **The tooling is baked, not installed at runtime.** `iproute2` and `wireguard-tools` are in `container/Dockerfile` because a runtime install lands in the writable layer and is lost on base-image migration — leaving a project holding the capability with nothing able to exercise it, - and no error that points at why. `iptables` is deliberately absent; see the Dockerfile comment. + and no error that points at why. `iptables` is included and `nftables` deliberately is not; see + the Dockerfile comment for why that way round. - **Anything built on this fails open.** The network namespace is rebuilt on every start and no service manager runs inside, so a tunnel never survives stop/start or recreation — while leftover `/run` state makes it look as though it did. Note the two different mechanisms: `/run` is in the diff --git a/HOW-TO-USE.md b/HOW-TO-USE.md index 38514a8..85f53b6 100644 --- a/HOW-TO-USE.md +++ b/HOW-TO-USE.md @@ -537,10 +537,11 @@ Things worth knowing: at `resolvconf: command not found` and deletes the interface again. This happens before any routing, so it takes **split tunnels down too**. Set the resolver another way instead, or drive `wg` and `ip route` directly rather than going through `wg-quick`. -- **`wg-quick` full tunnels also need `xt_CONNMARK` from the host kernel.** Native Linux, Docker - Desktop for Mac and WSL2 kernels from 6.6 have it; older WSL2 kernels do not, and a container - cannot load one. There the answer is again to add the routes yourself with `ip route`, which - needs no firewall backend on any platform. +- **`wg-quick` full tunnels additionally need `xt_CONNMARK` from the host kernel.** WSL2 kernels + before 6.6 do not have it and a container cannot load one — on Windows, `wsl --update` moves you + to a current kernel, which does. Failing that, add the routes yourself with `ip route`, which + needs no firewall backend on any platform. Note this is the *second* hurdle: clear the `DNS =` + one above first, or you will not reach this. > This setting can only be changed when the container is stopped. Capabilities and devices are > fixed when a container is created, so toggling it recreates the container on the next start. diff --git a/app/src-tauri/src/docker/migration.rs b/app/src-tauri/src/docker/migration.rs index 1b0b580..a08776a 100644 --- a/app/src-tauri/src/docker/migration.rs +++ b/app/src-tauri/src/docker/migration.rs @@ -135,7 +135,7 @@ pub const FEATURE_PROBES: &[(&str, &str)] = &[ ("/usr/local/bin/triple-c-task-runner", "Scheduled task runner"), ("/usr/local/bin/triple-c-sso-refresh", "AWS SSO auto-refresh"), ("/opt/mission-control", "Mission Control (Flight Control)"), - ("/usr/bin/wg", "VPN tooling (WireGuard, for the VPN Support toggle)"), + ("/usr/bin/wg", "VPN tooling for the VPN Support toggle (WireGuard)"), ]; /// Headroom demanded on Docker's storage backend on top of the measured diff --git a/container/Dockerfile b/container/Dockerfile index 86aea02..b94b76c 100644 --- a/container/Dockerfile +++ b/container/Dockerfile @@ -87,18 +87,25 @@ RUN for i in 1 2 3 4 5; do \ # Error: Could not process rule: No such file or directory # ^^^^^^^^^^^^^^ needs nft_fib_ipv4 # -# That matters because of how the two hosts we ship to are configured. From -# LinuxKit's kernel config — Docker Desktop for Mac, identical on both arches: +# The choice therefore turns on which kernel symbol each path needs, and the two +# are not equally safe to bet on. `xt_CONNMARK` (iptables) was present in every +# kernel config examined — LinuxKit's for both arches, and WSL2's from 6.6. +# `nft_fib_ipv4` (nftables) was absent from the LinuxKit config read here, and a +# later review argued Docker Desktop has since enabled it and no longer builds +# from that config at all. That may well be true; it could not be settled from a +# Linux host, and it is the point: nftables' viability varies by Docker Desktop +# version in a way nobody here can pin down, while iptables' requirement did not +# vary anywhere it was checked. # -# CONFIG_NETFILTER_XT_CONNMARK=y <- the iptables path works -# # CONFIG_NFT_FIB_IPV4 is not set <- the nft path does not +# So `iptables` is chosen for being robust to that uncertainty rather than for +# beating nftables on any particular host. If nft_fib_ipv4 is present, wg-quick +# never reaches the iptables path and this costs 1.6 MB and nothing else; if it +# is absent, this is the difference between a working full tunnel and none. # -# So shipping `nftables` would forfeit the platform it was meant to fix. With -# `iptables`, full tunnels work on native Linux, on Docker Desktop for Mac, and -# on WSL2 kernels from 6.6 (which added xt_CONNMARK as a module). Only WSL2 -# older than that is left out, and nothing installable here changes it — the way -# out there is to add the routes with `ip route` instead of using `wg-quick`, -# which is what the pia-vpn skill does on every platform. +# The residual gap is WSL2 before 6.6, which has neither symbol. Nothing +# installable in the container changes that — but `wsl --update` does, and moves +# the host to a far newer kernel. Add the routes with `ip route` in the meantime; +# that needs no firewall backend on any platform. # # ## What this still does not fix #