Files
luci-app-zt-gateway/docker-compose.yml
Malar Invention eb04a2597d 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

71 lines
1.7 KiB
YAML

services:
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"