68 lines
4.3 KiB
Bash
68 lines
4.3 KiB
Bash
#!/bin/sh
|
|
# aurora-vpnsel (B22): chooses the LAN tunnel. Runs under supervise-daemon (/etc/init.d/aurora-vpnsel), after aurora-vpn (which brings up
|
|
# both wg0 = WireGuard via the free-turn relay on 127.0.0.1:9000 and wg1 = direct WireGuard to the server over LTE).
|
|
# wg1 handshake fresh (age <= VS_DEAD s) -> LAN default route (table 51820) via wg1, free-turn stopped (no VK/TURN traffic).
|
|
# wg1 handshake stale -> free-turn started, LAN via wg0; wg1 keeps its keepalive, so it re-handshakes by itself
|
|
# as soon as the direct path works again -> back to wg1 after VS_BACK fresh checks.
|
|
# A healthy wg1 re-handshakes every ~120 s (REKEY_AFTER_TIME, driven by the 25 s keepalive), so age > 150 s means the direct path is gone.
|
|
# State: /run/aurora-vpnsel/mode = direct | relay. Config: /etc/aurora/vpnsel.conf (optional).
|
|
# Operator whitelist probe (every VS_WL_PERIOD s, board traffic straight over LTE, TCP connect to :443, no data sent):
|
|
# a domestic host answers and no foreign one does -> on | foreign answers -> off | nothing answers -> nodata.
|
|
# /run/aurora-vpnsel/wl = "<on|off|nodata> <unix time>". Beeline in whitelist mode drops/RSTs every non-whitelisted (foreign) IP,
|
|
# which also blocks the direct WireGuard server - so "on" explains a relay-only period.
|
|
VS_PERIOD=10 VS_DEAD=150 VS_BACK=2 VS_BOOT_WAIT=40 VS_WL_PERIOD=60
|
|
VS_WL_DOM="ya.ru vk.com gosuslugi.ru" VS_WL_FOR="1.1.1.1 8.8.8.8 9.9.9.9"
|
|
[ -f /etc/aurora/vpnsel.conf ] && . /etc/aurora/vpnsel.conf
|
|
TBL=51820; S=/run/aurora-vpnsel; mkdir -p $S; LOG=$S/vpnsel.log
|
|
now() { cut -d' ' -f1 /proc/uptime; }
|
|
log() { m="[$(now)] $*"; echo "$m" >> $LOG; echo "<5>[aurora-vpnsel] $*" > /dev/kmsg 2>/dev/null; }
|
|
age() { h=$(wg show $1 latest-handshakes 2>/dev/null | awk '{print $2; exit}'); [ -n "$h" ] && [ "$h" != 0 ] && echo $(( $(date +%s) - h )) || echo 99999; }
|
|
active() { ip route show table $TBL | awk '/^default/{print $3; exit}'; }
|
|
ft_on() { rc-service free-turn status >/dev/null 2>&1 || { rc-service free-turn start >/dev/null 2>&1; log "free-turn started"; }; }
|
|
ft_off() { rc-service free-turn status >/dev/null 2>&1 && { rc-service free-turn stop >/dev/null 2>&1; log "free-turn stopped"; }; }
|
|
wl_probe() {
|
|
d=0; f=0
|
|
for h in $VS_WL_DOM; do timeout 6 nc -z -w4 $h 443 >/dev/null 2>&1 && { d=1; break; }; done
|
|
for h in $VS_WL_FOR; do timeout 6 nc -z -w4 $h 443 >/dev/null 2>&1 && { f=1; break; }; done
|
|
if [ $f = 1 ]; then w=off; elif [ $d = 1 ]; then w=on; else w=nodata; fi
|
|
o=$(cut -d' ' -f1 $S/wl 2>/dev/null)
|
|
echo "$w $(date +%s)" > $S/wl
|
|
[ "$w" != "$o" ] && log "whitelist ${o:-?} -> $w (domestic=$d foreign=$f)"
|
|
}
|
|
use() { # use <wg0|wg1> <mode> <reason>
|
|
[ -e /sys/class/net/$1 ] || return 1
|
|
ip route replace default dev $1 table $TBL || return 1
|
|
echo $2 > $S/mode; log "LAN -> $1 ($2): $3"
|
|
}
|
|
|
|
log "=== VPNSEL START dead=${VS_DEAD}s back=${VS_BACK}x${VS_PERIOD}s whitelist probe every ${VS_WL_PERIOD}s"
|
|
wl_probe
|
|
# wait for aurora-vpn to create the tunnels (it may still be starting at boot)
|
|
i=0; while ! { [ -e /sys/class/net/wg0 ] && [ -e /sys/class/net/wg1 ]; } && [ $i -lt 120 ]; do sleep 2; i=$((i+1)); done
|
|
[ -e /sys/class/net/wg1 ] || { log "no wg1 (no /etc/wireguard/wg1.conf?): relay only"; echo relay > $S/mode; ft_on
|
|
while :; do sleep $VS_WL_PERIOD; wl_probe; done; }
|
|
# give the direct path a chance first: free-turn keeps running until wg1 proves itself
|
|
mode=$(cat $S/mode 2>/dev/null); fresh=0
|
|
if [ -z "$mode" ]; then
|
|
i=0; while [ $(age wg1) -gt $VS_DEAD ] && [ $i -lt $VS_BOOT_WAIT ]; do sleep 1; i=$((i+1)); done
|
|
if [ $(age wg1) -le $VS_DEAD ]; then use wg1 direct "handshake after ${i}s"; mode=direct; ft_off
|
|
else use wg0 relay "no direct handshake in ${VS_BOOT_WAIT}s"; mode=relay; ft_on; fi
|
|
fi
|
|
n=0
|
|
while :; do
|
|
sleep $VS_PERIOD
|
|
n=$((n+1)); [ $((n * VS_PERIOD % VS_WL_PERIOD)) = 0 ] && wl_probe
|
|
a1=$(age wg1)
|
|
case "$mode" in
|
|
direct)
|
|
[ "$(active)" = wg1 ] || use wg1 direct "route was $(active), restored"
|
|
if [ $a1 -gt $VS_DEAD ]; then
|
|
ft_on; use wg0 relay "wg1 handshake age ${a1}s > ${VS_DEAD}s"; mode=relay; fresh=0
|
|
fi;;
|
|
*)
|
|
[ "$(active)" = wg0 ] || use wg0 relay "route was $(active), restored"
|
|
ft_on
|
|
if [ $a1 -le $VS_DEAD ]; then fresh=$((fresh+1)); else fresh=0; fi
|
|
if [ $fresh -ge $VS_BACK ]; then use wg1 direct "wg1 handshake age ${a1}s (fresh ${fresh}x)"; mode=direct; ft_off; fi;;
|
|
esac
|
|
done
|