Files
local_machine/scripts/vpn/ssh-exit-mode.sh
ahauimix 1938b7c743 Expand local_machine docs and automation for connectivity, games, and ops.
Add proxy/VPN/telegram launchd and emergency runbooks; reorganize apps docs;
document JA3 CrossOver runbook and Wine troubleshooting; add GOG/HoMM game
scripts, disk cleanup guides, and gitea push-via-proxy helper. Ignore temp/.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 08:12:19 +03:00

140 lines
5.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Переключение режима выхода в интернет через SSH SOCKS (macOS / Linux).
# См. docs/connectivity/vpn/SSH_EXIT_MODES.md
set -e
SSH_EXIT_MAIN_PORT="${SSH_EXIT_MAIN_PORT:-10809}"
SSH_EXIT_STOP_PORTS="${SSH_EXIT_STOP_PORTS:-10809 1081 1082}"
SSH_EXIT_RU_HOST="${SSH_EXIT_RU_HOST:-hsites-ahau}"
SSH_SSH_STABLE_OPTS="-o TCPKeepAlive=yes -o IPQoS=throughput -o ServerAliveInterval=60 -o ServerAliveCountMax=4"
SSH_SSH_RU_OPTS="-o TCPKeepAlive=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=6"
usage() {
cat <<EOF
Usage: $(basename "$0") COMMAND
local | off | stop Остановить SSH SOCKS на портах: $SSH_EXIT_STOP_PORTS
(трафик без SOCKS — ваш локальный публичный IP).
ru SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT → выход с RU ($SSH_EXIT_RU_HOST).
ru-do SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT → Mac → RU → DO → интернет
(telegram-socks-via-do). Без RU — ошибка (без прямого Mac→DO).
status Кто слушает порты из SSH_EXIT_STOP_PORTS.
verify Показать IP без SOCKS и через 127.0.0.1:$SSH_EXIT_MAIN_PORT.
Env:
SSH_EXIT_MAIN_PORT Порт SOCKS для ru / ru-do (по умолчанию 10809).
SSH_EXIT_STOP_PORTS Порты для команды local (пробелы).
SSH_EXIT_RU_HOST Хост только-RU (по умолчанию hsites-ahau).
Требуется ~/.ssh/config: $SSH_EXIT_RU_HOST, telegram-socks-via-do (шаблон — docs/connectivity/PROXY_GUIDE.md).
EOF
}
stop_dynamic_tunnels() {
local p
for p in $SSH_EXIT_STOP_PORTS; do
pkill -f "ssh.*-D ${p} " 2>/dev/null || true
pkill -f "ssh.*-D ${p}\$" 2>/dev/null || true
done
sleep 0.4
for p in $SSH_EXIT_STOP_PORTS; do
if command -v lsof >/dev/null 2>&1; then
# shellcheck disable=SC2046
lsof -ti ":$p" -sTCP:LISTEN 2>/dev/null | xargs kill 2>/dev/null || true
fi
done
}
cmd_local() {
stop_dynamic_tunnels
echo "SSH SOCKS на портах ($SSH_EXIT_STOP_PORTS) остановлены. Выход в интернет — с локального IP (если в приложениях отключён SOCKS-прокси)."
}
ensure_port_free() {
if command -v lsof >/dev/null 2>&1; then
if lsof -i :"$SSH_EXIT_MAIN_PORT" -sTCP:LISTEN -t >/dev/null 2>&1; then
echo "Порт $SSH_EXIT_MAIN_PORT занят — освобождаю..."
pkill -f "ssh.*-D ${SSH_EXIT_MAIN_PORT} " 2>/dev/null || true
sleep 0.4
# shellcheck disable=SC2046
lsof -ti ":$SSH_EXIT_MAIN_PORT" -sTCP:LISTEN 2>/dev/null | xargs kill 2>/dev/null || true
sleep 0.3
fi
fi
if lsof -i :"$SSH_EXIT_MAIN_PORT" -sTCP:LISTEN -t >/dev/null 2>&1; then
echo "Ошибка: порт $SSH_EXIT_MAIN_PORT всё ещё занят. Закройте процесс вручную или: $0 local"
exit 1
fi
}
cmd_ru() {
ensure_port_free
# shellcheck disable=SC2086
ssh -D "$SSH_EXIT_MAIN_PORT" -f -N $SSH_SSH_RU_OPTS "$SSH_EXIT_RU_HOST"
echo "SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT$SSH_EXIT_RU_HOST (выход с IP RU-прокси)."
}
cmd_ru_do() {
ensure_port_free
if ! ssh -o BatchMode=yes -o ConnectTimeout=6 -o ConnectionAttempts=1 "$SSH_EXIT_RU_HOST" "exit 0" 2>/dev/null; then
echo "Ошибка: $SSH_EXIT_RU_HOST недоступен. Режим ru-do только Mac→RU→DO; прямой Mac→DO не используется." >&2
exit 1
fi
# shellcheck disable=SC2086
ssh -D "$SSH_EXIT_MAIN_PORT" -f -N $SSH_SSH_STABLE_OPTS telegram-socks-via-do
echo "SOCKS 127.0.0.1:$SSH_EXIT_MAIN_PORT$SSH_EXIT_RU_HOST → DO (telegram-socks-via-do). Снаружи виден IP DO."
}
cmd_status() {
local p any=0
if ! command -v lsof >/dev/null 2>&1; then
echo "lsof не найден — статус портов недоступен."
exit 1
fi
for p in $SSH_EXIT_STOP_PORTS; do
if lsof -i :"$p" -sTCP:LISTEN -t >/dev/null 2>&1; then
echo "--- :$p ---"
lsof -i :"$p" -sTCP:LISTEN
any=1
fi
done
if [ "$any" = 0 ]; then
echo "Ни один из портов не слушает: $SSH_EXIT_STOP_PORTS"
fi
}
cmd_verify() {
echo "Без прокси (локальный выход):"
curl -sS --max-time 12 https://ipinfo.io/ip 2>/dev/null || echo "(ошибка curl)"
echo ""
echo "Через SOCKS socks5h://127.0.0.1:$SSH_EXIT_MAIN_PORT:"
curl -sS --max-time 12 -x "socks5h://127.0.0.1:$SSH_EXIT_MAIN_PORT" https://ipinfo.io/ip 2>/dev/null || echo "(нет ответа — туннель не поднят или порт другой)"
echo ""
echo "Кратко через SOCKS (ip + страна):"
curl -sS --max-time 12 -x "socks5h://127.0.0.1:$SSH_EXIT_MAIN_PORT" https://ipinfo.io/json 2>/dev/null \
| sed -n 's/.*"ip": *"\([^"]*\)".*/IP: \1/p; s/.*"country": *"\([^"]*\)".*/country: \1/p' 2>/dev/null | head -4 || true
}
case "${1:-}" in
local|off|stop) cmd_local ;;
ru) cmd_ru ;;
ru-do|ru_do) cmd_ru_do ;;
status) cmd_status ;;
verify) cmd_verify ;;
-h|--help|help) usage ;;
"")
usage
exit 1
;;
*)
echo "Неизвестная команда: $1"
usage
exit 1
;;
esac