add: bypass entries for forwarded source networks #120

Merged
mysticalsoap merged 2 commits from feat/network-bypass into trunk 2026-08-22 16:41:22 -04:00
Owner

Problem

The bypass only reaches local sockets: forwarded packets (containers, LAN clients) have no socket to put in the cgroup, so they ride the tunnel with no opt-out. A container running its own VPN gets silently double-tunnelled — measured at roughly half its throughput on #116 — and its connection state becomes coupled to the host VPN's.

Fix

Network bypass entries: user-listed source networks whose forwarded traffic is marked into table 11 via a dedicated mangle chain (aqomui_bypass_net), jumped to from PREROUTING — the routing decision sits before FORWARD, so that is the only chain where the mark can steer policy routing. Optional protocol/port qualifiers keep an entry as narrow as one service's tunnel transport.

  • Entries live in config.json (bypass_networks) and ride the existing cfgupdate channel — no new D-Bus surface; load_firewall already reloads settings before every bypass() re-apply, and reconcile_bypass restores the rules across service restarts (the manual workaround rule from #116 did not survive a day).
  • The chain is flushed and repopulated on every apply, removed on teardown with clear_fwmark_rules-style tolerance — idempotent, no memory of a previous service's state needed.
  • Entries are validated with a shared utils.parse_network_entry (GUI at entry time, service at apply time — they end up as root iptables arguments; one bad entry is skipped and logged, not fatal to the rest).
  • GUI: networks list on the bypass tab below the app list, same row/remove pattern; add-dialog in aqomui/gui/netbypass.py.
  • firewall.ipt_cmd extracted from add_rule (first commit) so chain management can pick the right binary without add_rule's check-then-add logging quirks.

Verification

  • tests/test_utils.py parse/reject cases, tests/test_bypass.py rule-builder cases; full suite green (the two test_mgmt socket failures exist on trunk).
  • Live round pending before merge: branch install, add the gluetun entry (172.18.7.0/24 udp 51820) via the GUI, confirm zero bytes on tun_aqomui during an in-container download, then a service restart to confirm reconcile restores the chain.

Closes #116.

🤖 Generated with Claude Code

**Problem** The bypass only reaches local sockets: forwarded packets (containers, LAN clients) have no socket to put in the cgroup, so they ride the tunnel with no opt-out. A container running its own VPN gets silently double-tunnelled — measured at roughly half its throughput on #116 — and its connection state becomes coupled to the host VPN's. **Fix** Network bypass entries: user-listed source networks whose forwarded traffic is marked into table 11 via a dedicated mangle chain (`aqomui_bypass_net`), jumped to from PREROUTING — the routing decision sits before FORWARD, so that is the only chain where the mark can steer policy routing. Optional protocol/port qualifiers keep an entry as narrow as one service's tunnel transport. - Entries live in `config.json` (`bypass_networks`) and ride the existing cfgupdate channel — no new D-Bus surface; `load_firewall` already reloads settings before every `bypass()` re-apply, and `reconcile_bypass` restores the rules across service restarts (the manual workaround rule from #116 did not survive a day). - The chain is flushed and repopulated on every apply, removed on teardown with `clear_fwmark_rules`-style tolerance — idempotent, no memory of a previous service's state needed. - Entries are validated with a shared `utils.parse_network_entry` (GUI at entry time, service at apply time — they end up as root iptables arguments; one bad entry is skipped and logged, not fatal to the rest). - GUI: networks list on the bypass tab below the app list, same row/remove pattern; add-dialog in `aqomui/gui/netbypass.py`. - `firewall.ipt_cmd` extracted from `add_rule` (first commit) so chain management can pick the right binary without `add_rule`'s check-then-add logging quirks. **Verification** - `tests/test_utils.py` parse/reject cases, `tests/test_bypass.py` rule-builder cases; full suite green (the two `test_mgmt` socket failures exist on trunk). - Live round pending before merge: branch install, add the gluetun entry (`172.18.7.0/24` udp 51820) via the GUI, confirm zero bytes on `tun_aqomui` during an in-container download, then a service restart to confirm reconcile restores the chain. Closes #116. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
add: bypass entries for forwarded source networks (#116)
All checks were successful
ci / test (pull_request) Successful in 34s
ci / test (push) Successful in 27s
e315650f43
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

Live round complete on the installed branch build:

  • Entry added via the GUI dialog (172.18.7.0/24, udp, 51820); in-container download immediately stopped crossing tun_aqomui (RX delta 0 over 150 MB; 113 MiB/100 MB before) at direct-WireGuard speed (55-65 MB/s vs ~29 double-tunnelled).
  • Service restart: reconcile_bypass rebuilt table 11, the fwmark rule and the network chain with no GUI running-state involved; after reconnecting the main tunnel, gluetun still exits direct (RX delta 0, 42-58 MB/s).
  • Other containers on the same bridge remain tunnelled (background traffic still visible on tun_aqomui).

Merge-ready.

Live round complete on the installed branch build: - Entry added via the GUI dialog (172.18.7.0/24, udp, 51820); in-container download immediately stopped crossing tun_aqomui (RX delta 0 over 150 MB; 113 MiB/100 MB before) at direct-WireGuard speed (55-65 MB/s vs ~29 double-tunnelled). - Service restart: reconcile_bypass rebuilt table 11, the fwmark rule and the network chain with no GUI running-state involved; after reconnecting the main tunnel, gluetun still exits direct (RX delta 0, 42-58 MB/s). - Other containers on the same bridge remain tunnelled (background traffic still visible on tun_aqomui). Merge-ready.
mysticalsoap deleted branch feat/network-bypass 2026-08-22 16:41:22 -04:00
Sign in to join this conversation.
No description provided.