#!/bin/sh # ikev2-egress.sh - runs inside ts-lan-ikev2, which shares ts-vpn's network # namespace. Tailscale (kernel mode, --netfilter-mode=off) only installs the # policy routing (default -> tailscale0 via table 52); this loop owns the rest # and is idempotent, so a container restart or a late tailscale0 is harmless. # # 1. ip rules ahead of Tailscale's 52xx rules: replies of the IKE/NAT-T/ESP # server itself must leave via the docker bridge (main table), otherwise # the SYN-ACK-equivalent goes into the tunnel and no client ever connects. # 2. FORWARD accepts for VPN<->tailscale0 ahead of hwdsl2's final -j DROP, and # MASQUERADE everything leaving tailscale0 to the node's own 100.x address - # the exit node's WireGuard AllowedIPs drops any other source. # 3. MSS clamp to the tunnel PMTU (tailscale0 is MTU 1280; hwdsl2 clamps 1360). # 4. Pin the Libreswan conn to eth0's address: hwdsl2 writes left=%defaultroute, # which resolves through Tailscale's policy routing to the tailscale0 address, # so IKE packets arriving on the bridge match no conn (NO_PROPOSAL_CHOSEN). # 5. LAN access: one ip rule sends LAN_NET out the docker bridge (main table) # instead of table 52, plus FORWARD accepts and a MASQUERADE to the bridge # address - LAN hosts have no route back to the VPN pool. Scoped to LAN_NET # only: every other destination, including the docker bridges themselves, # still falls through to table 52 = tailscale0. Set LAN_NET empty to restore # the original egress-only behaviour. # The LAN block sits OUTSIDE the tailscale0 guard on purpose: LAN access does not # depend on the exit node, so a client still reaches the office if the tunnel is # down (internet then fails closed, which is what we want). TS_IF=tailscale0 LAN_IF=eth0 VPN_NET="192.168.43.0/24" # hwdsl2 IKEv2 address pool (rightaddresspool) LAN_NET="192.168.0.0/22" # client-02 head office (Kirochnaya). Branch sites # are NOT routed here - see the deployment note. log() { echo "[ikev2-egress] $*"; } ensure_ipt() { # ensure_ipt