#!/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}" 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}" log() { printf '[gateway-entrypoint] %s\n' "$*" } ipt() { iptables -w "$@" } 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() { 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 } 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 # Direct bypass cache: IP-адреса из ipset идут напрямую, минуя sing-box ipt -t mangle -A "$TPROXY_CHAIN" -m set --match-set "$DIRECT_BYPASS_SET" dst -j RETURN 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 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_tproxy } trap 'shutdown; exit 0' SIGTERM SIGINT wait "$APP_PID" STATUS=$? cleanup_tproxy exit "$STATUS"