Files
vps_ssh_tunel/install_ssh_tunnel.sh
2025-12-22 19:35:31 +00:00

950 lines
41 KiB
Bash
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.
#!/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 -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))
read -p "$prompt" input
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
}
# Функция загрузки настроек 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.pub" ]; then
echo -e "${GREEN}Ключ RSA:${NC}"
cat /root/.ssh/id_rsa.pub
echo ""
fi
read -p "Нажмите Enter для продолжения..."
}
# Функция проверки 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}"
if timeout 10 ssh -p "$VPS_PORT" -o BatchMode=yes -o ConnectTimeout=5 "$VPS_USER@$VPS_HOST" "echo 'SSH Connection OK'" 2>/dev/null; then
echo -e "${GREEN}✓ SSH подключение работает${NC}"
return 0
else
echo -e "${RED}✗ SSH подключение не работает${NC}"
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 "Установка необходимых зависимостей (autossh, openssh-client)..." "$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..." "$BLUE"
apt-get install -y autossh openssh-client sshpass 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..." "$BLUE"
if command -v dnf &> /dev/null; then
dnf install -y autossh openssh-clients sshpass 2>&1 | tee -a "$LOG_DIR/manager.log"
check_error "Не удалось установить пакеты (dnf)"
else
yum install -y autossh openssh-clients sshpass 2>&1 | tee -a "$LOG_DIR/manager.log"
check_error "Не удалось установить пакеты (yum)"
fi
else
log_message "ОШИБКА: Не удалось определить менеджер пакетов (apt, dnf, yum)." "$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"
cp "$0" "$SCRIPT_PATH"
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"
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
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
EOFCONFIG
chmod 600 /root/.ssh/config
log_message "Конфигурация SSH клиента обновлена." "$GREEN"
# Настройка локального SSHD
configure_local_sshd
}
# Функция настройки локального SSH-демона для приема туннелей
configure_local_sshd() {
log_message "Настройка локального SSH-демона (sshd) для приема туннелей..." "$BLUE"
local SSHD_CONFIG="/etc/ssh/sshd_config"
if [ ! -f "$SSHD_CONFIG" ]; then
log_message "ОШИБКА: Файл конфигурации SSHD не найден: $SSHD_CONFIG" "$RED"
return 1
fi
# Создание резервной копии
cp "$SSHD_CONFIG" "${SSHD_CONFIG}.backup.$(date +%Y%m%d%H%M%S)"
log_message "Создана резервная копия: ${SSHD_CONFIG}.backup.$(date +%Y%m%d%H%M%S)" "$YELLOW"
# Настройки для приема обратных туннелей
local SETTINGS=(
"GatewayPorts yes"
"AllowTcpForwarding yes"
)
for setting in "${SETTINGS[@]}"; do
key=$(echo "$setting" | cut -d' ' -f1)
if grep -q "^#\?\s*$key" "$SSHD_CONFIG"; then
# Заменяем или раскомментируем
sed -i "s/^#\?\s*$key.*/$setting/" "$SSHD_CONFIG"
else
# Добавляем в конец файла
echo "$setting" >> "$SSHD_CONFIG"
fi
done
# Перезапуск SSHD
if systemctl restart sshd 2>/dev/null || service ssh restart 2>/dev/null; then
log_message "SSHD перезапущен с новыми настройками (GatewayPorts, AllowTcpForwarding)." "$GREEN"
else
log_message "ПРЕДУПРЕЖДЕНИЕ: Не удалось перезапустить SSHD. Возможно, потребуется ручной перезапуск." "$YELLOW"
fi
}
# 2. Настройка VPS (сервера)
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}"
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) Другой пользователь"
read -p "Ваш выбор [1-2]: " USER_CHOICE
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"
return 1
fi
# Дополнительная проверка, если пользователь выбрал "Другой пользователь", но не ввел имя
if [ "$USER_CHOICE" == "2" ] && [ -z "$VPS_USER" ]; then
log_message "ОШИБКА: Имя пользователя обязательно." "$RED"
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}"
# Используем read -s для скрытого ввода
read -s -p "Введите пароль для $VPS_USER@$VPS_HOST: " VPS_PASSWORD
echo
if [ -n "$VPS_PASSWORD" ]; then
if command -v sshpass &> /dev/null; then
# Используем sshpass для автоматического копирования ключа
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"
log_message "Возможно, пароль неверен, или на VPS не установлен ssh-copy-id." "$YELLOW"
log_message "Вам может потребоваться скопировать ключ вручную:" "$YELLOW"
cat /root/.ssh/id_rsa.pub
fi
else
log_message "ПРЕДУПРЕЖДЕНИЕ: sshpass не установлен. Невозможно скопировать ключ автоматически." "$YELLOW"
log_message "Вам потребуется скопировать ключ вручную:" "$YELLOW"
cat /root/.ssh/id_rsa.pub
fi
else
log_message "Пароль не введен. Вам потребуется скопировать ключ вручную:" "$YELLOW"
cat /root/.ssh/id_rsa.pub
fi
# Тестовое подключение
log_message "Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT..." "$BLUE"
if timeout 10 ssh -p "$VPS_PORT" -o BatchMode=yes "$VPS_USER@$VPS_HOST" "echo 'Connection OK'" 2>/dev/null; then
log_message "Тестовое подключение успешно! Ключ работает." "$GREEN"
else
log_message "ОШИБКА: Тестовое подключение не удалось." "$RED"
log_message "Убедитесь, что публичный ключ скопирован, порт $VPS_PORT открыт, и SSH-сервер на VPS запущен." "$YELLOW"
fi
}
# 3. Добавление нового туннеля
add_tunnel() {
check_root "add_tunnel"
if ! load_vps_settings; then
log_message "Сначала необходимо настроить VPS (опция 1)." "$RED"
return 1
fi
echo -e "${BOLD}${CYAN}--- Добавление нового обратного туннеля (Local -> VPS) ---${NC}"
log_message "VPS: $VPS_USER@$VPS_HOST:$VPS_PORT" "$YELLOW"
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 [ -z "$LOCAL_PORT" ] || [ -z "$REMOTE_PORT" ] || [ -z "$TUNNEL_NAME" ]; then
log_message "ОШИБКА: Все поля обязательны." "$RED"
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"
return 1
fi
# Создание конфигурационного файла туннеля
local CONFIG_FILE="$TUNNELS_DIR/$TUNNEL_ID.conf"
cat > "$CONFIG_FILE" << EOFCONF
# Конфигурация туннеля: $TUNNEL_NAME
TUNNEL_ID="$TUNNEL_ID"
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
[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
Restart=always
RestartSec=10
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
systemctl start "$SERVICE_NAME.service"
if systemctl is-active --quiet "$SERVICE_NAME.service"; then
log_message "Туннель '$TUNNEL_NAME' успешно запущен и включен в автозагрузку." "$GREEN"
log_message "Для доступа к локальному порту $LOCAL_PORT через VPS используйте:" "$YELLOW"
log_message "ssh -p $REMOTE_PORT $VPS_USER@$VPS_HOST" "$BOLD"
else
log_message "ОШИБКА: Не удалось запустить туннель '$TUNNEL_NAME'." "$RED"
log_message "Проверьте лог: tail -f $LOG_DIR/$TUNNEL_ID.log" "$YELLOW"
fi
}
# 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"
;;
status)
systemctl status "$SERVICE_NAME.service"
;;
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 ""
read -p "Выберите действие: " choice
case $choice in
1)
local LOG_DIR="/var/log/tunnel-manager"
echo -e "${CYAN}Доступные логи:${NC}"
find "$LOG_DIR" -maxdepth 1 -type f -name "tunnel-*.log" -printf " %f\n"
echo ""
read -p "Введите имя лог-файла (например, tunnel-ssh_access.log): " log_file
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 -p "Нажмите Enter для продолжения..."
;;
3)
echo -e "${CYAN}Системные логи туннелей (последний час):${NC}"
journalctl -u tunnel-* --since "1 hour ago" -n 20 2>/dev/null || log_message "Системные логи отсутствуют" "$YELLOW"
read -p "Нажмите Enter для продолжения..."
;;
4)
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) Назад"
echo ""
read -p "Выберите тест: " test_choice
case $test_choice in
1)
check_ssh_connection
read -p "Нажмите Enter для продолжения..."
;;
2)
echo -e "${CYAN}Тест локальных портов туннелей:${NC}"
local TUNNEL_DIR="/etc/tunnel-manager/tunnels"
local NC_CMD
if command -v nc &> /dev/null; then
NC_CMD="nc -z localhost"
elif command -v ncat &> /dev/null; then
NC_CMD="ncat -z localhost"
else
log_message "ОШИБКА: Утилита 'nc' или 'ncat' не найдена. Невозможно проверить порты." "$RED"
read -p "Нажмите Enter для продолжения..."
continue
fi
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_CMD "$LOCAL_PORT" 2>/dev/null; then
echo -e "${GREEN}✓ Открыт${NC}"
else
echo -e "${RED}✗ Закрыт${NC}"
fi
fi
done
read -p "Нажмите Enter для продолжения..."
;;
3)
return
;;
*)
log_message "Неверный выбор" "$RED"
sleep 1
;;
esac
done
}
# Функция настройки маршрутизации (iptables)
setup_routing() {
if ! command -v iptables &> /dev/null; then
log_message "ОШИБКА: Утилита 'iptables' не найдена. Установите ее для использования этой функции." "$RED"
read -p "Нажмите 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 ""
read -p "Выберите действие: " routing_choice
case $routing_choice in
1)
echo -e "${CYAN}Текущие правила iptables (NAT PREROUTING):${NC}"
sudo iptables -t nat -L PREROUTING -n -v
read -p "Нажмите Enter для продолжения..."
;;
2)
local IN_PORT DEST_IP DEST_PORT
read -p "Входной порт (напр. 80): " IN_PORT
read -p "IP назначения (напр. 192.168.1.10): " DEST_IP
read -p "Порт назначения (напр. 8080): " DEST_PORT
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 -p "Нажмите 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 "ОШИБКА: Не найдена утилита для сохранения правил (netfilter-persistent или iptables-save)." "$RED"
fi
read -p "Нажмите Enter для продолжения..."
;;
4)
return
;;
*)
log_message "Неверный выбор" "$RED"
sleep 1
;;
esac
done
}
# Функция настройки SSH демона
setup_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) Назад"
echo ""
read -p "Выберите действие: " ssh_choice
case $ssh_choice in
1)
echo -e "${CYAN}Текущие настройки sshd (GatewayPorts, AllowTcpForwarding):${NC}"
grep -E "^(GatewayPorts|AllowTcpForwarding)" /etc/ssh/sshd_config 2>/dev/null || log_message "Настройки не найдены" "$YELLOW"
read -p "Нажмите 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 -p "Нажмите Enter для продолжения..."
;;
3)
if sudo sshd -t 2>/dev/null; then
log_message "Конфигурация SSH корректна." "$GREEN"
else
log_message "ОШИБКА: Ошибка в конфигурации SSH." "$RED"
fi
read -p "Нажмите Enter для продолжения..."
;;
4)
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}"
read -p "ID туннеля: " TUNNEL_ID_MANAGE
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}"
# Показать текущий статус
manage_tunnel "$TUNNEL_ID_MANAGE" "status"
echo -e "\n${CYAN}Выберите действие:${NC}"
echo " s) Статус (обновить)"
echo " t) Старт"
echo " p) Стоп"
echo " r) Перезапуск"
echo " d) Удалить"
echo " b) Назад"
read -p "Действие: " ACTION_CHOICE
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)
read -p "Вы уверены, что хотите удалить туннель $TUNNEL_ID_MANAGE? (y/N): " CONFIRM_REMOVE
if [[ "$CONFIRM_REMOVE" =~ ^[Yy]$ ]]; then
manage_tunnel "$TUNNEL_ID_MANAGE" "remove"
return # Возврат в меню туннелей после удаления
fi
;;
b) break;;
*) log_message "Неизвестная опция." "$RED";;
esac
read -p "Нажмите 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 v1.0 (by Manus) ${NC}"
echo -e "${BOLD}${CYAN}========================================================${NC}"
if load_vps_settings; then
echo -e "${GREEN}✓ VPS настроен: $VPS_USER@$VPS_HOST:$VPS_PORT${NC}"
else
echo -e "${RED}✗ VPS не настроен. Начните с опции 1.${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 Демона (sshd)${NC}"
echo -e "8) ${BOLD}Показать публичный ключ${NC} (Для копирования на VPS)"
echo -e "9) ${BOLD}Выход${NC}"
echo ""
read -p "Выберите опцию [1-9]: " choice
case $choice in
1) setup_vps ;;
2) add_tunnel ;;
3) manage_tunnels_menu ;;
4) view_logs ;;
5) test_connections ;;
6) setup_routing ;;
7) setup_ssh_config ;;
8) show_public_key ;;
9)
log_message "Выход из менеджера." "$GREEN"
exit 0
;;
*)
log_message "Неверный выбор. Попробуйте еще раз." "$RED"
sleep 1
;;
esac
done
}
# --- Точка входа ---
# Главное изменение: если скрипт запущен без аргументов, выполняем автоматическую установку и запуск меню
if [[ $# -eq 0 ]]; then
echo -e "${BOLD}${CYAN}SSH Tunnel Manager v1.0${NC}"
echo -e "Автоматический запуск установки и меню..."
# Проверяем, установлен ли уже скрипт
if [ -f "/usr/local/bin/tunnel-manager" ]; then
echo -e "${YELLOW}Менеджер уже установлен. Запуск меню...${NC}"
main_menu
else
echo -e "${GREEN}Начинаем установку...${NC}"
install_manager
echo -e "${GREEN}Установка завершена. Запуск меню...${NC}"
main_menu
fi
else
case "$1" in
install)
install_manager
;;
menu)
main_menu
;;
*)
echo -e "${BOLD}${CYAN}SSH Tunnel Manager v1.0${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