<===
2026-02-26 00:13:41
- Написан bash‑скрипт, который по меню переключает SSH‑туннели для работы через SOCKS5‑прокси. [digitalocean](https://www.digitalocean.com/community/tutorials/ssh-port-forwarding)
- Список серверов описывается массивом `ip:ssh_port:user:passwd`; при выборе пункта скрипт:
- глушит старый туннель (если есть);
- поднимает новый через `sshpass + autossh` с динамическим форвардингом `-D 8080`. [mankier](https://www.mankier.com/1/autossh)
- На локальной машине постоянно доступен SOCKS5‑прокси `127.0.0.1:8080`, который идёт по SSH на выбранный сервер; срок жизни — пока живы сеть и sshd, autossh сам перезапускает сессию при обрывах. [redhat](https://www.redhat.com/en/blog/ssh-dynamic-port-forwarding)
- Работоспособность проверена:
- через `ss -nltp` (виден `ssh` слушающий `127.0.0.1:8080`);
- через `curl --proxy socks5h://127.0.0.1:8080 http://ur4uqu.com/f/` — трафик успешно ходит через туннель. [systutorials](https://www.systutorials.com/port-forwarding-using-ssh-tunnel/)
- В браузере (SeaMonkey) всё работает, когда выставлен SOCKS5 `127.0.0.1:8080`; проблема была только в привычке указать 1080. [kb.mozillazine](https://kb.mozillazine.org/Issues_with_SeaMonkey)
########################################
#!/usr/bin/env bash
DEBUG="${DEBUG:-0}" # DEBUG=1 sockssw ... включит подробный вывод
LOCAL_PORT=8080
# список серверов: ip:ssh_port:user:password
servers=(
"111.222.222.111:1234:user:passwd"
"111.222.222.112:1234:user:passwd"
)
if [[ "$DEBUG" == "1" ]]; then
set -x
fi
kill_tunnel() {
[[ "$DEBUG" == "1" ]] && echo "[DEBUG] kill_tunnel: LOCAL_PORT=${LOCAL_PORT}"
local pid
pid=$(lsof -t -iTCP:${LOCAL_PORT} -sTCP:LISTEN 2>/dev/null || true)
if [[ -n "$pid" ]]; then
echo "Убиваю старый туннель (pid $pid)..."
kill "$pid" 2>/dev/null || true
fi
pkill -f "autossh .* -D ${LOCAL_PORT}" 2>/dev/null || true
}
start_tunnel() {
local ip="$1"
local ssh_port="$2"
local user="$3"
local pass="$4"
[[ "$DEBUG" == "1" ]] && echo "[DEBUG] start_tunnel: ip=${ip} ssh_port=${ssh_port} user=${user}"
kill_tunnel
echo "Запускаю туннель через ${user}@${ip}:${ssh_port} (SOCKS5 на 127.0.0.1:${LOCAL_PORT})..."
# если DEBUG=1 — не глушим вывод autossh/ssh, чтобы видеть ошибки
if [[ "$DEBUG" == "1" ]]; then
AUTOSSH_DEBUG=1 AUTOSSH_LOGLEVEL=7 \
sshpass -p "${pass}" \
autossh -M 0 \
-o "StrictHostKeyChecking=no" \
-o "ServerAliveInterval=5" \
-o "ServerAliveCountMax=5" \
-o "ExitOnForwardFailure=yes" \
-D "${LOCAL_PORT}" -N -T \
"${user}@${ip}" -p "${ssh_port}" &
else
sshpass -p "${pass}" \
autossh -M 0 \
-o "StrictHostKeyChecking=no" \
-o "ServerAliveInterval=5" \
-o "ServerAliveCountMax=5" \
-o "ExitOnForwardFailure=yes" \
-D "${LOCAL_PORT}" -N -T \
"${user}@${ip}" -p "${ssh_port}" \
>/dev/null 2>&1 &
fi
}
menu() {
while true; do
echo
echo "Выбери сервер (SOCKS5 будет на 127.0.0.1:${LOCAL_PORT}):"
echo "0) отключить (убить туннель)"
local i=1
for srv in "${servers[@]}"; do
IFS=":" read -r ip ssh_port user pass <<<"$srv"
echo "${i}) ${user}@${ip}:${ssh_port}"
((i++))
done
echo -n "> "
read -r choice
if [[ "$choice" == "0" ]]; then
kill_tunnel
echo "Туннель отключен."
continue
fi
if ! [[ "$choice" =~ ^[0-9]+$ ]]; then
echo "Нужно число."
continue
fi
local idx=$((choice-1))
if (( idx < 0 || idx >= ${#servers[@]} )); then
echo "Нет такого пункта."
continue
fi
IFS=":" read -r ip ssh_port user pass <<<"${servers[$idx]}"
start_tunnel "$ip" "$ssh_port" "$user" "$pass"
done
}
main() {
local sel="$1"
if [[ -n "$sel" ]]; then
if [[ "$sel" == "0" ]]; then
kill_tunnel
exit 0
fi
if ! [[ "$sel" =~ ^[0-9]+$ ]]; then
echo "Нужно число."
exit 1
fi
local idx=$((sel-1))
if (( idx < 0 || idx >= ${#servers[@]} )); then
echo "Нет такого пункта."
exit 1
fi
IFS=":" read -r ip ssh_port user pass <<<"${servers[$idx]}"
start_tunnel "$ip" "$ssh_port" "$user" "$pass"
exit 0
fi
menu
}
main "$@"
Back to list