tailscale-proxy: add the missing IKEv2 VPN front, and correct the stale exit node
This file has been unsafe to deploy for two separate reasons. Both are fixed here, and the result is now byte-identical in effective config to what actually runs on the client-02 host (verified by diffing `docker compose config` on both). 1. ts-vpn + ikev2 were missing entirely. The IKEv2 VPN front has run on the host since 2026-09-05, but was never mirrored here — this file defined only ts-proxy, proxy and telemt. Deploying it as-is would have taken the VPN down for the Windows and iOS clients. Added both services, plus ikev2-egress.sh, which the ikev2 service mounts and cannot start without. ts-vpn is a SECOND Tailscale node in kernel/TUN mode (unlike ts-proxy, which is userspace): it forwards raw IP packets rather than TCP streams, so a userspace SOCKS5 is useless for it. It owns the network namespace that ikev2 joins via network_mode, which is also why the ports and sysctls live on ts-vpn and not on ikev2 — Docker forbids net.* sysctls on a network_mode:service container. 2. ts-proxy still pointed at the pre-migration exit node. TS_EXTRA_ARGS --exit-node=100.121.234.85 -> --exit-node=100.106.197.99 TS_HOSTNAME / hostname technohim-lan-proxy -> 02-tekhnohim-lan-proxy 100.121.234.85 has not existed since the 2026-08-27 tailnet migration. This is worse than a dead setting: with the exit node absent this stack does NOT fail closed — it silently egresses through the local ISP, so a redeploy from this repo would have turned a censorship-avoiding proxy into a plain local-egress one while still reporting healthy. This drift was recorded as an open issue in the migration write-up on 2026-08-27; these are the exact substitutions it prescribed. Not included, deliberately: ts-vpn.env and ikev2.env, which hold TS_AUTHKEY and the VPN credentials. Like every other config in this stack they are staged on the host by hand — a git push does not deploy config here, and these must never enter git. Both extracted files were scanned for secrets before being added.
This commit is contained in:
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/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 <table> <chain> <rule...>
|
||||
t=$1; c=$2; shift 2
|
||||
iptables -w -t "$t" -C "$c" "$@" 2>/dev/null || { iptables -w -t "$t" -A "$c" "$@" && log "iptables -t $t -A $c $*"; }
|
||||
}
|
||||
ensure_ipt_first() { # like ensure_ipt but inserts at the top (hwdsl2 ends FORWARD with -j DROP)
|
||||
t=$1; c=$2; shift 2
|
||||
iptables -w -t "$t" -C "$c" "$@" 2>/dev/null || { iptables -w -t "$t" -I "$c" 1 "$@" && log "iptables -t $t -I $c $*"; }
|
||||
}
|
||||
ensure_rule() { # ensure_rule <pref> <selector...>
|
||||
p=$1; shift
|
||||
ip rule list | grep -q "^$p:" || { ip rule add pref "$p" "$@" && log "ip rule $p: $*"; }
|
||||
}
|
||||
|
||||
fix_left() {
|
||||
conf=/etc/ipsec.d/ikev2.conf
|
||||
[ -f "$conf" ] || return 0
|
||||
ip4=$(ip -4 -o addr show dev eth0 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -1)
|
||||
[ -n "$ip4" ] || return 0
|
||||
grep -q "^ left=$ip4\$" "$conf" && return 0
|
||||
sed -i "s|^ left=.*| left=$ip4|" "$conf" && log "ikev2.conf: left=$ip4 (was %defaultroute -> tailscale0)"
|
||||
if ipsec auto --replace ikev2-cp >/dev/null 2>&1; then log "ipsec auto --replace ikev2-cp"; fi
|
||||
}
|
||||
|
||||
|
||||
while :; do
|
||||
fix_left
|
||||
if [ -n "$LAN_NET" ] && ip link show "$LAN_IF" >/dev/null 2>&1; then
|
||||
ensure_rule 5010 to "$LAN_NET" lookup main
|
||||
ensure_ipt_first filter FORWARD -s "$VPN_NET" -d "$LAN_NET" -o "$LAN_IF" -j ACCEPT
|
||||
ensure_ipt_first filter FORWARD -d "$VPN_NET" -s "$LAN_NET" -i "$LAN_IF" \
|
||||
-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
ensure_ipt nat POSTROUTING -s "$VPN_NET" -d "$LAN_NET" -o "$LAN_IF" -j MASQUERADE
|
||||
fi
|
||||
if ip link show "$TS_IF" >/dev/null 2>&1; then
|
||||
ensure_rule 5001 ipproto udp sport 500 lookup main
|
||||
ensure_rule 5002 ipproto udp sport 4500 lookup main
|
||||
ensure_rule 5003 ipproto 50 lookup main
|
||||
ensure_ipt_first filter FORWARD -s "$VPN_NET" -o "$TS_IF" -j ACCEPT
|
||||
ensure_ipt_first filter FORWARD -d "$VPN_NET" -i "$TS_IF" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
ensure_ipt nat POSTROUTING -o "$TS_IF" -j MASQUERADE
|
||||
ensure_ipt mangle FORWARD -o "$TS_IF" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
|
||||
fi
|
||||
sleep 30
|
||||
done
|
||||
Reference in New Issue
Block a user