Some checks failed
Build and Deploy Gateway / build-and-deploy (push) Failing after 13s
125 lines
4.8 KiB
Bash
125 lines
4.8 KiB
Bash
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
TPROXY_PORT="${TPROXY_PORT:-7895}"
|
||
TPROXY_MARK="${TPROXY_MARK:-1}"
|
||
TPROXY_TABLE="${TPROXY_TABLE:-100}"
|
||
TPROXY_CHAIN="${TPROXY_CHAIN:-VPN_PROXY_TPROXY}"
|
||
PROXY_PORT="${PROXY_PORT:-8080}"
|
||
PROXY_BIND_IP="${PROXY_BIND_IP:-0.0.0.0}"
|
||
PROXY_INPUT_CHAIN="${PROXY_INPUT_CHAIN:-VPN_PROXY_INPUT}"
|
||
PROXY_FIREWALL="${PROXY_FIREWALL:-true}"
|
||
PROXY_ALLOWED_CIDRS="${PROXY_ALLOWED_CIDRS:-10.0.0.0/8 172.16.0.0/12 192.168.0.0/16}"
|
||
BYPASS_CIDRS="${BYPASS_CIDRS:-0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4}"
|
||
# Имя ipset для IP-адресов, которые sing-box отправил напрямую (direct bypass cache)
|
||
DIRECT_BYPASS_SET="${DIRECT_BYPASS_SET:-vpn_direct_bypass}"
|
||
# TTL записи в ipset (секунды). По умолчанию 1 час.
|
||
DIRECT_BYPASS_TTL="${DIRECT_BYPASS_TTL:-3600}"
|
||
# Direct bypass cache выключен по умолчанию, потому что он обходит global rules.
|
||
DIRECT_BYPASS_CACHE="${DIRECT_BYPASS_CACHE:-false}"
|
||
|
||
log() {
|
||
printf '[gateway-entrypoint] %s\n' "$*"
|
||
}
|
||
|
||
ipt() {
|
||
iptables -w "$@"
|
||
}
|
||
|
||
cleanup_proxy_firewall() {
|
||
ipt -D INPUT -p tcp --dport "$PROXY_PORT" -j "$PROXY_INPUT_CHAIN" 2>/dev/null || true
|
||
ipt -D INPUT -p udp --dport "$PROXY_PORT" -j "$PROXY_INPUT_CHAIN" 2>/dev/null || true
|
||
ipt -F "$PROXY_INPUT_CHAIN" 2>/dev/null || true
|
||
ipt -X "$PROXY_INPUT_CHAIN" 2>/dev/null || true
|
||
}
|
||
|
||
cleanup_tproxy() {
|
||
log "cleanup tproxy rules"
|
||
ipt -t mangle -D PREROUTING -j "$TPROXY_CHAIN" 2>/dev/null || true
|
||
ipt -t mangle -F "$TPROXY_CHAIN" 2>/dev/null || true
|
||
ipt -t mangle -X "$TPROXY_CHAIN" 2>/dev/null || true
|
||
ip rule del fwmark "$TPROXY_MARK" table "$TPROXY_TABLE" 2>/dev/null || true
|
||
ip route flush table "$TPROXY_TABLE" 2>/dev/null || true
|
||
# ipset не чистим при завершении — TTL сам истечёт
|
||
}
|
||
|
||
setup_direct_bypass_set() {
|
||
if [[ "$DIRECT_BYPASS_CACHE" != "true" ]]; then
|
||
export DIRECT_BYPASS_CACHE
|
||
return
|
||
fi
|
||
|
||
log "setup ipset ${DIRECT_BYPASS_SET} (timeout=${DIRECT_BYPASS_TTL}s)"
|
||
# Создаём с timeout; если уже существует — не трогаем (сохраняем накопленные записи)
|
||
ipset create "$DIRECT_BYPASS_SET" hash:ip timeout "$DIRECT_BYPASS_TTL" 2>/dev/null || true
|
||
# Экспортируем имя для использования в Node.js через env
|
||
export DIRECT_BYPASS_SET DIRECT_BYPASS_TTL DIRECT_BYPASS_CACHE
|
||
}
|
||
|
||
setup_proxy_firewall() {
|
||
if [[ "$PROXY_FIREWALL" != "true" || "$PROXY_BIND_IP" == "127.0.0.1" || "$PROXY_BIND_IP" == "::1" ]]; then
|
||
return
|
||
fi
|
||
|
||
log "setup proxy firewall for :${PROXY_PORT} (${PROXY_ALLOWED_CIDRS})"
|
||
cleanup_proxy_firewall
|
||
|
||
ipt -N "$PROXY_INPUT_CHAIN"
|
||
for cidr in $PROXY_ALLOWED_CIDRS; do
|
||
ipt -A "$PROXY_INPUT_CHAIN" -s "$cidr" -j RETURN
|
||
done
|
||
ipt -A "$PROXY_INPUT_CHAIN" -j DROP
|
||
ipt -I INPUT -p tcp --dport "$PROXY_PORT" -j "$PROXY_INPUT_CHAIN"
|
||
ipt -I INPUT -p udp --dport "$PROXY_PORT" -j "$PROXY_INPUT_CHAIN"
|
||
}
|
||
|
||
setup_tproxy() {
|
||
log "setup tproxy on port ${TPROXY_PORT}, mark ${TPROXY_MARK}, table ${TPROXY_TABLE}"
|
||
cleanup_tproxy
|
||
|
||
ip rule add fwmark "$TPROXY_MARK" table "$TPROXY_TABLE" 2>/dev/null || true
|
||
ip route replace local 0.0.0.0/0 dev lo table "$TPROXY_TABLE"
|
||
|
||
ipt -t mangle -N "$TPROXY_CHAIN"
|
||
# Пропускаем пакеты, адресованные самому хосту (ответы на исходящие соединения sing-box)
|
||
ipt -t mangle -A "$TPROXY_CHAIN" -m addrtype --dst-type LOCAL -j RETURN
|
||
ipt -t mangle -A "$TPROXY_CHAIN" -m mark --mark "$TPROXY_MARK" -j RETURN
|
||
|
||
if [[ "$DIRECT_BYPASS_CACHE" == "true" ]]; then
|
||
# Direct bypass cache: IP-адреса из ipset идут напрямую, минуя sing-box.
|
||
# Включайте только если готовы к тому, что global rules для этих dst IP не будут проверяться.
|
||
ipt -t mangle -A "$TPROXY_CHAIN" -m set --match-set "$DIRECT_BYPASS_SET" dst -j RETURN
|
||
fi
|
||
|
||
for cidr in $BYPASS_CIDRS; do
|
||
ipt -t mangle -A "$TPROXY_CHAIN" -d "$cidr" -j RETURN
|
||
done
|
||
|
||
ipt -t mangle -A "$TPROXY_CHAIN" -p tcp -j TPROXY --on-port "$TPROXY_PORT" --tproxy-mark "$TPROXY_MARK/$TPROXY_MARK"
|
||
ipt -t mangle -A "$TPROXY_CHAIN" -p udp -j TPROXY --on-port "$TPROXY_PORT" --tproxy-mark "$TPROXY_MARK/$TPROXY_MARK"
|
||
ipt -t mangle -A PREROUTING -j "$TPROXY_CHAIN"
|
||
}
|
||
|
||
setup_direct_bypass_set
|
||
setup_tproxy
|
||
setup_proxy_firewall
|
||
|
||
node /app/src/server/index.js &
|
||
APP_PID=$!
|
||
|
||
shutdown() {
|
||
log "shutdown requested"
|
||
kill "$APP_PID" 2>/dev/null || true
|
||
wait "$APP_PID" 2>/dev/null || true
|
||
cleanup_proxy_firewall
|
||
cleanup_tproxy
|
||
}
|
||
|
||
trap 'shutdown; exit 0' SIGTERM SIGINT
|
||
|
||
wait "$APP_PID"
|
||
STATUS=$?
|
||
cleanup_proxy_firewall
|
||
cleanup_tproxy
|
||
exit "$STATUS"
|