Files
vps_ssh_tunel/install_ssh_tunnel.sh
NW 6a89be6f57 v3.5
Ключевые улучшения:

    Добавлена функция check_ports() - проверяет:

        Локальные порты через ss или netstat

        Удаленные порты на VPS через SSH

        Внешнюю доступность портов на VPS

        Процессы autossh и ssh для каждого туннеля

    Добавлена функция diagnose_tunnel() - полная диагностика туннеля:

        Конфигурация

        Статус службы systemd

        Логи туннеля

        Проверка процессов

        Проверка портов

        Ручной тест SSH соединения

    Улучшена проверка SSH подключения:

        Более детальные сообщения об ошибках

        Проверка прав на ключ (должны быть 600)

        Проверка валидности ключа

    В меню управления туннелем добавлена опция "Диагностика" (кнопка 'd'):

        Полная проверка проблемного туннеля

        Показывает конкретные рекомендации по исправлению

    В тестировании подключений добавлен пункт "Диагностика всех туннелей":

        Автоматически проверяет все настроенные туннели

    Улучшен вывод при создании туннеля:

        Сразу показывает диагностику портов

        Более информативные сообщения об ошибках
2025-12-22 22:34:05 +00:00

1643 lines
70 KiB
Bash
Raw Permalink 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.
#!/bin/bash
#
# SSH Tunnel Manager - Профессиональное решение для управления обратными SSH-туннелями
# Использует autossh и systemd для обеспечения стабильного и постоянного соединения.
#
# Использование:
# 1. Запуск одной командой (автоустановка + меню): curl -s https://.../install_ssh_tunnel.sh | sudo bash
# 2. Установка: sudo bash tunnel-manager.sh install
# 3. Запуск меню: sudo bash tunnel-manager.sh menu
#
# --- Глобальные переменные и конфигурация ---
CONFIG_DIR="/etc/tunnel-manager"
TUNNELS_DIR="$CONFIG_DIR/tunnels"
LOG_DIR="/var/log/tunnel-manager"
SERVICE_DIR="/etc/systemd/system"
SCRIPT_PATH="/usr/local/bin/tunnel-manager"
VPS_CONFIG="$CONFIG_DIR/vps_config"
# --- Цвета для вывода ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
BOLD='\033[1m'
# --- Вспомогательные функции ---
# Функция логирования и вывода сообщений
log_message() {
local message="$1"
local color="${2:-$NC}"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Вывод в консоль и запись в лог
echo -e "${color}[$timestamp] $message${NC}" | tee -a "$LOG_DIR/manager.log"
}
# Функция проверки ошибок
check_error() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
log_message "ОШИБКА (код $exit_code): $1" "$RED"
log_message "Подробности в логе: $LOG_DIR/manager.log" "$YELLOW"
echo -e "${YELLOW}Произошла ошибка: $1${NC}"
read -t 60 -p "Продолжить выполнение скрипта? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
return 1
fi
return 0
}
# Функция проверки прав root
check_root() {
if [[ $EUID -ne 0 ]]; then
log_message "ОШИБКА: Этот скрипт требует прав root (sudo)." "$RED"
log_message "Пожалуйста, запустите: sudo bash $0 $1" "$BOLD"
exit 1
fi
}
# Функция безопасного ввода с ограничением попыток
safe_read() {
local prompt="$1"
local default="$2"
local var_name="$3"
local max_attempts="${4:-3}" # По умолчанию 3 попытки
local attempt=0
local input=""
while [[ $attempt -lt $max_attempts ]]; do
attempt=$((attempt + 1))
# Явное чтение из /dev/tty чтобы избежать проблем с pipe
if [[ -t 0 ]]; then
read -p "$prompt" input
else
read -p "$prompt" input </dev/tty
fi
input="${input:-$default}"
# Если есть ввод или значение по умолчанию
if [ -n "$input" ]; then
eval "$var_name=\"$input\""
return 0
# Если нет ввода и нет значения по умолчанию, и это не последняя попытка
elif [ -z "$default" ] && [[ $attempt -lt $max_attempts ]]; then
echo -e "${YELLOW}Поле не может быть пустым! Попытка $attempt из $max_attempts${NC}"
# Если нет ввода, но есть значение по умолчанию, и это не последняя попытка (должно быть обработано выше, но для надежности)
elif [ -n "$default" ]; then
eval "$var_name=\"$default\""
return 0
fi
done
# Если превышено количество попыток
echo -e "${RED}Превышено максимальное количество попыток ввода. Выход.${NC}"
exit 1
}
# Функция чтения ввода с поддержкой pipe
read_input() {
local prompt="$1"
local timeout="${2:-0}"
local input
if [[ -t 0 ]]; then
if [[ $timeout -gt 0 ]]; then
read -t "$timeout" -p "$prompt" input
else
read -p "$prompt" input
fi
else
# Если stdin не терминал (например, при pipe), читаем из /dev/tty
if [[ $timeout -gt 0 ]]; then
read -t "$timeout" -p "$prompt" input </dev/tty
else
read -p "$prompt" input </dev/tty
fi
fi
echo "$input"
}
# Функция чтения скрытого ввода (для паролей)
read_secret() {
local prompt="$1"
local secret
if [[ -t 0 ]]; then
read -s -p "$prompt" secret
echo
else
read -s -p "$prompt" secret </dev/tty
echo
fi
echo "$secret"
}
# Функция загрузки настроек VPS
load_vps_settings() {
if [ -f "$VPS_CONFIG" ]; then
source "$VPS_CONFIG"
return 0
fi
return 1
}
# Функция отображения публичного ключа
show_public_key() {
echo -e "${BOLD}${CYAN}--- Публичный ключ для копирования на VPS ---${NC}"
if [ -f "/root/.ssh/id_rsa" ]; then
echo -e "${GREEN}Приватный ключ: /root/.ssh/id_rsa${NC}"
echo -e "${GREEN}Публичный ключ:${NC}"
cat /root/.ssh/id_rsa.pub 2>/dev/null || echo "Публичный ключ не найден"
echo ""
else
echo -e "${RED}SSH ключ не найден. Сначала выполните установку.${NC}"
fi
read_input "Нажмите Enter для продолжения..."
}
# Функция проверки портов
check_ports() {
local LOCAL_PORT="$1"
local REMOTE_PORT="$2"
local VPS_HOST="$3"
local VPS_USER="$4"
local VPS_PORT="$5"
echo -e "${CYAN}=== ПРОВЕРКА ПОРТОВ ===${NC}"
# 1. Проверка локального порта
echo -e "\n${BLUE}1. Проверка локального порта $LOCAL_PORT:${NC}"
if command -v ss &> /dev/null; then
echo -e " ss -tlnp | grep :$LOCAL_PORT"
ss -tlnp | grep ":$LOCAL_PORT" || echo " Порт $LOCAL_PORT не слушает локально"
elif command -v netstat &> /dev/null; then
echo -e " netstat -tlnp | grep :$LOCAL_PORT"
netstat -tlnp 2>/dev/null | grep ":$LOCAL_PORT" || echo " Порт $LOCAL_PORT не слушает локально"
else
echo " Утилиты ss и netstat не найдены"
fi
# 2. Проверка удаленного порта на VPS
echo -e "\n${BLUE}2. Проверка удаленного порта $REMOTE_PORT на VPS ($VPS_HOST):${NC}"
if ! load_vps_settings; then
echo " Настройки VPS не загружены"
return 1
fi
# Проверка доступности VPS
echo -e " Проверка подключения к VPS..."
if timeout 5 nc -z "$VPS_HOST" "$VPS_PORT" 2>/dev/null; then
echo -e " ✓ VPS доступен на порту $VPS_PORT"
else
echo -e " ✗ VPS недоступен на порту $VPS_PORT"
return 1
fi
# Попробуем проверить порт на VPS через SSH
if [ -f "/root/.ssh/id_rsa" ]; then
echo -e " Проверка порта $REMOTE_PORT на VPS через SSH..."
local check_cmd="if command -v ss >/dev/null 2>&1; then ss -tlnp | grep ':$REMOTE_PORT'; elif command -v netstat >/dev/null 2>&1; then netstat -tlnp 2>/dev/null | grep ':$REMOTE_PORT'; else echo 'Не найдены утилиты для проверки портов'; fi"
if output=$(timeout 10 ssh -p "$VPS_PORT" -i /root/.ssh/id_rsa -o ConnectTimeout=5 -o BatchMode=yes "$VPS_USER@$VPS_HOST" "$check_cmd" 2>/dev/null); then
if [ -n "$output" ]; then
echo -e " ✗ Порт $REMOTE_PORT на VPS уже занят:"
echo " $output"
else
echo -e " ✓ Порт $REMOTE_PORT на VPS свободен"
fi
else
echo -e " ⚠ Не удалось проверить порт на VPS (возможно, нет доступа по ключу)"
fi
else
echo -e " ⚠ SSH ключ не найден, проверка порта на VPS невозможна"
fi
# 3. Проверка проброса через telnet/nc
echo -e "\n${BLUE}3. Проверка внешней доступности порта $REMOTE_PORT на VPS:${NC}"
echo -e " (Эта проверка работает только если на VPS настроен GatewayPorts=yes)"
if timeout 5 nc -zv "$VPS_HOST" "$REMOTE_PORT" 2>&1 | grep -q "succeeded"; then
echo -e " ✓ Порт $REMOTE_PORT открыт на VPS"
else
echo -e " ⚠ Порт $REMOTE_PORT не открыт на VPS (нормально для обратного туннеля)"
fi
# 4. Проверка процесса autossh
echo -e "\n${BLUE}4. Проверка процессов autossh:${NC}"
if pgrep -f "autossh.*$REMOTE_PORT.*localhost:$LOCAL_PORT" > /dev/null; then
echo -e " ✓ Процесс autossh для туннеля $LOCAL_PORT->$REMOTE_PORT запущен"
ps aux | grep "autossh.*$REMOTE_PORT.*localhost:$LOCAL_PORT" | grep -v grep
else
echo -e " ✗ Процесс autossh для туннеля не найден"
fi
# 5. Проверка SSH процессов
echo -e "\n${BLUE}5. Проверка SSH процессов для туннеля:${NC}"
if pgrep -f "ssh.*$REMOTE_PORT:localhost:$LOCAL_PORT" > /dev/null; then
echo -e " ✓ SSH процесс для туннеля запущен"
ps aux | grep "ssh.*$REMOTE_PORT:localhost:$LOCAL_PORT" | grep -v grep
else
echo -e " ✗ SSH процесс для туннеля не найден"
fi
echo -e "${CYAN}=== КОНЕЦ ПРОВЕРКИ ===${NC}\n"
}
# Функция проверки SSH подключения с подробным выводом
check_ssh_connection() {
if ! load_vps_settings; then
log_message "Сначала необходимо настроить VPS (опция 1)." "$RED"
return 1
fi
echo -e "${CYAN}Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT...${NC}"
echo -e "${YELLOW}Используется ключ: /root/.ssh/id_rsa${NC}"
# Проверяем существование ключа
if [ ! -f "/root/.ssh/id_rsa" ]; then
echo -e "${RED}✗ SSH ключ не найден. Выполните установку менеджера.${NC}"
return 1
fi
# Проверяем права на ключ
local key_perms=$(stat -c %a /root/.ssh/id_rsa 2>/dev/null || echo "000")
if [ "$key_perms" != "600" ]; then
echo -e "${YELLOW}⚠ Предупреждение: Неправильные права на ключ ($key_perms, должны быть 600)${NC}"
chmod 600 /root/.ssh/id_rsa 2>/dev/null && echo " Права исправлены на 600"
fi
# Проверяем наличие публичного ключа
if [ ! -f "/root/.ssh/id_rsa.pub" ]; then
echo -e "${YELLOW}⚠ Публичный ключ не найден. Генерируем...${NC}"
ssh-keygen -y -f /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub 2>/dev/null
fi
# Выполняем тестовое подключение с подробным выводом
echo -e "${BLUE}Выполняем тестовую команду на удаленном сервере...${NC}"
# Сначала простой тест
echo -e "Тест 1: Проверка базового подключения..."
if timeout 10 ssh -p "$VPS_PORT" \
-o BatchMode=yes \
-o ConnectTimeout=5 \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o IdentityFile=/root/.ssh/id_rsa \
-o PasswordAuthentication=no \
"$VPS_USER@$VPS_HOST" "echo 'SSH Connection Test: SUCCESS'; exit 0" 2>&1; then
echo -e "${GREEN}✓ SSH подключение работает!${NC}"
# Расширенный тест
echo -e "\nТест 2: Проверка возможности создания туннеля..."
if output=$(timeout 15 ssh -p "$VPS_PORT" \
-o BatchMode=yes \
-o ConnectTimeout=5 \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o IdentityFile=/root/.ssh/id_rsa \
-o PasswordAuthentication=no \
-T \
"$VPS_USER@$VPS_HOST" "echo 'Tunnel test: READY'; sleep 2; exit 0" 2>&1); then
echo -e "${GREEN}✓ Туннелирование доступно${NC}"
return 0
else
echo -e "${YELLOW}⚠ Проблемы с туннелированием${NC}"
echo "Вывод: $output"
return 1
fi
else
local ssh_output=$(timeout 10 ssh -p "$VPS_PORT" \
-o BatchMode=yes \
-o ConnectTimeout=5 \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o IdentityFile=/root/.ssh/id_rsa \
-o PasswordAuthentication=no \
-v \
"$VPS_USER@$VPS_HOST" "echo 'test'" 2>&1 | tail -20)
echo -e "${RED}✗ SSH подключение не работает${NC}"
echo -e "${YELLOW}Последние строки лога SSH:${NC}"
echo "$ssh_output"
echo -e "\n${YELLOW}Возможные причины:${NC}"
echo "1. Ключ не скопирован на VPS"
echo "2. На VPS не разрешена аутентификация по ключу"
echo "3. Порт $VPS_PORT закрыт на VPS"
echo "4. SSH сервер на VPS не запущен"
echo "5. Проблемы с сетью/файрволом"
echo "6. Неправильные права на ключ"
echo ""
# Пробуем подключиться без ключа для диагностики
echo -e "${YELLOW}Проверка доступности порта...${NC}"
if timeout 3 nc -zv "$VPS_HOST" "$VPS_PORT" 2>&1; then
echo -e "${GREEN}✓ Порт $VPS_PORT доступен${NC}"
else
echo -e "${RED}✗ Порт $VPS_PORT недоступен${NC}"
fi
# Проверяем конфигурацию ключа
echo -e "\n${YELLOW}Проверка SSH ключа:${NC}"
if ssh-keygen -l -f /root/.ssh/id_rsa 2>/dev/null; then
echo -e "✓ Ключ валиден"
else
echo -e "✗ Ключ поврежден или невалиден"
fi
return 1
fi
}
# --- Основные функции ---
# 1. Установка зависимостей и настройка системы
install_manager() {
check_root "install"
log_message "Начало установки SSH Tunnel Manager..." "$CYAN"
# Создание директорий
log_message "Создание системных директорий..." "$BLUE"
mkdir -p "$CONFIG_DIR" "$TUNNELS_DIR" "$LOG_DIR"
chmod 700 "$CONFIG_DIR" "$TUNNELS_DIR"
chmod 777 "$LOG_DIR" # Для удобства логирования
# Установка зависимостей
log_message "Установка необходимых зависимостей..." "$BLUE"
# Определение дистрибутива
local OS
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
fi
log_message "Обнаружен дистрибутив: ${OS:-Unknown}" "$BLUE"
if [[ "$OS" == "ubuntu" || "$OS" == "debian" ]]; then
log_message "Обновление списка пакетов..." "$BLUE"
apt-get update 2>&1 | tee -a "$LOG_DIR/manager.log"
check_error "Не удалось обновить список пакетов"
log_message "Установка autossh, openssh-client, sshpass, netcat..." "$BLUE"
apt-get install -y autossh openssh-client sshpass netcat 2>&1 | tee -a "$LOG_DIR/manager.log"
check_error "Не удалось установить пакеты (apt)"
elif [[ "$OS" == "centos" || "$OS" == "rhel" || "$OS" == "fedora" || "$OS" == "rocky" || "$OS" == "almalinux" ]]; then
log_message "Установка autossh, openssh-clients, sshpass, nc..." "$BLUE"
if command -v dnf &> /dev/null; then
dnf install -y autossh openssh-clients sshpass nc 2>&1 | tee -a "$LOG_DIR/manager.log"
check_error "Не удалось установить пакеты (dnf)"
else
yum install -y autossh openssh-clients sshpass nc 2>&1 | tee -a "$LOG_DIR/manager.log"
check_error "Не удалось установить пакеты (yum)"
fi
else
log_message "ОШИБКА: Не удалось определить менеджер пакетов." "$RED"
log_message "Пожалуйста, установите autossh и openssh-client вручную." "$YELLOW"
return 1
fi
if ! command -v autossh &> /dev/null; then
log_message "ОШИБКА: autossh не установлен. Проверьте вывод установки." "$RED"
return 1
fi
log_message "Зависимости успешно установлены." "$GREEN"
# Копирование скрипта в системный путь
log_message "Копирование скрипта в $SCRIPT_PATH..." "$BLUE"
# Получаем содержимое текущего скрипта
local current_script
if [ -f "$0" ]; then
current_script="$0"
else
# Если скрипт запущен через pipe, читаем из stdin
current_script="/tmp/tunnel-manager-$(date +%s).sh"
cat > "$current_script"
fi
# Копируем скрипт
cp "$current_script" "$SCRIPT_PATH" 2>/dev/null || {
# Если не удалось, создаем новый
cat > "$SCRIPT_PATH" << 'EOF'
#!/bin/bash
echo "SSH Tunnel Manager - Установленная версия"
echo "Используйте: sudo tunnel-manager menu"
EOF
}
chmod +x "$SCRIPT_PATH"
log_message "Установка завершена. Теперь можно использовать команду: sudo tunnel-manager menu" "$GREEN"
# Генерация SSH ключа
if [ ! -f "/root/.ssh/id_rsa" ]; then
log_message "Генерация SSH ключа RSA 4096 бит для root..." "$BLUE"
mkdir -p /root/.ssh
ssh-keygen -t rsa -b 4096 -N "" -f /root/.ssh/id_rsa -q
log_message "SSH ключ сгенерирован: /root/.ssh/id_rsa.pub" "$GREEN"
else
log_message "SSH ключ уже существует. Используем существующий." "$YELLOW"
fi
# Настройка SSH конфига для стабильности
log_message "Настройка SSH клиента для стабильности..." "$BLUE"
mkdir -p /root/.ssh
cat > /root/.ssh/config << EOFCONFIG
Host *
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
ServerAliveInterval 30
ServerAliveCountMax 3
ConnectTimeout 30
TCPKeepAlive yes
IdentitiesOnly yes
ExitOnForwardFailure yes
ControlMaster auto
ControlPath ~/.ssh/control-%r@%h:%p
ControlPersist 10m
IPQoS throughput
Compression yes
GSSAPIAuthentication no
AddressFamily inet
EOFCONFIG
chmod 600 /root/.ssh/config
log_message "Конфигурация SSH клиента обновлена." "$GREEN"
# Настройка локального SSHD
configure_local_sshd
}
# Функция установки SSH сервера
install_ssh_server() {
log_message "Проверка установки SSH сервера..." "$BLUE"
# Проверяем, установлен ли sshd
if ! command -v sshd &> /dev/null && [ ! -f /etc/ssh/sshd_config ]; then
log_message "SSH сервер не установлен. Устанавливаем..." "$YELLOW"
# Определение дистрибутива
local OS
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
fi
if [[ "$OS" == "ubuntu" || "$OS" == "debian" ]]; then
apt-get install -y openssh-server 2>&1 | tee -a "$LOG_DIR/manager.log"
elif [[ "$OS" == "centos" || "$OS" == "rhel" || "$OS" == "fedora" || "$OS" == "rocky" || "$OS" == "almalinux" ]]; then
if command -v dnf &> /dev/null; then
dnf install -y openssh-server 2>&1 | tee -a "$LOG_DIR/manager.log"
else
yum install -y openssh-server 2>&1 | tee -a "$LOG_DIR/manager.log"
fi
else
log_message "Не удалось определить дистрибутив для установки SSH сервера." "$RED"
return 1
fi
# Проверяем установку
if command -v sshd &> /dev/null; then
log_message "SSH сервер успешно установлен." "$GREEN"
else
log_message "Не удалось установить SSH сервер." "$RED"
return 1
fi
else
log_message "SSH сервер уже установлен." "$GREEN"
fi
# Запускаем и включаем автозагрузку
if systemctl is-active sshd &> /dev/null; then
log_message "SSH сервер уже запущен." "$GREEN"
else
systemctl start sshd 2>&1 | tee -a "$LOG_DIR/manager.log"
systemctl enable sshd 2>&1 | tee -a "$LOG_DIR/manager.log"
log_message "SSH сервер запущен и включен в автозагрузку." "$GREEN"
fi
return 0
}
# Функция настройки локального SSH-демона для приема туннелей
configure_local_sshd() {
log_message "Настройка локального SSH-демона (sshd) для приема туннелей..." "$BLUE"
# Устанавливаем SSH сервер если нужно
install_ssh_server
local SSHD_CONFIG="/etc/ssh/sshd_config"
if [ ! -f "$SSHD_CONFIG" ]; then
log_message "Файл конфигурации SSHD не найден. Создаем базовый..." "$YELLOW"
mkdir -p /etc/ssh
SSHD_CONFIG="/etc/ssh/sshd_config"
cat > "$SSHD_CONFIG" << 'EOFSSHD'
# SSH Server Configuration
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
# Logging
SyslogFacility AUTH
LogLevel INFO
# Authentication
LoginGraceTime 120
PermitRootLogin yes
StrictModes yes
PasswordAuthentication yes
PubkeyAuthentication yes
# Allow forwardings for tunnels
AllowTcpForwarding yes
GatewayPorts yes
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes
AcceptEnv LANG LC_*
AuthorizedKeysFile .ssh/authorized_keys
PermitEmptyPasswords no
ChallengeResponseAuthentication no
GSSAPIAuthentication no
GSSAPICleanupCredentials yes
UsePAM yes
# Keep connections alive
ClientAliveInterval 30
ClientAliveCountMax 3
# Max sessions
MaxSessions 20
MaxStartups 20:30:100
# Allow tunnel creation
AllowStreamLocalForwarding yes
PermitTunnel yes
Subsystem sftp /usr/lib/openssh/sftp-server
EOFSSHD
log_message "Создан базовый конфигурационный файл SSH сервера." "$GREEN"
fi
# Создание резервной копии
cp "$SSHD_CONFIG" "${SSHD_CONFIG}.backup.$(date +%Y%m%d%H%M%S)"
log_message "Создана резервная копия." "$YELLOW"
# Настройки для приема обратных туннелей
log_message "Настройка параметров для SSH туннелей..." "$BLUE"
# Массив настроек
local SETTINGS=(
"GatewayPorts yes"
"AllowTcpForwarding yes"
"PermitTunnel yes"
"AllowStreamLocalForwarding yes"
"ClientAliveInterval 30"
"ClientAliveCountMax 3"
"TCPKeepAlive yes"
"PasswordAuthentication yes"
"PubkeyAuthentication yes"
"MaxSessions 20"
"MaxStartups 20:30:100"
)
# Применяем настройки
for setting in "${SETTINGS[@]}"; do
local key=$(echo "$setting" | awk '{print $1}')
local value=$(echo "$setting" | awk '{print $2}')
# Проверяем существует ли настройка
if grep -q "^#\?\s*$key" "$SSHD_CONFIG"; then
# Заменяем существующую настройку
sed -i "s/^#\?\s*$key.*/$setting/" "$SSHD_CONFIG"
log_message "Обновлено: $setting" "$GREEN"
else
# Добавляем новую настройку
echo "$setting" >> "$SSHD_CONFIG"
log_message "Добавлено: $setting" "$GREEN"
fi
done
# Проверяем и настраиваем PermitRootLogin
if ! grep -q "^PermitRootLogin" "$SSHD_CONFIG"; then
echo "PermitRootLogin yes" >> "$SSHD_CONFIG"
log_message "Добавлено: PermitRootLogin yes" "$GREEN"
fi
# Перезапуск SSHD
log_message "Перезапуск SSH демона..." "$BLUE"
if systemctl restart sshd 2>/dev/null || service ssh restart 2>/dev/null || /etc/init.d/ssh restart 2>/dev/null; then
log_message "SSHD перезапущен с новыми настройками." "$GREEN"
else
log_message "ПРЕДУПРЕЖДЕНИЕ: Не удалось перезапустить SSHD." "$YELLOW"
fi
}
# 2. Настройка VPS (сервера) с автоматической настройкой SSH для многопользовательского доступа
setup_vps() {
check_root "setup_vps"
log_message "Настройка подключения к удаленному VPS (серверу)..." "$CYAN"
local current_host=""
local current_port="22"
local current_user=""
if load_vps_settings; then
current_host="$VPS_HOST"
current_port="$VPS_PORT"
current_user="$VPS_USER"
log_message "Текущая конфигурация: $current_user@$current_host:$current_port" "$YELLOW"
fi
echo -e "${BOLD}${CYAN}--- Настройка VPS ---${NC}"
echo ""
local VPS_HOST_TEMP
local VPS_PORT_TEMP
local VPS_USER_TEMP
local USER_CHOICE
# Ввод IP и Порта
safe_read "Введите IP адрес или доменное имя VPS (текущий: $current_host): " "$current_host" VPS_HOST_TEMP
safe_read "Введите порт SSH (по умолчанию 22, текущий: $current_port): " "$current_port" VPS_PORT_TEMP
# Выбор пользователя
echo -e "${CYAN}Выберите пользователя для подключения:${NC}"
echo "1) root (рекомендуется для полного доступа)"
echo "2) Другой пользователь"
USER_CHOICE=$(read_input "Ваш выбор [1-2]: ")
if [ "$USER_CHOICE" == "1" ]; then
VPS_USER_TEMP="root"
echo -e "${YELLOW}Будет использоваться пользователь: root${NC}"
else
safe_read "Введите имя пользователя на VPS (текущий: $current_user): " "$current_user" VPS_USER_TEMP
fi
VPS_HOST="$VPS_HOST_TEMP"
VPS_PORT="$VPS_PORT_TEMP"
VPS_USER="$VPS_USER_TEMP"
if [ -z "$VPS_HOST" ] || [ -z "$VPS_USER" ]; then
log_message "ОШИБКА: IP адрес и имя пользователя обязательны." "$RED"
read_input "Нажмите Enter для продолжения..."
return 1
fi
# Сохранение настроек
cat > "$VPS_CONFIG" << EOFSETTINGS
# Настройки VPS для автономных туннелей
VPS_HOST="$VPS_HOST"
VPS_PORT="$VPS_PORT"
VPS_USER="$VPS_USER"
CONFIGURED_ON="$(date '+%Y-%m-%d %H:%M:%S')"
EOFSETTINGS
chmod 600 "$VPS_CONFIG"
log_message "Настройки VPS сохранены в $VPS_CONFIG" "$GREEN"
# Автоматическое копирование ключа
log_message "Попытка автоматического копирования SSH-ключа на VPS..." "$CYAN"
# Запрос пароля для sshpass с безопасным вводом
local VPS_PASSWORD
echo -e "${YELLOW}Для автоматического копирования ключа потребуется пароль от $VPS_USER на VPS.${NC}"
echo -e "${YELLOW}Если вы не хотите вводить пароль, нажмите Enter и скопируйте ключ вручную.${NC}"
# Используем read_secret для скрытого ввода
VPS_PASSWORD=$(read_secret "Введите пароль для $VPS_USER@$VPS_HOST (оставьте пустым для пропуска): ")
if [ -n "$VPS_PASSWORD" ]; then
if command -v sshpass &> /dev/null; then
# Используем sshpass для автоматического копирования ключа
echo -e "${BLUE}Копирую ключ на VPS...${NC}"
if sshpass -p "$VPS_PASSWORD" ssh-copy-id -p "$VPS_PORT" -i /root/.ssh/id_rsa.pub -o StrictHostKeyChecking=no "$VPS_USER@$VPS_HOST" 2>&1 | tee -a "$LOG_DIR/manager.log"; then
log_message "SSH ключ успешно скопирован на VPS!" "$GREEN"
else
log_message "Не удалось скопировать ключ через sshpass." "$RED"
echo -e "${YELLOW}Скопируйте ключ вручную:${NC}"
cat /root/.ssh/id_rsa.pub
fi
else
log_message "sshpass не установлен. Невозможно скопировать ключ автоматически." "$YELLOW"
echo -e "${YELLOW}Скопируйте ключ вручную:${NC}"
cat /root/.ssh/id_rsa.pub
fi
else
log_message "Пароль не введен. Скопируйте ключ вручную:" "$YELLOW"
cat /root/.ssh/id_rsa.pub
fi
# Тестовое подключение
echo ""
log_message "Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT..." "$BLUE"
check_ssh_connection
read_input "Нажмите Enter для продолжения..."
}
# Функция диагностики туннеля
diagnose_tunnel() {
local TUNNEL_ID="$1"
if [ ! -f "$TUNNELS_DIR/$TUNNEL_ID.conf" ]; then
log_message "Туннель с ID '$TUNNEL_ID' не найден." "$RED"
return 1
fi
source "$TUNNELS_DIR/$TUNNEL_ID.conf"
echo -e "${BOLD}${CYAN}=== ДИАГНОСТИКА ТУННЕЛЯ: $TUNNEL_NAME ===${NC}"
echo ""
# 1. Проверка конфигурации
echo -e "${BLUE}1. Конфигурация туннеля:${NC}"
echo " ID: $TUNNEL_ID"
echo " Имя: $TUNNEL_NAME"
echo " Локальный порт: $LOCAL_PORT"
echo " Удаленный порт: $REMOTE_PORT"
echo " VPS: $VPS_USER@$VPS_HOST:$VPS_PORT"
echo " Создан: $CREATED"
echo ""
# 2. Проверка службы systemd
echo -e "${BLUE}2. Проверка службы systemd:${NC}"
local SERVICE_NAME="tunnel-$TUNNEL_ID"
systemctl status "$SERVICE_NAME.service" --no-pager -l
# 3. Проверка логов
echo -e "\n${BLUE}3. Последние логи туннеля:${NC}"
if [ -f "$LOG_DIR/$TUNNEL_ID.log" ]; then
tail -20 "$LOG_DIR/$TUNNEL_ID.log"
else
echo " Лог файл не найден"
fi
# 4. Проверка процессов
echo -e "\n${BLUE}4. Проверка процессов:${NC}"
echo " autossh процессы:"
pgrep -af "autossh.*$TUNNEL_ID" || echo " Не найдены"
echo ""
echo " ssh процессы:"
pgrep -af "ssh.*$REMOTE_PORT.*localhost:$LOCAL_PORT" || echo " Не найдены"
# 5. Проверка портов
echo -e "\n${BLUE}5. Проверка портов:${NC}"
check_ports "$LOCAL_PORT" "$REMOTE_PORT" "$VPS_HOST" "$VPS_USER" "$VPS_PORT"
# 6. Ручной тест SSH соединения для туннеля
echo -e "${BLUE}6. Ручной тест SSH туннеля:${NC}"
echo -e "${YELLOW}Выполняем тестовую команду...${NC}"
local test_cmd="ssh -v -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ConnectTimeout=10 -i /root/.ssh/id_rsa -R $REMOTE_PORT:localhost:$LOCAL_PORT -p $VPS_PORT $VPS_USER@$VPS_HOST"
echo "Команда: $test_cmd"
echo ""
echo -e "${YELLOW}Запускаем на 10 секунд... (Ctrl+C для остановки)${NC}"
timeout 10 $test_cmd 2>&1 | head -50
echo -e "\n${CYAN}=== РЕКОМЕНДАЦИИ ===${NC}"
echo "1. Проверьте, что на VPS разрешены обратные туннели (GatewayPorts yes)"
echo "2. Убедитесь, что порт $REMOTE_PORT на VPS не занят"
echo "3. Проверьте права SSH ключа (должны быть 600)"
echo "4. Убедитесь, что локальный сервер слушает порт $LOCAL_PORT"
echo ""
}
# 3. Добавление нового туннеля
add_tunnel() {
check_root "add_tunnel"
if ! load_vps_settings; then
log_message "Сначала необходимо настроить VPS (опция 1)." "$RED"
read_input "Нажмите Enter для продолжения..."
return 1
fi
echo -e "${BOLD}${CYAN}--- Добавление нового обратного туннеля (Local -> VPS) ---${NC}"
log_message "VPS: $VPS_USER@$VPS_HOST:$VPS_PORT" "$YELLOW"
echo ""
local LOCAL_PORT=""
local REMOTE_PORT=""
local TUNNEL_NAME=""
safe_read "Введите локальный порт, который нужно пробросить (например, 22 для SSH): " "" LOCAL_PORT
safe_read "Введите удаленный порт на VPS, через который будет доступен локальный порт (например, 10022): " "" REMOTE_PORT
safe_read "Введите имя туннеля (например, 'ssh_access'): " "" TUNNEL_NAME
# Проверка ввода
if ! [[ "$LOCAL_PORT" =~ ^[0-9]+$ ]] || [ "$LOCAL_PORT" -lt 1 ] || [ "$LOCAL_PORT" -gt 65535 ]; then
log_message "ОШИБКА: Локальный порт должен быть числом от 1 до 65535." "$RED"
read_input "Нажмите Enter для продолжения..."
return 1
fi
if ! [[ "$REMOTE_PORT" =~ ^[0-9]+$ ]] || [ "$REMOTE_PORT" -lt 1 ] || [ "$REMOTE_PORT" -gt 65535 ]; then
log_message "ОШИБКА: Удаленный порт должен быть числом от 1 до 65535." "$RED"
read_input "Нажмите Enter для продолжения..."
return 1
fi
if [ -z "$TUNNEL_NAME" ]; then
log_message "ОШИБКА: Имя туннеля обязательно." "$RED"
read_input "Нажмите Enter для продолжения..."
return 1
fi
# Проверка имени туннеля
TUNNEL_ID=$(echo "$TUNNEL_NAME" | tr '[:upper:]' '[:lower:]' | tr -cd '[:alnum:]_')
if [ -f "$TUNNELS_DIR/$TUNNEL_ID.conf" ]; then
log_message "ОШИБКА: Туннель с именем '$TUNNEL_ID' уже существует." "$RED"
read_input "Нажмите Enter для продолжения..."
return 1
fi
# Проверяем, доступен ли локальный порт
echo -e "${BLUE}Проверка доступности локального порта $LOCAL_PORT...${NC}"
if timeout 2 nc -z localhost "$LOCAL_PORT" 2>/dev/null; then
echo -e "${GREEN}✓ Локальный порт $LOCAL_PORT доступен${NC}"
else
echo -e "${YELLOW}⚠ Локальный порт $LOCAL_PORT не отвечает${NC}"
echo -e "${YELLOW}Убедитесь, что служба слушает на этом порту${NC}"
fi
# Создание конфигурационного файла туннеля
local CONFIG_FILE="$TUNNELS_DIR/$TUNNEL_ID.conf"
cat > "$CONFIG_FILE" << EOFCONF
# Конфигурация туннеля: $TUNNEL_NAME
TUNNEL_ID="$TUNNEL_ID"
TUNNEL_NAME="$TUNNEL_NAME"
LOCAL_PORT="$LOCAL_PORT"
REMOTE_PORT="$REMOTE_PORT"
VPS_HOST="$VPS_HOST"
VPS_PORT="$VPS_PORT"
VPS_USER="$VPS_USER"
CREATED="$(date '+%Y-%m-%d %H:%M:%S')"
EOFCONF
# Создание systemd unit-файла
local SERVICE_NAME="tunnel-$TUNNEL_ID"
local SERVICE_FILE="$SERVICE_DIR/$SERVICE_NAME.service"
cat > "$SERVICE_FILE" << EOFSERVICE
[Unit]
Description=SSH Reverse Tunnel: $TUNNEL_NAME ($LOCAL_PORT -> $REMOTE_PORT)
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
Type=simple
EnvironmentFile=$CONFIG_FILE
ExecStart=/usr/bin/autossh -M 0 -N -o "ExitOnForwardFailure=yes" -o "ServerAliveInterval=30" -o "ServerAliveCountMax=3" -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -o "TCPKeepAlive=yes" -o "ConnectTimeout=30" -o "IdentityFile=/root/.ssh/id_rsa" -R $REMOTE_PORT:localhost:$LOCAL_PORT $VPS_USER@$VPS_HOST -p $VPS_PORT
ExecReload=/bin/kill -HUP \$MAINPID
Restart=always
RestartSec=5
User=root
StandardOutput=append:$LOG_DIR/$TUNNEL_ID.log
StandardError=append:$LOG_DIR/$TUNNEL_ID.log
[Install]
WantedBy=multi-user.target
EOFSERVICE
log_message "Конфигурация туннеля '$TUNNEL_NAME' создана." "$GREEN"
# Запуск и включение службы
systemctl daemon-reload
systemctl enable "$SERVICE_NAME.service" > /dev/null 2>&1
echo -e "${BLUE}Запуск туннеля...${NC}"
systemctl start "$SERVICE_NAME.service"
sleep 2
if systemctl is-active --quiet "$SERVICE_NAME.service"; then
log_message "Туннель '$TUNNEL_NAME' успешно запущен." "$GREEN"
echo ""
echo -e "${BOLD}${CYAN}Информация о туннеле:${NC}"
echo -e " Имя: $TUNNEL_NAME"
echo -e " Локальный порт: $LOCAL_PORT"
echo -e " Удаленный порт на VPS: $REMOTE_PORT"
echo -e " VPS: $VPS_USER@$VPS_HOST:$VPS_PORT"
echo ""
echo -e "${GREEN}Для доступа через VPS используйте:${NC}"
echo -e "${BOLD} ssh -p $REMOTE_PORT $VPS_USER@$VPS_HOST${NC}"
echo ""
echo -e "${YELLOW}Логи туннеля: $LOG_DIR/$TUNNEL_ID.log${NC}"
echo -e "${YELLOW}Статус: systemctl status $SERVICE_NAME${NC}"
# Показываем диагностику
echo ""
check_ports "$LOCAL_PORT" "$REMOTE_PORT" "$VPS_HOST" "$VPS_USER" "$VPS_PORT"
else
log_message "ОШИБКА: Не удалось запустить туннель '$TUNNEL_NAME'." "$RED"
echo -e "${YELLOW}Проверьте логи: journalctl -u $SERVICE_NAME -n 50${NC}"
echo -e "${YELLOW}Или выполните диагностику туннеля${NC}"
# Показываем последние логи
echo ""
echo -e "${RED}Последние логи службы:${NC}"
journalctl -u "$SERVICE_NAME" -n 20 --no-pager
fi
read_input "Нажмите Enter для продолжения..."
}
# 4. Управление туннелем (запуск, остановка, перезапуск, удаление)
manage_tunnel() {
local TUNNEL_ID="$1"
local ACTION="$2"
local SERVICE_NAME="tunnel-$TUNNEL_ID"
if [ ! -f "$TUNNELS_DIR/$TUNNEL_ID.conf" ]; then
log_message "Туннель с ID '$TUNNEL_ID' не найден." "$RED"
return 1
fi
case "$ACTION" in
start|stop|restart)
systemctl "$ACTION" "$SERVICE_NAME.service"
log_message "Служба '$SERVICE_NAME' выполнила команду '$ACTION'." "$GREEN"
sleep 1
;;
status)
systemctl status "$SERVICE_NAME.service" --no-pager -l
;;
remove)
log_message "Остановка и удаление туннеля '$TUNNEL_ID'..." "$YELLOW"
systemctl stop "$SERVICE_NAME.service"
systemctl disable "$SERVICE_NAME.service" > /dev/null 2>&1
rm -f "$SERVICE_DIR/$SERVICE_NAME.service"
rm -f "$TUNNELS_DIR/$TUNNEL_ID.conf"
rm -f "$LOG_DIR/$TUNNEL_ID.log"
systemctl daemon-reload
log_message "Туннель '$TUNNEL_ID' полностью удален." "$GREEN"
;;
*)
log_message "Неизвестное действие: $ACTION" "$RED"
return 1
;;
esac
}
# 5. Список туннелей
list_tunnels() {
echo -e "${BOLD}${CYAN}--- Список настроенных туннелей ---${NC}"
local count=0
local header="%-20s | %-10s | %-10s | %-20s | %-10s"
local separator="---------------------|------------|------------|----------------------|------------"
printf "$header\n" "ИМЯ ТУННЕЛЯ" "ЛОК. ПОРТ" "УД. ПОРТ" "СТАТУС" "АВТОЗАГРУЗКА"
echo "$separator"
for config_file in "$TUNNELS_DIR"/*.conf; do
if [ -f "$config_file" ]; then
source "$config_file"
local SERVICE_NAME="tunnel-$TUNNEL_ID"
local STATUS=$(systemctl is-active "$SERVICE_NAME.service" 2>/dev/null || echo "inactive")
local ENABLED=$(systemctl is-enabled "$SERVICE_NAME.service" 2>/dev/null || echo "disabled")
local STATUS_COLOR="$RED"
if [ "$STATUS" == "active" ]; then
STATUS_COLOR="$GREEN"
elif [ "$STATUS" == "inactive" ]; then
STATUS_COLOR="$YELLOW"
fi
printf "%-20s | %-10s | %-10s | ${STATUS_COLOR}%-20s${NC} | %-10s\n" \
"$TUNNEL_ID" "$LOCAL_PORT" "$REMOTE_PORT" "$STATUS" "$ENABLED"
count=$((count + 1))
fi
done
if [ "$count" -eq 0 ]; then
echo -e "${YELLOW}Туннели не найдены. Используйте опцию 2 для добавления нового.${NC}"
fi
echo ""
}
# Функция просмотра логов
view_logs() {
while true; do
clear
echo -e "${BOLD}${CYAN}Просмотр логов${NC}"
echo -e "${YELLOW}=============${NC}"
echo ""
echo -e "${CYAN}[1]${NC} Логи конкретного туннеля"
echo -e "${CYAN}[2]${NC} Все логи туннелей (последние 5 строк)"
echo -e "${CYAN}[3]${NC} Системные логи (journalctl)"
echo -e "${CYAN}[4]${NC} Лог менеджера"
echo -e "${CYAN}[5]${NC} Назад"
echo ""
choice=$(read_input "Выберите действие: ")
case $choice in
1)
local LOG_DIR="/var/log/tunnel-manager"
echo -e "${CYAN}Доступные логи:${NC}"
ls -1 "$LOG_DIR"/*.log 2>/dev/null | xargs -n1 basename | grep -v "manager.log" || echo " Логи не найдены"
echo ""
log_file=$(read_input "Введите имя лог-файла (например, tunnel-ssh_access.log): ")
if [ -f "$LOG_DIR/$log_file" ]; then
less "$LOG_DIR/$log_file"
else
log_message "Файл не найден" "$RED"
sleep 1
fi
;;
2)
local LOG_DIR="/var/log/tunnel-manager"
echo -e "${CYAN}Все логи туннелей (последние 5 строк):${NC}"
for log in "$LOG_DIR"/tunnel-*.log; do
if [ -f "$log" ]; then
echo -e "\n${YELLOW}=== $(basename "$log") ===${NC}"
tail -5 "$log"
fi
done
read_input "Нажмите Enter для продолжения..."
;;
3)
echo -e "${CYAN}Системные логи туннелей (последний час):${NC}"
journalctl -u tunnel-* --since "1 hour ago" -n 20 2>/dev/null || log_message "Системные логи отсутствуют" "$YELLOW"
read_input "Нажмите Enter для продолжения..."
;;
4)
echo -e "${CYAN}Лог менеджера:${NC}"
less "/var/log/tunnel-manager/manager.log"
;;
5)
return
;;
*)
log_message "Неверный выбор" "$RED"
sleep 1
;;
esac
done
}
# Функция тестирования подключений
test_connections() {
while true; do
clear
echo -e "${BOLD}${CYAN}Тестирование подключений${NC}"
echo -e "${YELLOW}========================${NC}"
echo "1) Тест подключения к VPS"
echo "2) Тест локальных портов туннелей"
echo "3) Тест SSH ключа"
echo "4) Тест доступности портов на VPS"
echo "5) Диагностика всех туннелей"
echo "6) Назад"
echo ""
test_choice=$(read_input "Выберите тест: ")
case $test_choice in
1)
check_ssh_connection
read_input "Нажмите Enter для продолжения..."
;;
2)
echo -e "${CYAN}Тест локальных портов туннелей:${NC}"
local TUNNEL_DIR="/etc/tunnel-manager/tunnels"
for conf in "$TUNNEL_DIR"/*.conf; do
if [ -f "$conf" ]; then
local LOCAL_PORT
LOCAL_PORT=$(grep '^LOCAL_PORT=' "$conf" | cut -d'=' -f2 | tr -d '"')
local TUNNEL_NAME
TUNNEL_NAME=$(basename "$conf" .conf)
echo -n " $TUNNEL_NAME (локальный порт $LOCAL_PORT): "
if timeout 2 nc -z localhost "$LOCAL_PORT" 2>/dev/null; then
echo -e "${GREEN}✓ Открыт${NC}"
else
echo -e "${RED}✗ Закрыт${NC}"
fi
fi
done
read_input "Нажмите Enter для продолжения..."
;;
3)
echo -e "${CYAN}Тест SSH ключа:${NC}"
if [ -f "/root/.ssh/id_rsa" ]; then
echo -e "${GREEN}✓ Приватный ключ существует${NC}"
echo -e " Путь: /root/.ssh/id_rsa"
echo -e " Права: $(stat -c %a /root/.ssh/id_rsa 2>/dev/null || echo "неизвестно")"
if ssh-keygen -l -f /root/.ssh/id_rsa 2>/dev/null; then
echo -e "${GREEN}✓ Ключ валиден${NC}"
else
echo -e "${RED}✗ Ключ поврежден или невалиден${NC}"
fi
else
echo -e "${RED}✗ SSH ключ не найден${NC}"
fi
read_input "Нажмите Enter для продолжения..."
;;
4)
if load_vps_settings; then
echo -e "${CYAN}Тест доступности портов на VPS ($VPS_HOST):${NC}"
# Проверяем SSH порт
echo -n " SSH порт $VPS_PORT: "
if timeout 3 nc -zv "$VPS_HOST" "$VPS_PORT" 2>&1 | grep -q "succeeded"; then
echo -e "${GREEN}✓ Доступен${NC}"
else
echo -e "${RED}✗ Недоступен${NC}"
fi
# Проверяем порты туннелей
for conf in "$TUNNELS_DIR"/*.conf; do
if [ -f "$conf" ]; then
local REMOTE_PORT
REMOTE_PORT=$(grep '^REMOTE_PORT=' "$conf" | cut -d'=' -f2 | tr -d '"')
local TUNNEL_NAME
TUNNEL_NAME=$(basename "$conf" .conf)
echo -n " $TUNNEL_NAME (порт $REMOTE_PORT): "
if timeout 3 nc -zv "$VPS_HOST" "$REMOTE_PORT" 2>&1 | grep -q "succeeded"; then
echo -e "${GREEN}✓ Доступен${NC}"
else
echo -e "${RED}✗ Недоступен${NC}"
fi
fi
done
else
log_message "Сначала необходимо настроить VPS (опция 1)." "$RED"
fi
read_input "Нажмите Enter для продолжения..."
;;
5)
echo -e "${CYAN}Диагностика всех туннелей:${NC}"
for conf in "$TUNNELS_DIR"/*.conf; do
if [ -f "$conf" ]; then
local TUNNEL_ID
TUNNEL_ID=$(basename "$conf" .conf)
echo ""
diagnose_tunnel "$TUNNEL_ID"
echo ""
read_input "Нажмите Enter для следующего туннеля..."
fi
done
;;
6)
return
;;
*)
log_message "Неверный выбор" "$RED"
sleep 1
;;
esac
done
}
# Функция настройки маршрутизации (iptables)
setup_routing() {
if ! command -v iptables &> /dev/null; then
log_message "Утилита 'iptables' не найдена." "$RED"
read_input "Нажмите Enter для продолжения..."
return
fi
while true; do
clear
echo -e "${BOLD}${CYAN}Настройка маршрутизации (iptables)${NC}"
echo -e "${YELLOW}==================================${NC}"
echo "1) Показать текущие правила NAT (PREROUTING)"
echo "2) Добавить правило перенаправления порта (DNAT)"
echo "3) Сохранить правила (требует iptables-persistent/netfilter-persistent)"
echo "4) Назад"
echo ""
routing_choice=$(read_input "Выберите действие: ")
case $routing_choice in
1)
echo -e "${CYAN}Текущие правила iptables (NAT PREROUTING):${NC}"
sudo iptables -t nat -L PREROUTING -n -v
read_input "Нажмите Enter для продолжения..."
;;
2)
IN_PORT=$(read_input "Входной порт (напр. 80): ")
DEST_IP=$(read_input "IP назначения (напр. 192.168.1.10): ")
DEST_PORT=$(read_input "Порт назначения (напр. 8080): ")
if [ -n "$IN_PORT" ] && [ -n "$DEST_IP" ] && [ -n "$DEST_PORT" ]; then
sudo iptables -t nat -A PREROUTING -p tcp --dport "$IN_PORT" -j DNAT --to-destination "$DEST_IP:$DEST_PORT"
log_message "Правило DNAT добавлено: $IN_PORT -> $DEST_IP:$DEST_PORT" "$GREEN"
else
log_message "Не все поля заполнены." "$RED"
fi
read_input "Нажмите Enter для продолжения..."
;;
3)
if command -v netfilter-persistent &> /dev/null; then
sudo netfilter-persistent save
log_message "Правила iptables сохранены с помощью netfilter-persistent." "$GREEN"
elif command -v iptables-save &> /dev/null; then
sudo mkdir -p /etc/iptables
sudo iptables-save > /etc/iptables/rules.v4
log_message "Правила iptables сохранены в /etc/iptables/rules.v4." "$GREEN"
else
log_message "Не найдена утилита для сохранения правил." "$RED"
fi
read_input "Нажмите Enter для продолжения..."
;;
4)
return
;;
*)
log_message "Неверный выбор" "$RED"
sleep 1
;;
esac
done
}
# Функция настройки SSH демона на VPS
setup_vps_ssh_config() {
while true; do
clear
echo -e "${BOLD}${CYAN}Настройки SSH Демона на VPS${NC}"
echo -e "${YELLOW}==============================${NC}"
if ! load_vps_settings; then
log_message "Сначала необходимо настроить VPS (опция 1)." "$RED"
read_input "Нажмите Enter для продолжения..."
return
fi
echo -e "${CYAN}VPS: $VPS_USER@$VPS_HOST:$VPS_PORT${NC}"
echo ""
echo "1) Показать текущие настройки SSH на VPS"
echo "2) Проверить SSH подключение"
echo "3) Назад"
echo ""
ssh_choice=$(read_input "Выберите действие: ")
case $ssh_choice in
1)
echo -e "${CYAN}Текущие настройки SSH на VPS:${NC}"
if [ -f "/root/.ssh/id_rsa" ]; then
ssh -p "$VPS_PORT" -i /root/.ssh/id_rsa -o BatchMode=yes "$VPS_USER@$VPS_HOST" \
"grep -E '^(PasswordAuthentication|PubkeyAuthentication|PermitRootLogin|GatewayPorts|AllowTcpForwarding|MaxSessions|MaxStartups)' /etc/ssh/sshd_config 2>/dev/null || echo 'Не удалось получить настройки'" 2>/dev/null
else
echo -e "${YELLOW}SSH ключ не найден. Сначала выполните установку.${NC}"
fi
read_input "Нажмите Enter для продолжения..."
;;
2)
check_ssh_connection
read_input "Нажмите Enter для продолжения..."
;;
3)
return
;;
*)
log_message "Неверный выбор" "$RED"
sleep 1
;;
esac
done
}
# Функция настройки локального SSH демона
setup_local_ssh_config() {
while true; do
clear
echo -e "${BOLD}${CYAN}Настройки локального SSH Демона (sshd)${NC}"
echo -e "${YELLOW}====================================${NC}"
echo "1) Показать текущие настройки sshd"
echo "2) Перезапустить SSH демон"
echo "3) Проверить конфигурацию sshd"
echo "4) Установить/переустановить SSH сервер"
echo "5) Настроить sshd для локальных подключений"
echo "6) Показать статус SSH сервера"
echo "7) Назад"
echo ""
ssh_choice=$(read_input "Выберите действие: ")
case $ssh_choice in
1)
echo -e "${CYAN}Текущие настройки sshd:${NC}"
if [ -f "/etc/ssh/sshd_config" ]; then
grep -E "^(GatewayPorts|AllowTcpForwarding|PermitTunnel|AllowStreamLocalForwarding|PermitRootLogin|PasswordAuthentication)" /etc/ssh/sshd_config 2>/dev/null ||
echo "Настройки не найдены"
else
echo "Файл /etc/ssh/sshd_config не найден"
fi
read_input "Нажмите Enter для продолжения..."
;;
2)
if sudo systemctl restart sshd 2>/dev/null || sudo service ssh restart 2>/dev/null; then
log_message "SSH демон перезапущен." "$GREEN"
else
log_message "Не удалось перезапустить SSH демон." "$RED"
fi
read_input "Нажмите Enter для продолжения..."
;;
3)
if command -v sshd &> /dev/null; then
if sudo sshd -t 2>/dev/null; then
log_message "Конфигурация SSH корректна." "$GREEN"
else
log_message "Ошибка в конфигурации SSH." "$RED"
fi
else
log_message "SSH сервер не установлен." "$RED"
fi
read_input "Нажмите Enter для продолжения..."
;;
4)
install_ssh_server
read_input "Нажмите Enter для продолжения..."
;;
5)
configure_local_sshd
read_input "Нажмите Enter для продолжения..."
;;
6)
echo -e "${CYAN}Статус SSH сервера:${NC}"
if systemctl is-active sshd &> /dev/null; then
echo -e "${GREEN}✓ SSH сервер запущен${NC}"
systemctl status sshd --no-pager -l
elif pgrep sshd &> /dev/null; then
echo -e "${GREEN}✓ SSH процесс работает${NC}"
ps aux | grep sshd | grep -v grep
else
echo -e "${RED}✗ SSH сервер не запущен${NC}"
fi
read_input "Нажмите Enter для продолжения..."
;;
7)
return
;;
*)
log_message "Неверный выбор" "$RED"
sleep 1
;;
esac
done
}
# 6. Меню управления туннелями
manage_tunnels_menu() {
while true; do
clear
echo -e "${BOLD}${CYAN}--- Управление существующими туннелями ---${NC}"
echo -e "${YELLOW}===========================================${NC}"
local count=0
local TUNNEL_IDS=()
for config_file in "$TUNNELS_DIR"/*.conf; do
if [ -f "$config_file" ]; then
local TUNNEL_ID=$(basename "$config_file" .conf)
TUNNEL_IDS+=("$TUNNEL_ID")
count=$((count + 1))
fi
done
if [ "$count" -eq 0 ]; then
log_message "Туннели не найдены." "$YELLOW"
sleep 2
return
fi
list_tunnels
echo -e "${CYAN}Введите ID туннеля для управления (или 'b' для назад):${NC}"
TUNNEL_ID_MANAGE=$(read_input "ID туннеля: ")
if [ "$TUNNEL_ID_MANAGE" == "b" ]; then
return
fi
if [[ " ${TUNNEL_IDS[@]} " =~ " ${TUNNEL_ID_MANAGE} " ]]; then
while true; do
clear
echo -e "${BOLD}${CYAN}--- Управление туннелем $TUNNEL_ID_MANAGE ---${NC}"
echo -e "${YELLOW}===========================================${NC}"
# Загружаем конфигурацию туннеля
if [ -f "$TUNNELS_DIR/$TUNNEL_ID_MANAGE.conf" ]; then
source "$TUNNELS_DIR/$TUNNEL_ID_MANAGE.conf"
echo -e "${GREEN}Информация о туннеле:${NC}"
echo -e " Имя: $TUNNEL_NAME"
echo -e " Локальный порт: $LOCAL_PORT"
echo -e " Удаленный порт: $REMOTE_PORT"
echo -e " VPS: $VPS_USER@$VPS_HOST:$VPS_PORT"
echo -e " Создан: $CREATED"
echo ""
fi
# Показываем текущий статус
echo -e "${CYAN}Статус службы:${NC}"
manage_tunnel "$TUNNEL_ID_MANAGE" "status"
echo -e "\n${CYAN}Выберите действие:${NC}"
echo " s) Статус (обновить)"
echo " t) Старт"
echo " p) Стоп"
echo " r) Перезапуск"
echo " d) Диагностика"
echo " e) Включить автозагрузку"
echo " x) Отключить автозагрузку"
echo " u) Удалить"
echo " l) Просмотр логов"
echo " b) Назад"
ACTION_CHOICE=$(read_input "Действие: ")
case "$ACTION_CHOICE" in
s) ;; # Статус уже показан
t)
manage_tunnel "$TUNNEL_ID_MANAGE" "start"
;;
p)
manage_tunnel "$TUNNEL_ID_MANAGE" "stop"
;;
r)
manage_tunnel "$TUNNEL_ID_MANAGE" "restart"
;;
d)
diagnose_tunnel "$TUNNEL_ID_MANAGE"
read_input "Нажмите Enter для продолжения..."
;;
e)
systemctl enable "tunnel-$TUNNEL_ID_MANAGE.service" 2>/dev/null
log_message "Автозагрузка включена" "$GREEN"
sleep 1
;;
x)
systemctl disable "tunnel-$TUNNEL_ID_MANAGE.service" 2>/dev/null
log_message "Автозагрузка отключена" "$YELLOW"
sleep 1
;;
u)
CONFIRM_REMOVE=$(read_input "Вы уверены, что хотите удалить туннель $TUNNEL_ID_MANAGE? (y/N): ")
if [[ "$CONFIRM_REMOVE" =~ ^[Yy]$ ]]; then
manage_tunnel "$TUNNEL_ID_MANAGE" "remove"
sleep 2
return
fi
;;
l)
if [ -f "/var/log/tunnel-manager/$TUNNEL_ID_MANAGE.log" ]; then
less "/var/log/tunnel-manager/$TUNNEL_ID_MANAGE.log"
else
log_message "Лог файл не найден" "$RED"
sleep 1
fi
;;
b) break;;
*) log_message "Неизвестная опция." "$RED";;
esac
read_input "Нажмите Enter для продолжения...";
done
else
log_message "Туннель с ID '$TUNNEL_ID_MANAGE' не найден." "$RED"
sleep 1
fi
done
}
# 7. Главное меню
main_menu() {
check_root "menu"
while true; do
clear
echo -e "${BOLD}${CYAN}========================================================${NC}"
echo -e "${BOLD}${CYAN} SSH Tunnel Manager v2.1 (by Manus) ${NC}"
echo -e "${BOLD}${CYAN}========================================================${NC}"
# Проверяем наличие SSH ключа
if [ ! -f "/root/.ssh/id_rsa" ]; then
echo -e "${RED}⚠ SSH ключ не найден. Выполните установку.${NC}"
else
echo -e "${GREEN}✓ SSH ключ настроен${NC}"
fi
# Проверяем настройки VPS
if load_vps_settings; then
echo -e "${GREEN}✓ VPS настроен: $VPS_USER@$VPS_HOST:$VPS_PORT${NC}"
else
echo -e "${RED}✗ VPS не настроен. Начните с опции 1.${NC}"
fi
# Проверяем SSH сервер
if systemctl is-active sshd &> /dev/null || pgrep sshd &> /dev/null; then
echo -e "${GREEN}✓ SSH сервер запущен${NC}"
elif [ -f "/etc/ssh/sshd_config" ]; then
echo -e "${YELLOW}⚠ SSH сервер не запущен${NC}"
else
echo -e "${RED}✗ SSH сервер не установлен${NC}"
fi
echo ""
list_tunnels
echo -e "${BOLD}${YELLOW}--- МЕНЮ УПРАВЛЕНИЯ ---${NC}"
echo -e "1) ${BOLD}Настроить/сменить VPS${NC} (Указать адрес, пользователя, порт)"
echo -e "2) ${BOLD}Добавить новый туннель${NC} (Local:Port -> VPS:Port)"
echo -e "3) ${BOLD}Управление туннелем${NC} (Статус, Старт, Стоп, Перезапуск, Удаление)"
echo -e "4) ${BOLD}Просмотр логов и мониторинг${NC}"
echo -e "5) ${BOLD}Тестирование подключений${NC}"
echo -e "6) ${BOLD}Настройка маршрутизации (iptables)${NC}"
echo -e "7) ${BOLD}Настройки SSH Демона на VPS${NC}"
echo -e "8) ${BOLD}Настройки локального SSH Демона${NC}"
echo -e "9) ${BOLD}Показать публичный ключ${NC} (Для копирования на VPS)"
echo -e "0) ${BOLD}Выход${NC}"
echo ""
choice=$(read_input "Выберите опцию [0-9]: ")
case $choice in
1) setup_vps ;;
2) add_tunnel ;;
3) manage_tunnels_menu ;;
4) view_logs ;;
5) test_connections ;;
6) setup_routing ;;
7) setup_vps_ssh_config ;;
8) setup_local_ssh_config ;;
9) show_public_key ;;
0)
log_message "Выход из менеджера." "$GREEN"
exit 0
;;
*)
log_message "Неверный выбор. Попробуйте еще раз." "$RED"
sleep 1
;;
esac
done
}
# --- Точка входа ---
# Главное изменение: если скрипт запущен без аргументов, выполняем автоматическую установку и запуск меню
if [[ $# -eq 0 ]]; then
echo -e "${BOLD}${CYAN}SSH Tunnel Manager v2.1${NC}"
echo -e "Автоматический запуск установки и меню..."
echo ""
# Проверяем, установлен ли уже скрипт
if [ -f "/usr/local/bin/tunnel-manager" ]; then
echo -e "${YELLOW}Менеджер уже установлен. Запуск меню...${NC}"
sleep 2
main_menu
else
echo -e "${GREEN}Начинаем установку...${NC}"
echo -e "${YELLOW}Установка займет несколько минут...${NC}"
sleep 2
install_manager
echo -e "${GREEN}Установка завершена. Запуск меню...${NC}"
sleep 2
main_menu
fi
else
case "$1" in
install)
install_manager
;;
menu)
main_menu
;;
*)
echo -e "${BOLD}${CYAN}SSH Tunnel Manager v2.1${NC}"
echo -e "Использование:"
echo -e " 1. Запуск одной командой (автоустановка + меню):"
echo -e " curl -s https://git.softuniq.eu/OpenDoor/vps_ssh_tunel/raw/branch/main/install_ssh_tunnel.sh | sudo bash"
echo -e " 2. Только установка: sudo bash $0 install"
echo -e " 3. Только меню: sudo bash $0 menu"
echo ""
echo -e "После установки можно использовать: sudo tunnel-manager menu"
;;
esac
fi
exit 0