Drop IPv6 NAT (MASQUERADE): never correct IPv6 practice, unsupported

The real target device's ip6tables build has no MASQUERADE target,
breaking extern network provisioning whenever IPv6 was enabled. Rather
than work around that gap, dropped the ip6tables MASQUERADE rule
entirely, unconditionally, on both the veth and tap+relay paths --
it was never correct IPv6 design to begin with. The fd00::/8 ULA
addresses this project auto-allocates (network_subnet.h) are
non-globally-routable by design (RFC 4193, the IPv6 equivalent of
RFC1918 private space); NAT66 for them isn't how IPv6 is meant to get
outside access -- that's supposed to come from a properly delegated,
globally-routable prefix (DHCPv6-PD), which this project doesn't do.
Dropping NAT66 is the honest design, not a workaround.

extern's IPv6 side now behaves exactly like intern's already did: real
same-bridge reachability between containers, no path to the actual
internet. IPv4 is unaffected -- extern still gets full NAT'd outside
access there. IPv6 forwarding stays enabled (harmless, global,
available for other uses later); only the ip6tables MASQUERADE call
and the ip6tables dependency check that gated it were removed
(network_bridge.{h,cpp}'s provision_bridge()/teardown_network_state()/
check_network_dependencies()) -- one less required tool on the target
device too.

Verified as root via the doas rule: creating and fully deleting an
extern network with IPv6 enabled no longer invokes ip6tables at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
2026-08-30 18:38:57 +00:00
parent 745930aad6
commit 8a0d800478
5 changed files with 129 additions and 54 deletions
+2 -2
View File
@@ -92,10 +92,10 @@ slocker-lite -V|--version
| `--list-volumes` | List all named volumes (see `-v/--volume`) with their host directory. |
| `--delete-volume <name>` | Remove a named volume from the config. The host directory is left untouched. |
| `--delete-volume-full <name>` | Like `--delete-volume`, but also recursively deletes the volume's host directory. |
| `-n, --network <name>` | Create/manage a persistent named network: requires exactly one of `--extern` (a real Linux bridge in the host's own namespace, with NAT/forwarding set up so containers on it reach the host's real network) or `--intern` (a bridge inside its own dedicated, routeless namespace, only reachable by other containers on the same network). `--subnet <cidr>` overrides the auto-allocated IPv4 range (`10.168.0.0/24`, incrementing per network); `--no-ipv6` disables (and `--subnet6 <cidr>` overrides) the auto-allocated IPv6 range, on by default. `--no-veth` forces the tap+relay join fallback even on a kernel that supports veth (useful for testing that path; it's otherwise chosen automatically whenever the running kernel lacks veth support). With `--run`, instead joins `<name>` to the container as its own `eth<N>` interface with an address from the network's subnet; repeatable, no membership limit. Root-only for now. See [`docs/networking-design.md`](docs/networking-design.md) for the full design, including the tap+relay veth fallback. |
| `-n, --network <name>` | Create/manage a persistent named network: requires exactly one of `--extern` (a real Linux bridge in the host's own namespace, with IPv4 NAT/forwarding set up so containers on it reach the host's real network — IPv6, if enabled, is same-bridge reachability only, no NAT: its ULA addresses are non-globally-routable by design) or `--intern` (a bridge inside its own dedicated, routeless namespace, only reachable by other containers on the same network). `--subnet <cidr>` overrides the auto-allocated IPv4 range (`10.168.0.0/24`, incrementing per network); `--no-ipv6` disables (and `--subnet6 <cidr>` overrides) the auto-allocated IPv6 range, on by default. `--no-veth` forces the tap+relay join fallback even on a kernel that supports veth (useful for testing that path; it's otherwise chosen automatically whenever the running kernel lacks veth support). With `--run`, instead joins `<name>` to the container as its own `eth<N>` interface with an address from the network's subnet; repeatable, no membership limit. Root-only for now. See [`docs/networking-design.md`](docs/networking-design.md) for the full design, including the tap+relay veth fallback. |
| `--list-networks` | List all named networks (see `-n/--network`) with their kind, IPv4 subnet, bridge name, and IPv6 subnet (or `(no ipv6)`). |
| `--delete-network <name>` | Remove a named network from the config. Its live bridge/namespace/iptables state is left untouched. |
| `--delete-network-full <name>` | Like `--delete-network`, but also tears down its live state (MASQUERADE rule(s), the bridge itself for `extern`, or the whole persistent namespace for `intern`), so a network with the same name can be created fresh afterward. |
| `--delete-network-full <name>` | Like `--delete-network`, but also tears down its live state (the IPv4 MASQUERADE rule and the bridge itself for `extern`, or the whole persistent namespace for `intern`), so a network with the same name can be created fresh afterward. |
| `-p, --port-forward [<network>:]<host-port>:<container-port>` | With `--run`, forward a TCP port from the host into the container. `<network>` is optional, defaulting to the container's sole `--extern` network (an error if it joined more than one without specifying). Repeatable. Reachable via the host's real, externally-facing IP; `localhost`/loopback access has a known NAT-hairpinning limitation (see [`docs/networking-design.md`](docs/networking-design.md)). |
| `--list-processes` | List running `--run` sessions found by their pid files under `$XDG_STATE_HOME/slocker-lite/run/`, with their pid, container name, and status (`running` or `exited`). |
| `--clean-processes` | Remove stale pid files (see `--list-processes`), and any `-p`/`--port-forward` iptables rules, left behind by sessions that are no longer running (e.g. after a crash). |