feat: implement ZeroTier exit gateway switcher
Adds the luci-app-zt-gateway package: a LuCI app + rpcd/ucode backend +
shell switch script that reconfigures which remote ZeroTier node acts as
the internet exit gateway for WIBLAN clients (10.11.13.0/24).
- Makefile (luci.mk, arch-independent)
- UCI config skeleton with three sample gateways
- rpcd ACL + menu entry
- zt-gateway.uc rpcd backend exposing status / switch / health /
drain_status / cancel_drain ubus methods
- zt-gateway-switch shell script implementing force + graceful modes:
* force: pre-flight ping, atomic route replace, conntrack flush,
UCI/hotplug/rc.local persistence
* graceful: dual-table drain using CONNMARK fwmark 0x100 at
priority 99, background drain monitor with two-consecutive-zero
completion and timeout-forced fallback to force
- LuCI overview.js: gateway radio list, mode select, drain progress
panel, cancel-drain button, health polling
- Docker test harness (docker-compose + Dockerfile.router +
router/gw entrypoints) exercising the switch script against real
iproute2/iptables/conntrack on two simulated exit nodes
Verified against the harness: force switch, graceful drain to natural
completion, pre-flight blocking of unreachable gateways (force + graceful),
and drain-timeout forced fallback.
2026-06-19 02:51:21 +05:30
|
|
|
services:
|
2026-07-12 23:42:54 +05:30
|
|
|
# OpenWRT LuCI container — web UI for Playwright E2E tests
|
|
|
|
|
# Uses the pre-imported zt-gateway-luci:dev image (OpenWrt 25.12.4 rootfs
|
|
|
|
|
# with LuCI + zt-gateway application overlay). No docker build needed.
|
|
|
|
|
openwrt-luci:
|
|
|
|
|
image: zt-gateway-luci:dev
|
|
|
|
|
container_name: openwrt-luci
|
|
|
|
|
privileged: true
|
|
|
|
|
cap_add:
|
|
|
|
|
- NET_ADMIN
|
|
|
|
|
- SYS_ADMIN
|
|
|
|
|
ports:
|
|
|
|
|
- "8080:80"
|
|
|
|
|
networks:
|
|
|
|
|
zt-exit-net:
|
|
|
|
|
ipv4_address: "10.99.12.2"
|
|
|
|
|
environment:
|
|
|
|
|
ZTG_SKIP_PERSIST: "1"
|
|
|
|
|
ZTG_PING_IFACE: "br-zt"
|
|
|
|
|
ZTG_WIBLAN_CIDR: "10.99.13.0/24"
|
|
|
|
|
entrypoint: ["/entrypoint.sh"]
|
|
|
|
|
volumes:
|
|
|
|
|
# Overlay fixed application files (rpcd backend, LuCI view, config, menu, acl)
|
|
|
|
|
- ./root/usr/share/rpcd/ucode/zt-gateway.uc:/usr/share/rpcd/ucode/zt-gateway.uc:ro
|
|
|
|
|
- ./root/usr/share/rpcd/ucode/system.uc:/usr/share/rpcd/ucode/system.uc:ro
|
|
|
|
|
- ./root/usr/share/ucode/luci/runtime.uc:/usr/share/ucode/luci/runtime.uc:ro
|
|
|
|
|
- ./root/usr/share/luci/menu.d/luci-app-zt-gateway.json:/usr/share/luci/menu.d/luci-app-zt-gateway.json:ro
|
|
|
|
|
- ./root/usr/share/rpcd/acl.d/luci-app-zt-gateway.json:/usr/share/rpcd/acl.d/luci-app-zt-gateway.json:ro
|
|
|
|
|
# Stage host config so the entrypoint can copy it into the writable overlay.
|
|
|
|
|
- ./root/etc/config:/host-config:ro
|
|
|
|
|
- ./htdocs/luci-static/resources/view/zt-gateway/overview.js:/www/luci-static/resources/view/zt-gateway/overview.js:ro
|
|
|
|
|
- ./docker/openwrt-luci-entrypoint.sh:/entrypoint.sh:ro
|
|
|
|
|
|
|
|
|
|
# Arch-based router — CLI routing tests
|
feat: implement ZeroTier exit gateway switcher
Adds the luci-app-zt-gateway package: a LuCI app + rpcd/ucode backend +
shell switch script that reconfigures which remote ZeroTier node acts as
the internet exit gateway for WIBLAN clients (10.11.13.0/24).
- Makefile (luci.mk, arch-independent)
- UCI config skeleton with three sample gateways
- rpcd ACL + menu entry
- zt-gateway.uc rpcd backend exposing status / switch / health /
drain_status / cancel_drain ubus methods
- zt-gateway-switch shell script implementing force + graceful modes:
* force: pre-flight ping, atomic route replace, conntrack flush,
UCI/hotplug/rc.local persistence
* graceful: dual-table drain using CONNMARK fwmark 0x100 at
priority 99, background drain monitor with two-consecutive-zero
completion and timeout-forced fallback to force
- LuCI overview.js: gateway radio list, mode select, drain progress
panel, cancel-drain button, health polling
- Docker test harness (docker-compose + Dockerfile.router +
router/gw entrypoints) exercising the switch script against real
iproute2/iptables/conntrack on two simulated exit nodes
Verified against the harness: force switch, graceful drain to natural
completion, pre-flight blocking of unreachable gateways (force + graceful),
and drain-timeout forced fallback.
2026-06-19 02:51:21 +05:30
|
|
|
openwrt-router:
|
|
|
|
|
build:
|
|
|
|
|
context: .
|
|
|
|
|
dockerfile: Dockerfile.router
|
|
|
|
|
image: zt-gateway-router:dev
|
|
|
|
|
container_name: openwrt-router
|
|
|
|
|
privileged: true
|
|
|
|
|
cap_add:
|
|
|
|
|
- NET_ADMIN
|
|
|
|
|
- SYS_ADMIN
|
|
|
|
|
networks:
|
|
|
|
|
zt-gateway-lan:
|
|
|
|
|
ipv4_address: "10.99.13.1"
|
|
|
|
|
zt-exit-net:
|
|
|
|
|
ipv4_address: "10.99.12.1"
|
|
|
|
|
environment:
|
|
|
|
|
ZTG_SKIP_PERSIST: "1"
|
|
|
|
|
ZTG_PING_IFACE: "br-zt"
|
|
|
|
|
ZTG_WIBLAN_CIDR: "10.99.13.0/24"
|
|
|
|
|
|
|
|
|
|
wiblan-client:
|
|
|
|
|
image: archlinux:latest
|
|
|
|
|
container_name: wiblan-client
|
|
|
|
|
networks:
|
|
|
|
|
zt-gateway-lan:
|
|
|
|
|
ipv4_address: "10.99.13.10"
|
|
|
|
|
cap_add:
|
|
|
|
|
- NET_ADMIN
|
|
|
|
|
command: ["sleep", "infinity"]
|
|
|
|
|
|
|
|
|
|
zt-gw-amsterdam:
|
|
|
|
|
image: archlinux:latest
|
|
|
|
|
container_name: zt-gw-amsterdam
|
|
|
|
|
privileged: true
|
|
|
|
|
cap_add:
|
|
|
|
|
- NET_ADMIN
|
|
|
|
|
networks:
|
|
|
|
|
zt-exit-net:
|
|
|
|
|
ipv4_address: "10.99.12.3"
|
|
|
|
|
volumes:
|
|
|
|
|
- ./docker/gw-entrypoint.sh:/usr/local/bin/gw-entrypoint.sh:ro
|
|
|
|
|
entrypoint: ["/bin/sh", "/usr/local/bin/gw-entrypoint.sh", "10.99.12.3", "10.99.12.1"]
|
|
|
|
|
|
|
|
|
|
zt-gw-tirunelveli:
|
|
|
|
|
image: archlinux:latest
|
|
|
|
|
container_name: zt-gw-tirunelveli
|
|
|
|
|
privileged: true
|
|
|
|
|
cap_add:
|
|
|
|
|
- NET_ADMIN
|
|
|
|
|
networks:
|
|
|
|
|
zt-exit-net:
|
|
|
|
|
ipv4_address: "10.99.12.5"
|
|
|
|
|
volumes:
|
|
|
|
|
- ./docker/gw-entrypoint.sh:/usr/local/bin/gw-entrypoint.sh:ro
|
|
|
|
|
entrypoint: ["/bin/sh", "/usr/local/bin/gw-entrypoint.sh", "10.99.12.5", "10.99.12.1"]
|
|
|
|
|
|
|
|
|
|
networks:
|
|
|
|
|
zt-gateway-lan:
|
|
|
|
|
driver: bridge
|
|
|
|
|
ipam:
|
|
|
|
|
config:
|
|
|
|
|
- subnet: "10.99.13.0/24"
|
|
|
|
|
gateway: "10.99.13.1"
|
|
|
|
|
zt-exit-net:
|
|
|
|
|
driver: bridge
|
|
|
|
|
ipam:
|
|
|
|
|
config:
|
|
|
|
|
- subnet: "10.99.12.0/24"
|
|
|
|
|
gateway: "10.99.12.1"
|