From 0ad965f0a6ca6ca8134c18908138c65b7b04e1a9 Mon Sep 17 00:00:00 2001 From: NW Date: Mon, 22 Dec 2025 18:43:32 +0000 Subject: [PATCH] v3 --- install_ssh_tunnel.sh | 2294 ++++++++++++++--------------------------- 1 file changed, 762 insertions(+), 1532 deletions(-) diff --git a/install_ssh_tunnel.sh b/install_ssh_tunnel.sh index 00178e5..591611b 100644 --- a/install_ssh_tunnel.sh +++ b/install_ssh_tunnel.sh @@ -1,9 +1,22 @@ #!/bin/bash +# +# SSH Tunnel Manager - Профессиональное решение для управления обратными SSH-туннелями +# Использует autossh и systemd для обеспечения стабильного и постоянного соединения. +# +# Использование: +# 1. Установка: sudo bash tunnel-manager.sh install +# 2. Запуск: sudo bash tunnel-manager.sh menu +# -# Установщик автономного менеджера SSH туннелей -# Использование: bash <(curl -s https://git.softuniq.eu/OpenDoor/vps_ssh_tunel/raw/branch/main/install_ssh_tunnel.sh) +# --- Глобальные переменные и конфигурация --- +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' @@ -12,70 +25,26 @@ CYAN='\033[0;36m' NC='\033[0m' BOLD='\033[1m' -# Логирование -LOG_FILE="/tmp/ssh_tunnel_install.log" +# --- Вспомогательные функции --- +# Функция логирования и вывода сообщений log_message() { - echo -e "${2:-$NC}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a "$LOG_FILE" -} - -clear -echo -e "${BOLD}${CYAN}════════════════════════════════════════════════════════════════${NC}" -echo -e "${BOLD}${CYAN} УСТАНОВКА АВТОНОМНОГО МЕНЕДЖЕРА SSH ТУННЕЛЕЙ ${NC}" -echo -e "${BOLD}${CYAN}════════════════════════════════════════════════════════════════${NC}" -echo "" - -# Проверка прав root -if [[ $EUID -ne 0 ]]; then - echo -e "${RED}ОШИБКА: Этот скрипт требует прав root (sudo).${NC}" - echo "Пожалуйста, запустите снова:" - echo -e "${BOLD}sudo bash <(curl -s https://git.softuniq.eu/OpenDoor/vps_ssh_tunel/raw/branch/main/install_ssh_tunnel.sh)${NC}" - exit 1 -fi - -# Функция безопасного ввода с ограничением попыток (переименована во избежание конфликтов) -safe_input() { - local prompt="$1" - local default="$2" - local var_name="$3" - local is_password="$4" - local max_attempts="${5:-3}" - - local attempt=0 - local input="" - - while [[ $attempt -lt $max_attempts ]]; do - attempt=$((attempt + 1)) - - if [ "$is_password" = "yes" ]; then - read -s -p "$prompt" input - echo - else - read -p "$prompt" input - fi - - input="${input:-$default}" - - if [ -n "$input" ]; then - eval "$var_name=\"$input\"" - return 0 - elif [[ $attempt -lt $max_attempts ]]; then - echo -e "${YELLOW}Поле не может быть пустым! Попытка $attempt из $max_attempts${NC}" - fi - done - - echo -e "${RED}Превышено максимальное количество попыток ввода. Выход.${NC}" - exit 1 + 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() { - if [ $? -ne 0 ]; then - log_message "ОШИБКА: $1" "$RED" - log_message "Подробности в логе: $LOG_FILE" "$YELLOW" + 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 + read -p "Продолжить выполнение скрипта? (y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 @@ -85,199 +54,133 @@ check_error() { return 0 } -# Определение дистрибутива -detect_distro() { - log_message "Определение операционной системы..." "$CYAN" - - if [ -f /etc/os-release ]; then - . /etc/os-release - OS=$ID - VERSION=$VERSION_ID - elif [ -f /etc/redhat-release ]; then - OS="rhel" - VERSION=$(cat /etc/redhat-release | sed 's/.*release \([0-9]\).*/\1/') - else - OS=$(uname -s) - VERSION=$(uname -r) +# Функция проверки прав root +check_root() { + if [[ $EUID -ne 0 ]]; then + log_message "ОШИБКА: Этот скрипт требует прав root (sudo)." "$RED" + log_message "Пожалуйста, запустите: sudo bash $0 $1" "$BOLD" + exit 1 fi - - log_message "Система: $OS $VERSION" "$GREEN" - return 0 } -# Установка зависимостей -install_dependencies() { - log_message "Установка необходимых зависимостей..." "$CYAN" +# Функция безопасного ввода с ограничением попыток +safe_read() { + local prompt="$1" + local default="$2" + local var_name="$3" + local max_attempts="${4:-3}" # По умолчанию 3 попытки - case $OS in - ubuntu|debian) - log_message "Обновление списка пакетов..." "$BLUE" - if ! apt-get update 2>&1 | tee -a "$LOG_FILE"; then - echo -e "${YELLOW}Предупреждение: не удалось обновить список пакетов${NC}" - fi - - log_message "Установка autossh, openssh-client и утилит..." "$BLUE" - apt-get install -y autossh openssh-client net-tools curl git sshpass 2>&1 | tee -a "$LOG_FILE" - check_error "Не удалось установить пакеты" - ;; - - centos|rhel|fedora|rocky|almalinux) - log_message "Установка autossh, openssh-clients и утилит..." "$BLUE" - if command -v dnf &> /dev/null; then - dnf install -y autossh openssh-clients net-tools curl git sshpass 2>&1 | tee -a "$LOG_FILE" - else - yum install -y autossh openssh-clients net-tools curl git sshpass 2>&1 | tee -a "$LOG_FILE" - fi - check_error "Не удалось установить пакеты" - ;; - - *) - log_message "Неизвестный дистрибутив. Попытка установки вручную..." "$YELLOW" - if ! command -v autossh &> /dev/null; then - log_message "Установка autossh вручную..." "$BLUE" - if curl -sSL http://www.harding.motd.ca/autossh/autossh-1.4g.tgz | tar -xz; then - cd autossh-1.4g || exit 1 - ./configure - make - make install - cd .. - else - echo -e "${YELLOW}Не удалось загрузить autossh${NC}" - fi - fi - ;; - esac + local attempt=0 + local input="" - log_message "Зависимости успешно установлены!" "$GREEN" - return 0 -} - -# Настройка SSH -setup_ssh() { - log_message "Настройка SSH системы..." "$CYAN" - - # Создание директорий SSH если их нет - mkdir -p /root/.ssh - chmod 700 /root/.ssh - - # Запрос данных VPS - echo "" - echo -e "${BOLD}${YELLOW}════════════════════════════════════════════════════════════════${NC}" - echo -e "${BOLD}${YELLOW} НАСТРОЙКА ПОДКЛЮЧЕНИЯ К VPS ${NC}" - echo -e "${BOLD}${YELLOW}════════════════════════════════════════════════════════════════${NC}" - echo "" - - # Запрос данных VPS с проверкой - local vps_data_ok=false - local max_attempts=3 - local VPS_HOST="" - local VPS_PORT="" - local VPS_USER="" - - for ((attempt=1; attempt<=max_attempts; attempt++)); do - echo -e "${CYAN}Введите данные для подключения к VPS (попытка $attempt из $max_attempts):${NC}" - echo "" + while [[ $attempt -lt $max_attempts ]]; do + attempt=$((attempt + 1)) - read -p "IP адрес или доменное имя VPS: " VPS_HOST - read -p "Порт SSH (по умолчанию 22): " VPS_PORT - VPS_PORT=${VPS_PORT:-22} + read -p "$prompt" input - echo "" - echo -e "${CYAN}Выберите пользователя для подключения:${NC}" - echo "1) root (рекомендуется для полного доступа)" - echo "2) Другой пользователь" - read -p "Ваш выбор [1-2]: " USER_CHOICE + input="${input:-$default}" - if [ "$USER_CHOICE" = "1" ] || [ -z "$USER_CHOICE" ]; then - VPS_USER="root" - echo -e "${YELLOW}Будет использоваться пользователь: root${NC}" - else - read -p "Введите имя пользователя: " VPS_USER - fi - - # Проверка заполнения обязательных полей - if [[ -z "$VPS_HOST" || -z "$VPS_USER" ]]; then - echo -e "${RED}Ошибка: обязательные поля не заполнены!${NC}" - if [[ $attempt -lt $max_attempts ]]; then - echo -e "${YELLOW}Пожалуйста, заполните все поля.${NC}" - echo "" - continue - else - echo -e "${RED}Превышено максимальное количество попыток. Выход.${NC}" - exit 1 - fi - fi - - echo "" - echo -e "${CYAN}Проверка введенных данных:${NC}" - echo -e " VPS: ${YELLOW}$VPS_USER@$VPS_HOST:$VPS_PORT${NC}" - echo "" - - read -p "Все верно? (y/n): " CONFIRM - - if [[ "$CONFIRM" =~ ^[Yy]$ ]] || [ -z "$CONFIRM" ]; then - vps_data_ok=true - break - else - echo -e "${YELLOW}Повторите ввод данных...${NC}" - echo "" + # Если есть ввод или значение по умолчанию + 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 - if [ "$vps_data_ok" = false ]; then - echo -e "${RED}Не удалось получить корректные данные VPS. Выход.${NC}" - exit 1 + # Если превышено количество попыток + echo -e "${RED}Превышено максимальное количество попыток ввода. Выход.${NC}" + exit 1 +} + +# Функция загрузки настроек VPS +load_vps_settings() { + if [ -f "$VPS_CONFIG" ]; then + source "$VPS_CONFIG" + return 0 + fi + return 1 +} + +# --- Основные функции --- + +# 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 "Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT..." "$BLUE" - echo -e "${CYAN}Пытаюсь подключиться к VPS...${NC}" + log_message "Обнаружен дистрибутив: ${OS:-Unknown}" "$BLUE" - if timeout 10 bash -c "echo > /dev/tcp/$VPS_HOST/$VPS_PORT" 2>/dev/null; then - log_message "Порт $VPS_PORT доступен" "$GREEN" - else - log_message "Не удалось подключиться к порту $VPS_PORT" "$RED" - echo -e "${YELLOW}Проверьте:${NC}" - echo -e " 1) Правильность адреса VPS" - echo -e " 2) Открыт ли порт $VPS_PORT на VPS" - echo -e " 3) Работает ли SSH сервер на VPS" - echo -e " 4) Не блокирует ли брандмауэр подключение" + if [[ "$OS" == "ubuntu" || "$OS" == "debian" ]]; then + log_message "Обновление списка пакетов..." "$BLUE" + apt-get update 2>&1 | tee -a "$LOG_DIR/manager.log" + check_error "Не удалось обновить список пакетов" - read -p "Продолжить все равно? (y/n): " CONTINUE - - if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then - exit 1 + 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 ключа - echo "" - log_message "Генерация SSH ключа RSA 4096 бит..." "$CYAN" - - if [ -f "/root/.ssh/id_rsa" ]; then - echo -e "${YELLOW}SSH ключ уже существует.${NC}" - read -p "Сгенерировать новый? (y/n): " GEN_NEW - - if [[ "$GEN_NEW" =~ ^[Yy]$ ]]; then - ssh-keygen -t rsa -b 4096 -N "" -f /root/.ssh/id_rsa -q - log_message "Новый SSH ключ сгенерирован" "$GREEN" - fi - else + 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 ключ сгенерирован" "$GREEN" + log_message "SSH ключ сгенерирован: /root/.ssh/id_rsa.pub" "$GREEN" + else + log_message "SSH ключ уже существует. Используем существующий." "$YELLOW" fi - # Настройка SSH конфигурации для стабильного подключения - log_message "Настройка конфигурации SSH для стабильного подключения..." "$BLUE" - - # Создание конфига для root с улучшенными настройками - cat > /root/.ssh/config << 'EOFCONFIG' -# Основная конфигурация SSH -Host tunnel-vps - HostName $VPS_HOST - Port $VPS_PORT - User $VPS_USER - IdentityFile ~/.ssh/id_rsa + # Настройка SSH конфига для стабильности + log_message "Настройка SSH клиента для стабильности..." "$BLUE" + cat > /root/.ssh/config << EOFCONFIG +Host * StrictHostKeyChecking no UserKnownHostsFile /dev/null ServerAliveInterval 30 @@ -286,1245 +189,230 @@ Host tunnel-vps TCPKeepAlive yes IdentitiesOnly yes ExitOnForwardFailure yes - # Увеличенные настройки для локальной сети - IPQoS throughput - Compression 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 - -Host * - # Глобальные настройки для всех хостов - StrictHostKeyChecking no - UserKnownHostsFile /dev/null - ServerAliveInterval 30 - ServerAliveCountMax 3 - TCPKeepAlive yes - Compression yes - ControlMaster auto - ControlPath ~/.ssh/control-%r@%h:%p - ControlPersist 10m - ConnectTimeout 30 - # Настройки для локальной сети - GSSAPIAuthentication no - AddressFamily inet - # Увеличение размера буферов - SendEnv LANG LC_* - HashKnownHosts yes - # Настройки переподключения - RekeyLimit 1G 1h EOFCONFIG - - # Замена переменных в конфиге - sed -i "s/\$VPS_HOST/$VPS_HOST/g" /root/.ssh/config - sed -i "s/\$VPS_PORT/$VPS_PORT/g" /root/.ssh/config - sed -i "s/\$VPS_USER/$VPS_USER/g" /root/.ssh/config - chmod 600 /root/.ssh/config + log_message "Конфигурация SSH клиента обновлена." "$GREEN" - # Настройка SSH демона для локальных подключений - log_message "Настройка SSH демона для локальных подключений..." "$BLUE" + # Настройка локального SSHD + configure_local_sshd +} + +# Функция настройки локального SSH-демона для приема туннелей +configure_local_sshd() { + log_message "Настройка локального SSH-демона (sshd) для приема туннелей..." "$BLUE" + local SSHD_CONFIG="/etc/ssh/sshd_config" - # Бэкап оригинального конфига - SSHD_CONFIG="/etc/ssh/sshd_config" - if [ -f "$SSHD_CONFIG" ]; then - cp "$SSHD_CONFIG" "${SSHD_CONFIG}.backup.$(date +%Y%m%d%H%M%S)" - - # Улучшенные настройки для стабильности - SSHD_SETTINGS=( - "ClientAliveInterval 30" - "ClientAliveCountMax 3" - "TCPKeepAlive yes" - "PasswordAuthentication yes" - "PermitRootLogin yes" - "GatewayPorts yes" - "AllowTcpForwarding yes" - "X11Forwarding yes" - "PrintMotd no" - "AcceptEnv LANG LC_*" - "Subsystem sftp /usr/lib/openssh/sftp-server" - "UsePAM yes" - "AllowUsers root" - ) - - for setting in "${SSHD_SETTINGS[@]}"; do - key=$(echo "$setting" | cut -d' ' -f1) - if grep -q "^$key" "$SSHD_CONFIG"; then - sed -i "s/^$key.*/$setting/" "$SSHD_CONFIG" - else - echo "$setting" >> "$SSHD_CONFIG" - fi - done - - # Перезапускаем SSH демон - if systemctl restart sshd 2>/dev/null || service ssh restart 2>/dev/null; then - log_message "SSH демон перезапущен с новыми настройками" "$GREEN" + 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 - log_message "Не удалось перезапустить SSH демон" "$YELLOW" + # Добавляем в конец файла + echo "$setting" >> "$SSHD_CONFIG" fi - fi + done - # Копирование ключа на VPS - echo "" - log_message "Копирование SSH ключа на VPS ($VPS_USER@$VPS_HOST)..." "$CYAN" - echo -e "${YELLOW}Для копирования ключа потребуется пароль от $VPS_USER на VPS${NC}" - - # Запрос пароля для копирования ключа - read -s -p "Введите пароль для $VPS_USER@$VPS_HOST (или нажмите Enter для пропуска): " VPS_PASSWORD - echo - - if [ -n "$VPS_PASSWORD" ]; then - echo "" - echo -e "${CYAN}Попытка копирования ключа с использованием пароля...${NC}" - - # Пытаемся скопировать ключ с использованием sshpass - if command -v sshpass &> /dev/null; then - 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_FILE"; then - log_message "SSH ключ успешно скопирован на VPS!" "$GREEN" - else - log_message "Не удалось скопировать ключ через sshpass" "$YELLOW" - echo -e "${YELLOW}Попробуйте скопировать ключ вручную${NC}" - fi - else - echo -e "${YELLOW}sshpass не установлен, пропускаю автоматическое копирование${NC}" - fi + # Перезапуск SSHD + if systemctl restart sshd 2>/dev/null || service ssh restart 2>/dev/null; then + log_message "SSHD перезапущен с новыми настройками (GatewayPorts, AllowTcpForwarding)." "$GREEN" else - echo -e "${YELLOW}Пароль не введен, пропускаю автоматическое копирование ключа${NC}" + log_message "ПРЕДУПРЕЖДЕНИЕ: Не удалось перезапустить SSHD. Возможно, потребуется ручной перезапуск." "$YELLOW" fi +} + +# 2. Настройка VPS (сервера) +setup_vps() { + check_root "setup_vps" + log_message "Настройка подключения к удаленному VPS (серверу)..." "$CYAN" - # Альтернативный метод копирования ключа - echo "" - echo -e "${CYAN}Альтернативный способ добавления ключа:${NC}" - echo -e "${YELLOW}Если автоматическое копирование не удалось, выполните следующие шаги:${NC}" - echo "" - echo -e "1. Скопируйте содержимое публичного ключа:" - echo -e "${BOLD}cat /root/.ssh/id_rsa.pub${NC}" - echo "" - echo -e "2. Подключитесь к VPS:" - echo -e "${BOLD}ssh -p $VPS_PORT $VPS_USER@$VPS_HOST${NC}" - echo "" - echo -e "3. На VPS выполните:" - echo -e "${BOLD}mkdir -p ~/.ssh && chmod 700 ~/.ssh${NC}" - echo -e "${BOLD}echo 'ВАШ_ПУБЛИЧНЫЙ_КЛЮЧ' >> ~/.ssh/authorized_keys${NC}" - echo -e "${BOLD}chmod 600 ~/.ssh/authorized_keys${NC}" - echo "" + local current_host="" + local current_port="22" + local current_user="" - read -p "Нажмите Enter после добавления ключа на VPS..." WAIT + 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}" - # Тестовое подключение - log_message "Тестовое подключение к VPS..." "$BLUE" - echo -e "${CYAN}Пытаюсь подключиться без пароля...${NC}" + local VPS_HOST_TEMP + local VPS_PORT_TEMP + local VPS_USER_TEMP + local USER_CHOICE - if timeout 15 ssh -p "$VPS_PORT" \ - -o BatchMode=yes \ - -o ConnectTimeout=10 \ - -o StrictHostKeyChecking=no \ - "$VPS_USER@$VPS_HOST" \ - "echo 'SSH подключение успешно!'" 2>&1 | tee -a "$LOG_FILE"; then - log_message "Тестовое подключение прошло успешно!" "$GREEN" - echo -e "${GREEN}✓ SSH ключ настроен корректно${NC}" + # Ввод 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 - log_message "Тестовое подключение не удалось" "$YELLOW" - echo -e "${YELLOW}⚠ Не удалось подключиться без пароля${NC}" - echo -e "${YELLOW}Убедитесь, что ключ добавлен в authorized_keys на VPS${NC}" - - read -p "Продолжить установку? (y/n): " CONTINUE_INSTALL - - if [[ ! "$CONTINUE_INSTALL" =~ ^[Yy]$ ]]; then - exit 1 - fi + safe_read "Введите имя пользователя на VPS (текущий: $current_user): " "$current_user" VPS_USER_TEMP fi - # Настройка для не-root пользователей - if [[ $EUID -eq 0 ]] && [ -d "/home/" ] && [ "$(ls -A /home/ 2>/dev/null)" ]; then - echo "" - read -p "Настроить SSH для обычных пользователей системы? (y/n): " SETUP_USERS - - if [[ "$SETUP_USERS" =~ ^[Yy]$ ]]; then - log_message "Настройка SSH для всех пользователей системы..." "$CYAN" - - for HOME_DIR in /home/*; do - if [ -d "$HOME_DIR" ] && [ "$HOME_DIR" != "/home/*" ]; then - USER=$(basename "$HOME_DIR") - USER_SSH_DIR="$HOME_DIR/.ssh" - - echo -e "${CYAN}Настройка пользователя: $USER${NC}" - - mkdir -p "$USER_SSH_DIR" - chmod 700 "$USER_SSH_DIR" - chown "$USER:$USER" "$USER_SSH_DIR" - - # Копируем конфиг - cp /root/.ssh/config "$USER_SSH_DIR/config" 2>/dev/null - if [ -f "$USER_SSH_DIR/config" ]; then - chown "$USER:$USER" "$USER_SSH_DIR/config" - chmod 600 "$USER_SSH_DIR/config" - echo -e " ${GREEN}✓ Конфиг скопирован${NC}" - fi - - read -p " Скопировать SSH ключ для пользователя $USER? (y/n): " COPY_FOR_USER - - if [[ "$COPY_FOR_USER" =~ ^[Yy]$ ]]; then - cp /root/.ssh/id_rsa* "$USER_SSH_DIR/" 2>/dev/null - chown -R "$USER:$USER" "$USER_SSH_DIR" - chmod 600 "$USER_SSH_DIR/id_rsa" 2>/dev/null - chmod 644 "$USER_SSH_DIR/id_rsa.pub" 2>/dev/null - echo -e " ${GREEN}✓ Ключ скопирован для $USER${NC}" - fi - fi - done - 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 - # Сохранение настроек VPS для использования в скриптах - log_message "Сохранение настроек VPS..." "$BLUE" + # Дополнительная проверка, если пользователь выбрал "Другой пользователь", но не ввел имя + if [ "$USER_CHOICE" == "2" ] && [ -z "$VPS_USER" ]; then + log_message "ОШИБКА: Имя пользователя обязательно." "$RED" + return 1 + fi - mkdir -p /etc/ssh_tunnel - cat > /etc/ssh_tunnel/vps_settings.conf << EOFSETTINGS + # Сохранение настроек + 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" - chmod 600 /etc/ssh_tunnel/vps_settings.conf - log_message "Настройки SSH сохранены в /etc/ssh_tunnel/vps_settings.conf" "$GREEN" + # Автоматическое копирование ключа + log_message "Попытка автоматического копирования SSH-ключа на VPS..." "$CYAN" - # Экспорт переменных для других функций - export VPS_HOST - export VPS_PORT - export VPS_USER - return 0 -} - -# Установка основного скрипта управления -install_main_script() { - log_message "Установка основного скрипта управления туннелями..." "$CYAN" + # Запрос пароля для sshpass с безопасным вводом + local VPS_PASSWORD + echo -e "${YELLOW}Для автоматического копирования ключа потребуется пароль от $VPS_USER на VPS.${NC}" - # Создание директорий - mkdir -p /opt/ssh_tunnel_manager - mkdir -p /var/log/ssh_tunnel - mkdir -p /etc/ssh_tunnel + # Используем read -s для скрытого ввода + read -s -p "Введите пароль для $VPS_USER@$VPS_HOST: " VPS_PASSWORD + echo - # Загрузка настроек VPS если есть - if [ -f /etc/ssh_tunnel/vps_settings.conf ]; then - source /etc/ssh_tunnel/vps_settings.conf - fi - - # Создание основного скрипта менеджера - cat > /opt/ssh_tunnel_manager/manager.sh << 'EOFMGR' -#!/bin/bash - -# Основной скрипт менеджера SSH туннелей -# Версия 4.0 - Стабильное меню - -# Конфигурация -CONFIG_DIR="/etc/ssh_tunnel" -LOG_DIR="/var/log/ssh_tunnel" -SERVICE_DIR="/etc/systemd/system" -SCRIPT_DIR="/opt/ssh_tunnel_manager" - -# Цвета -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -PURPLE='\033[0;35m' -NC='\033[0m' -BOLD='\033[1m' - -# Глобальные переменные -VPS_HOST="" -VPS_PORT="22" -VPS_USER="" - -# Загрузка настроек VPS если есть -load_vps_settings() { - if [ -f "/etc/ssh_tunnel/vps_settings.conf" ]; then - source "/etc/ssh_tunnel/vps_settings.conf" - return 0 - fi - return 1 -} - -# Функция безопасного ввода -safe_read_input() { - local prompt="$1" - local default="$2" - local var_name="$3" - - read -p "$prompt" input - input="${input:-$default}" - - if [ -n "$input" ]; then - eval "$var_name=\"$input\"" - return 0 - else - return 1 - fi -} - -# Очистка входного буфера -clear_input_buffer() { - while read -t 0.1 -n 1000 discard; do :; done -} - -# Функция проверки подключения -check_ssh_connection() { - if [ -z "$VPS_HOST" ] || [ -z "$VPS_USER" ]; then - echo -e "${RED}Настройки VPS не найдены!${NC}" - 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 \ - -o StrictHostKeyChecking=no \ - "${VPS_USER}@${VPS_HOST}" \ - "echo 'Connected' && exit 0" 2>/dev/null; then - echo -e "${GREEN}✓ Подключение успешно${NC}" - return 0 - else - echo -e "${RED}✗ Не удалось подключиться${NC}" - return 1 - fi -} - -# Функция настройки нового VPS -setup_new_vps() { - echo -e "${BOLD}${CYAN}Настройка нового VPS подключения${NC}" - echo -e "${YELLOW}========================================${NC}" - - read -p "Введите IP адрес или домен VPS: " NEW_VPS_HOST - read -p "Введите порт SSH (22): " NEW_VPS_PORT - NEW_VPS_PORT=${NEW_VPS_PORT:-22} - read -p "Введите имя пользователя: " NEW_VPS_USER - - if [ -z "$NEW_VPS_HOST" ] || [ -z "$NEW_VPS_USER" ]; then - echo -e "${RED}Ошибка: не все поля заполнены${NC}" - return 1 - fi - - # Проверка подключения - echo -e "${CYAN}Проверка подключения...${NC}" - if timeout 5 ssh -p "$NEW_VPS_PORT" \ - -o ConnectTimeout=3 \ - -o StrictHostKeyChecking=no \ - "$NEW_VPS_USER@$NEW_VPS_HOST" \ - "echo 'OK'" 2>/dev/null; then - echo -e "${GREEN}✓ Подключение работает${NC}" - else - echo -e "${YELLOW}⚠ Не удалось проверить подключение${NC}" - read -p "Все равно продолжить? (y/n): " CONTINUE - if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then - return 1 - fi - fi - - # Сохранение настроек - cat > /etc/ssh_tunnel/vps_settings.conf << CONFIGVPS -# Настройки VPS для автономных туннелей -VPS_HOST="$NEW_VPS_HOST" -VPS_PORT="$NEW_VPS_PORT" -VPS_USER="$NEW_VPS_USER" -CONFIGURED_ON="$(date '+%Y-%m-%d %H:%M:%S')" -CONFIGVPS - - echo -e "${GREEN}Настройки сохранены!${NC}" - VPS_HOST="$NEW_VPS_HOST" - VPS_PORT="$NEW_VPS_PORT" - VPS_USER="$NEW_VPS_USER" - - read -p "Нажмите Enter для продолжения..." - return 0 -} - -# Создание туннеля -create_tunnel() { - echo -e "${CYAN}Создание нового туннеля...${NC}" - - if [ -z "$VPS_HOST" ]; then - echo -e "${RED}Сначала настройте VPS (опция 9)${NC}" - sleep 2 - return - fi - - read -p "Введите локальный порт (например 22): " LOCAL_PORT - read -p "Введите удаленный порт на VPS (например 10022): " REMOTE_PORT - - if [ -z "$LOCAL_PORT" ] || [ -z "$REMOTE_PORT" ]; then - echo -e "${RED}Ошибка: не все поля заполнены${NC}" - return - fi - - echo -e "${CYAN}Создание туннеля $LOCAL_PORT -> $REMOTE_PORT на ${VPS_HOST}...${NC}" - - # Создание конфигурации - TUNNEL_ID="tunnel_${REMOTE_PORT}_$(date +%s)" - CONFIG_FILE="/etc/ssh_tunnel/${TUNNEL_ID}.conf" - - cat > "$CONFIG_FILE" << CONFTUN -TUNNEL_ID="$TUNNEL_ID" -VPS_HOST="$VPS_HOST" -VPS_PORT="$VPS_PORT" -VPS_USER="$VPS_USER" -LOCAL_PORT="$LOCAL_PORT" -REMOTE_PORT="$REMOTE_PORT" -CREATED="$(date '+%Y-%m-%d %H:%M:%S')" -CONFTUN - - echo -e "${GREEN}Туннель создан! Конфиг: $CONFIG_FILE${NC}" - - # Создание службы - SERVICE_FILE="/etc/systemd/system/ssh-tunnel-${TUNNEL_ID}.service" - - cat > "$SERVICE_FILE" << SERVICETUN -[Unit] -Description=SSH Tunnel: $TUNNEL_ID -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" \\ - -R \${REMOTE_PORT}:localhost:\${LOCAL_PORT} \\ - \${VPS_USER}@\${VPS_HOST} -p \${VPS_PORT} -Restart=always -RestartSec=10 -User=root - -StandardOutput=append:/var/log/ssh_tunnel/${TUNNEL_ID}.log -StandardError=append:/var/log/ssh_tunnel/${TUNNEL_ID}.log - -[Install] -WantedBy=multi-user.target -SERVICETUN - - systemctl daemon-reload - systemctl enable "ssh-tunnel-${TUNNEL_ID}.service" 2>/dev/null - systemctl start "ssh-tunnel-${TUNNEL_ID}.service" 2>/dev/null - - echo -e "${GREEN}Служба создана и запущена!${NC}" - echo -e "${CYAN}Для подключения используйте:${NC}" - echo -e "${BOLD}ssh -p $REMOTE_PORT ${VPS_USER}@${VPS_HOST}${NC}" - - read -p "Нажмите Enter для продолжения..." - return 0 -} - -# Быстрый SSH туннель -quick_ssh_tunnel() { - echo -e "${CYAN}Создание быстрого SSH туннеля...${NC}" - - if [ -z "$VPS_HOST" ]; then - echo -e "${RED}Сначала настройте VPS (опция 9)${NC}" - sleep 2 - return - fi - - LOCAL_PORT="22" - REMOTE_PORT="10022" - - echo -e "${YELLOW}Будет создан туннель: localhost:22 -> ${VPS_HOST}:${REMOTE_PORT}${NC}" - - TUNNEL_ID="ssh_tunnel_${REMOTE_PORT}" - CONFIG_FILE="/etc/ssh_tunnel/${TUNNEL_ID}.conf" - - cat > "$CONFIG_FILE" << CONFFAST -TUNNEL_ID="$TUNNEL_ID" -VPS_HOST="$VPS_HOST" -VPS_PORT="$VPS_PORT" -VPS_USER="$VPS_USER" -LOCAL_PORT="$LOCAL_PORT" -REMOTE_PORT="$REMOTE_PORT" -CREATED="$(date '+%Y-%m-%d %H:%M:%S')" -TYPE="ssh" -CONFFAST - - SERVICE_FILE="/etc/systemd/system/ssh-tunnel-${TUNNEL_ID}.service" - - cat > "$SERVICE_FILE" << SERVICEFAST -[Unit] -Description=SSH Tunnel: $TUNNEL_ID -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" \\ - -R \${REMOTE_PORT}:localhost:\${LOCAL_PORT} \\ - \${VPS_USER}@\${VPS_HOST} -p \${VPS_PORT} -Restart=always -RestartSec=10 -User=root - -StandardOutput=append:/var/log/ssh_tunnel/${TUNNEL_ID}.log -StandardError=append:/var/log/ssh_tunnel/${TUNNEL_ID}.log - -[Install] -WantedBy=multi-user.target -SERVICEFAST - - systemctl daemon-reload - systemctl enable "ssh-tunnel-${TUNNEL_ID}.service" 2>/dev/null - systemctl start "ssh-tunnel-${TUNNEL_ID}.service" 2>/dev/null - - echo -e "${GREEN}SSH туннель создан!${NC}" - echo -e "${CYAN}Для подключения используйте:${NC}" - echo -e "${BOLD}ssh -p $REMOTE_PORT ${VPS_USER}@${VPS_HOST}${NC}" - - read -p "Нажмите Enter для продолжения..." - return 0 -} - -# Управление туннелями -manage_tunnels() { - while true; do - clear - echo -e "${BOLD}${CYAN}Управление туннелями${NC}" - echo -e "${YELLOW}=====================${NC}" - echo "" - - # Список туннелей - count=0 - declare -A tunnels - - # Исправленный цикл для списка туннелей - for conf in /etc/ssh_tunnel/*.conf; do - if [ ! -f "$conf" ]; then - continue - fi - # Пропускаем файл настроек VPS - if [[ "$(basename "$conf")" == "vps_settings.conf" ]]; then - continue - fi - ((count++)) - tunnels[$count]="$conf" - tunnel_name=$(basename "$conf" .conf) - echo -e "${CYAN}[$count]${NC} $tunnel_name" - done - - if [ $count -eq 0 ]; then - echo -e "${YELLOW}Нет настроенных туннелей${NC}" - fi - - echo "" - echo -e "${CYAN}[s]${NC} Показать статус всех туннелей" - echo -e "${CYAN}[r]${NC} Перезапустить все туннели" - echo -e "${CYAN}[b]${NC} Назад в главное меню" - echo "" - - clear_input_buffer - read -p "Выберите опцию: " choice - - case $choice in - b|B) return ;; - s|S) - echo -e "${CYAN}Статус туннелей:${NC}" - systemctl list-units --type=service --state=active | grep ssh-tunnel || echo "Нет активных туннелей" - read -p "Нажмите Enter для продолжения..." - ;; - r|R) - echo -e "${CYAN}Перезапуск всех туннелей...${NC}" - for conf in /etc/ssh_tunnel/*.conf; do - if [ ! -f "$conf" ] || [[ "$(basename "$conf")" == "vps_settings.conf" ]]; then - continue - fi - tunnel_name=$(basename "$conf" .conf) - systemctl restart "ssh-tunnel-${tunnel_name}.service" 2>/dev/null - echo -e " ${GREEN}✓${NC} $tunnel_name перезапущен" - done - read -p "Нажмите Enter для продолжения..." - ;; - *) - if [[ $choice =~ ^[0-9]+$ ]] && [ $choice -ge 1 ] && [ $choice -le $count ]; then - manage_single_tunnel "${tunnels[$choice]}" - else - echo -e "${RED}Неверный выбор${NC}" - sleep 1 - fi - ;; - esac - done -} - -# Управление одним туннелем -manage_single_tunnel() { - local conf="$1" - local tunnel_name=$(basename "$conf" .conf) - - if [ ! -f "$conf" ]; then - echo -e "${RED}Конфигурация не найдена${NC}" - return 1 - fi - - # Загружаем настройки туннеля - LOCAL_PORT="" - REMOTE_PORT="" - VPS_HOST="" - VPS_PORT="" - VPS_USER="" - - source "$conf" 2>/dev/null || { - echo -e "${RED}Ошибка загрузки конфигурации${NC}" - return 1 - } - - while true; do - clear - echo -e "${BOLD}${CYAN}Управление туннелем: $tunnel_name${NC}" - echo -e "${YELLOW}=================================${NC}" - echo "" - echo -e "${CYAN}Информация:${NC}" - echo -e " Локальный порт: ${LOCAL_PORT:-не указан}" - echo -e " Удаленный порт: ${REMOTE_PORT:-не указан}" - echo -e " VPS: ${VPS_USER:-не указан}@${VPS_HOST:-не указан}:${VPS_PORT:-22}" - echo "" - - # Проверка статуса - if systemctl is-active --quiet "ssh-tunnel-${tunnel_name}.service" 2>/dev/null; then - echo -e "${GREEN}✓ Служба активна${NC}" - else - echo -e "${RED}✗ Служба неактивна${NC}" - fi - - echo "" - echo -e "${CYAN}[1]${NC} Перезапустить туннель" - echo -e "${CYAN}[2]${NC} Остановить туннель" - echo -e "${CYAN}[3]${NC} Запустить туннель" - echo -e "${CYAN}[4]${NC} Показать логи" - echo -e "${CYAN}[5]${NC} Удалить туннель" - echo -e "${CYAN}[6]${NC} Назад" - echo "" - - clear_input_buffer - read -p "Выберите действие: " action - - case $action in - 1) - systemctl restart "ssh-tunnel-${tunnel_name}.service" 2>/dev/null - echo -e "${GREEN}Туннель перезапущен${NC}" - sleep 1 - ;; - 2) - systemctl stop "ssh-tunnel-${tunnel_name}.service" 2>/dev/null - echo -e "${YELLOW}Туннель остановлен${NC}" - sleep 1 - ;; - 3) - systemctl start "ssh-tunnel-${tunnel_name}.service" 2>/dev/null - echo -e "${GREEN}Туннель запущен${NC}" - sleep 1 - ;; - 4) - echo -e "${CYAN}Логи туннеля:${NC}" - if [ -f "/var/log/ssh_tunnel/${tunnel_name}.log" ]; then - tail -20 "/var/log/ssh_tunnel/${tunnel_name}.log" - else - echo "Логи отсутствуют" - fi - read -p "Нажмите Enter для продолжения..." - ;; - 5) - read -p "Вы уверены, что хотите удалить туннель $tunnel_name? (y/n): " confirm - if [[ "$confirm" =~ ^[Yy]$ ]]; then - systemctl stop "ssh-tunnel-${tunnel_name}.service" 2>/dev/null - systemctl disable "ssh-tunnel-${tunnel_name}.service" 2>/dev/null - rm -f "/etc/systemd/system/ssh-tunnel-${tunnel_name}.service" - rm -f "$conf" - rm -f "/var/log/ssh_tunnel/${tunnel_name}.log" 2>/dev/null - systemctl daemon-reload - echo -e "${GREEN}Туннель удален${NC}" - sleep 1 - return - fi - ;; - 6) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - sleep 1 - ;; - esac - done -} - -# Настройка автозапуска -setup_autostart() { - while true; do - clear - echo -e "${BOLD}${CYAN}Настройка автозапуска${NC}" - echo -e "${YELLOW}======================${NC}" - echo "" - echo -e "${CYAN}[1]${NC} Включить автозапуск всех туннелей" - echo -e "${CYAN}[2]${NC} Выключить автозапуск всех туннелей" - echo -e "${CYAN}[3]${NC} Проверить статус автозапуска" - echo -e "${CYAN}[4]${NC} Назад" - echo "" - - clear_input_buffer - read -p "Выберите действие: " action - - case $action in - 1) - for conf in /etc/ssh_tunnel/*.conf; do - if [ ! -f "$conf" ] || [[ "$(basename "$conf")" == "vps_settings.conf" ]]; then - continue - fi - tunnel_name=$(basename "$conf" .conf) - if systemctl enable "ssh-tunnel-${tunnel_name}.service" 2>/dev/null; then - echo -e "${GREEN}✓ Автозапуск включен для $tunnel_name${NC}" - else - echo -e "${RED}✗ Ошибка для $tunnel_name${NC}" - fi - done - read -p "Нажмите Enter для продолжения..." - ;; - 2) - for conf in /etc/ssh_tunnel/*.conf; do - if [ ! -f "$conf" ] || [[ "$(basename "$conf")" == "vps_settings.conf" ]]; then - continue - fi - tunnel_name=$(basename "$conf" .conf) - if systemctl disable "ssh-tunnel-${tunnel_name}.service" 2>/dev/null; then - echo -e "${YELLOW}✓ Автозапуск выключен для $tunnel_name${NC}" - else - echo -e "${RED}✗ Ошибка для $tunnel_name${NC}" - fi - done - read -p "Нажмите Enter для продолжения..." - ;; - 3) - echo -e "${CYAN}Статус автозапуска:${NC}" - systemctl list-unit-files --type=service | grep ssh-tunnel || echo "Нет служб туннелей" - read -p "Нажмите Enter для продолжения..." - ;; - 4) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - sleep 1 - ;; - esac - done -} - -# Просмотр логов -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} Все логи туннелей" - echo -e "${CYAN}[3]${NC} Системные логи" - echo -e "${CYAN}[4]${NC} Лог монитора" - echo -e "${CYAN}[5]${NC} Реальный мониторинг" - echo -e "${CYAN}[6]${NC} Назад" - echo "" - - clear_input_buffer - read -p "Выберите действие: " choice - - case $choice in - 1) - echo -e "${CYAN}Доступные логи:${NC}" - for log_file in "$LOG_DIR"/*.log; do - if [ -f "$log_file" ]; then - echo " $(basename "$log_file")" - fi - done - echo "" - read -p "Введите имя лог-файла: " log_file - if [ -f "$LOG_DIR/$log_file" ]; then - less "$LOG_DIR/$log_file" - else - echo -e "${RED}Файл не найден${NC}" - sleep 1 - fi - ;; - 2) - echo -e "${CYAN}Все логи туннелей:${NC}" - for log_file in "$LOG_DIR"/*.log; do - if [ ! -f "$log_file" ]; then - continue - fi - echo -e "\n${YELLOW}=== $(basename "$log_file") ===${NC}" - tail -5 "$log_file" - done - read -p "Нажмите Enter для продолжения..." - ;; - 3) - echo -e "${CYAN}Системные логи туннелей:${NC}" - journalctl -u ssh-tunnel-* --since "1 hour ago" -n 10 2>/dev/null || echo "Логи отсутствуют" - read -p "Нажмите Enter для продолжения..." - ;; - 4) - if [ -f "$LOG_DIR/monitor.log" ]; then - echo -e "${CYAN}Лог монитора:${NC}" - tail -20 "$LOG_DIR/monitor.log" - else - echo -e "${YELLOW}Лог монитора отсутствует${NC}" - fi - read -p "Нажмите Enter для продолжения..." - ;; - 5) - echo -e "${CYAN}Реальный мониторинг логов (Ctrl+C для выхода)${NC}" - trap 'echo -e "\n${YELLOW}Мониторинг остановлен${NC}"; return' INT - tail -f "$LOG_DIR"/*.log 2>/dev/null || echo "Нет логов для мониторинга" - ;; - 6) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - sleep 1 - ;; - esac - done -} - -# Тестирование подключений -test_connections() { - while true; do - clear - echo -e "${CYAN}Тестирование подключений...${NC}" - echo "" - echo "1) Тест подключения к VPS" - echo "2) Тест портов туннелей" - echo "3) Назад" - echo "" - - clear_input_buffer - read -p "Выберите тест: " test_choice - - case $test_choice in - 1) - check_ssh_connection - ;; - 2) - echo -e "${CYAN}Тест портов туннелей:${NC}" - for conf in /etc/ssh_tunnel/*.conf; do - if [ ! -f "$conf" ] || [[ "$(basename "$conf")" == "vps_settings.conf" ]]; then - continue - fi - source "$conf" 2>/dev/null - 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 - done - ;; - 3) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - ;; - esac - - read -p "Нажмите Enter для продолжения..." - done -} - -# Настройка маршрутизации -setup_routing() { - while true; do - clear - echo -e "${CYAN}Настройка маршрутизации...${NC}" - echo "" - echo "1) Показать текущие правила iptables" - echo "2) Добавить правило перенаправления порта" - echo "3) Сохранить правила" - echo "4) Назад" - echo "" - - clear_input_buffer - read -p "Выберите действие: " routing_choice - - case $routing_choice in - 1) - echo -e "${CYAN}Текущие правила iptables:${NC}" - if command -v iptables &> /dev/null; then - iptables -t nat -L -n -v 2>/dev/null || echo "Ошибка при получении правил" - else - echo "iptables не установлен" - fi - ;; - 2) - read -p "Входной порт: " in_port - read -p "IP назначения: " dest_ip - read -p "Порт назначения: " dest_port - - if [ -n "$in_port" ] && [ -n "$dest_ip" ] && [ -n "$dest_port" ]; then - if command -v iptables &> /dev/null; then - iptables -t nat -A PREROUTING -p tcp --dport "$in_port" -j DNAT --to-destination "$dest_ip:$dest_port" 2>/dev/null - iptables -t nat -A POSTROUTING -p tcp -d "$dest_ip" --dport "$dest_port" -j MASQUERADE 2>/dev/null - echo -e "${GREEN}Правило добавлено${NC}" - else - echo -e "${RED}iptables не установлен${NC}" - fi - else - echo -e "${RED}Не все поля заполнены${NC}" - fi - ;; - 3) - if command -v iptables-save &> /dev/null; then - mkdir -p /etc/iptables - if iptables-save > /etc/iptables/rules.v4 2>/dev/null; then - echo -e "${GREEN}Правила сохранены${NC}" - else - echo -e "${RED}Ошибка сохранения${NC}" - fi - else - echo -e "${RED}iptables-save не найден${NC}" - fi - ;; - 4) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - ;; - esac - - read -p "Нажмите Enter для продолжения..." - done -} - -# Настройки SSH -setup_ssh_config() { - while true; do - clear - echo -e "${CYAN}Настройка SSH...${NC}" - echo "" - echo "1) Показать текущую конфигурацию SSH" - echo "2) Перезапустить SSH демон" - echo "3) Проверить конфигурацию" - echo "4) Назад" - echo "" - - clear_input_buffer - read -p "Выберите действие: " ssh_choice - - case $ssh_choice in - 1) - echo -e "${CYAN}Текущая конфигурация SSH:${NC}" - if [ -f /etc/ssh/sshd_config ]; then - grep -E "^(ClientAlive|TCPKeepAlive|ServerAlive|Port|PasswordAuthentication|PermitRootLogin)" /etc/ssh/sshd_config 2>/dev/null || echo "Настройки не найдены" - else - echo "Файл конфигурации не найден" - fi - ;; - 2) - if systemctl restart sshd 2>/dev/null || service ssh restart 2>/dev/null; then - echo -e "${GREEN}SSH демон перезапущен${NC}" - else - echo -e "${RED}Ошибка перезапуска SSH демона${NC}" - fi - ;; - 3) - if command -v sshd &> /dev/null; then - if sshd -t 2>/dev/null; then - echo -e "${GREEN}✓ Конфигурация SSH корректна${NC}" - else - echo -e "${RED}✗ Ошибка в конфигурации SSH${NC}" - fi - else - echo -e "${RED}sshd не найден${NC}" - fi - ;; - 4) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - ;; - esac - - read -p "Нажмите Enter для продолжения..." - done -} - -# Основное меню -show_menu() { - # Загрузка настроек - load_vps_settings - - while true; do - clear - echo -e "${BOLD}${CYAN}════════════════════════════════════════════════════════════════${NC}" - echo -e "${BOLD}${CYAN} АВТОНОМНЫЙ МЕНЕДЖЕР SSH ТУННЕЛЕЙ v4.0 ${NC}" - echo -e "${BOLD}${CYAN}════════════════════════════════════════════════════════════════${NC}" - - # Отображение текущих настроек VPS - if [ -n "$VPS_HOST" ]; then - echo -e "${CYAN}Текущий VPS: ${VPS_USER}@${VPS_HOST}:${VPS_PORT}${NC}" - else - echo -e "${RED}VPS не настроен! Выберите опцию 9 для настройки.${NC}" - fi - - echo "" - - # Проверка статуса подключения - if [ -n "$VPS_HOST" ]; then - echo -e "${CYAN}Статус подключения:${NC}" - if check_ssh_connection > /dev/null 2>&1; then - echo -e "${GREEN}✓ Соединение с VPS активно${NC}" + 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 - echo -e "${RED}✗ Нет соединения с VPS${NC}" + log_message "ОШИБКА: Не удалось скопировать ключ через sshpass." "$RED" + log_message "Возможно, пароль неверен, или на VPS не установлен ssh-copy-id." "$YELLOW" + log_message "Вам может потребоваться скопировать ключ вручную:" "$YELLOW" + cat /root/.ssh/id_rsa.pub fi - echo "" + else + log_message "ПРЕДУПРЕЖДЕНИЕ: sshpass не установлен. Невозможно скопировать ключ автоматически." "$YELLOW" + log_message "Вам потребуется скопировать ключ вручную:" "$YELLOW" + cat /root/.ssh/id_rsa.pub fi - - echo -e "${BOLD}${YELLOW}[1]${NC} Создать новый автономный туннель" - echo -e "${BOLD}${YELLOW}[2]${NC} Быстрый туннель (SSH 22 порт)" - echo -e "${BOLD}${YELLOW}[3]${NC} Управление существующими туннелями" - echo -e "${BOLD}${YELLOW}[4]${NC} Настройка автозапуска" - echo -e "${BOLD}${YELLOW}[5]${NC} Просмотр логов и мониторинг" - echo -e "${BOLD}${YELLOW}[6]${NC} Тестирование подключений" - echo -e "${BOLD}${YELLOW}[7]${NC} Настройка маршрутизации" - echo -e "${BOLD}${YELLOW}[8]${NC} Настройки SSH" - echo -e "${BOLD}${YELLOW}[9]${NC} Настройка/смена VPS" - echo -e "${BOLD}${YELLOW}[0]${NC} Выход" - echo "" - - clear_input_buffer - read -p "Выберите опцию [0-9]: " choice - - case $choice in - 1) create_tunnel ;; - 2) quick_ssh_tunnel ;; - 3) manage_tunnels ;; - 4) setup_autostart ;; - 5) view_logs ;; - 6) test_connections ;; - 7) setup_routing ;; - 8) setup_ssh_config ;; - 9) setup_new_vps ;; - 0) - echo -e "${GREEN}Выход...${NC}" - exit 0 - ;; - *) - echo -e "${RED}Неверный выбор. Попробуйте еще раз.${NC}" - sleep 1 - ;; - esac - done + 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 } -# Главный цикл -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - show_menu -fi -EOFMGR +# 3. Добавление нового туннеля +add_tunnel() { + check_root "add_tunnel" + if ! load_vps_settings; then + log_message "Сначала необходимо настроить VPS (опция 1)." "$RED" + return 1 + fi - # Создание файла с цветами - cat > /opt/ssh_tunnel_manager/colors.sh << 'EOFCOLORS' -#!/bin/bash -# Файл цветов для менеджера туннелей -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -PURPLE='\033[0;35m' -NC='\033[0m' -BOLD='\033[1m' -EOFCOLORS + echo -e "${BOLD}${CYAN}--- Добавление нового обратного туннеля (Local -> VPS) ---${NC}" + log_message "VPS: $VPS_USER@$VPS_HOST:$VPS_PORT" "$YELLOW" - # Делаем скрипт исполняемым - chmod +x /opt/ssh_tunnel_manager/manager.sh - chmod +x /opt/ssh_tunnel_manager/colors.sh + local LOCAL_PORT="" + local REMOTE_PORT="" + local TUNNEL_NAME="" - # Создание символической ссылки - ln -sf /opt/ssh_tunnel_manager/manager.sh /usr/local/bin/tunnel-manager 2>/dev/null + safe_read "Введите локальный порт, который нужно пробросить (например, 22 для SSH): " "" LOCAL_PORT + safe_read "Введите удаленный порт на VPS, через который будет доступен локальный порт (например, 10022): " "" REMOTE_PORT + safe_read "Введите имя туннеля (например, 'ssh_access'): " "" TUNNEL_NAME - log_message "Основной скрипт установлен в /opt/ssh_tunnel_manager/" "$GREEN" - return 0 -} - -# Настройка systemd служб -setup_systemd_services() { - log_message "Настройка systemd служб для автономной работы..." "$CYAN" + if [ -z "$LOCAL_PORT" ] || [ -z "$REMOTE_PORT" ] || [ -z "$TUNNEL_NAME" ]; then + log_message "ОШИБКА: Все поля обязательны." "$RED" + return 1 + fi - # Основная служба мониторинга - cat > /etc/systemd/system/tunnel-monitor.service << 'EOFSERVICE' + # Проверка имени туннеля + 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 туннелей +Description=SSH Reverse Tunnel: $TUNNEL_NAME ($LOCAL_PORT -> $REMOTE_PORT) After=network-online.target Wants=network-online.target [Service] Type=simple -ExecStart=/opt/ssh_tunnel_manager/monitor.sh -Restart=always -RestartSec=30 -User=root - -StandardOutput=append:/var/log/ssh_tunnel/monitor.log -StandardError=append:/var/log/ssh_tunnel/monitor.log - -[Install] -WantedBy=multi-user.target -EOFSERVICE - - # Скрипт мониторинга - cat > /opt/ssh_tunnel_manager/monitor.sh << 'EOFMONITOR' -#!/bin/bash -# Скрипт мониторинга туннелей - -LOG_FILE="/var/log/ssh_tunnel/monitor.log" -CONFIG_DIR="/etc/ssh_tunnel" - -log() { - echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" -} - -check_tunnel() { - local config_file="$1" - local tunnel_name=$(basename "$config_file" .conf) - - if [ ! -f "$config_file" ]; then - return 1 - fi - - source "$config_file" - - # Проверяем, работает ли туннель - if ps aux | grep -v grep | grep -q "autossh.*$REMOTE_PORT.*$VPS_HOST"; then - # Проверяем доступность порта - if timeout 2 nc -z localhost "$LOCAL_PORT" 2>/dev/null; then - log "Туннель $tunnel_name: OK" - return 0 - fi - fi - - log "Туннель $tunnel_name: FAILED - перезапуск" - - # Перезапускаем службу - if systemctl is-active --quiet "ssh-tunnel-$tunnel_name.service" 2>/dev/null; then - systemctl restart "ssh-tunnel-$tunnel_name.service" - else - # Запускаем туннель напрямую - /usr/bin/autossh -M 0 -N \ - -o "ExitOnForwardFailure=yes" \ - -o "ServerAliveInterval=30" \ - -o "ServerAliveCountMax=3" \ - -R "${REMOTE_PORT}:localhost:${LOCAL_PORT}" \ - "${VPS_USER}@${VPS_HOST}" -p "${VPS_PORT}" & - fi - - return 1 -} - -log "Запуск монитора SSH туннелей" - -while true; do - # Проверяем все конфигурации (кроме vps_settings.conf) - for config in "$CONFIG_DIR"/*.conf; do - if [ -f "$config" ] && [[ "$(basename "$config")" != "vps_settings.conf" ]]; then - check_tunnel "$config" - fi - done - - sleep 60 -done -EOFMONITOR - - chmod +x /opt/ssh_tunnel_manager/monitor.sh - - # Создание таймера для периодической проверки - cat > /etc/systemd/system/tunnel-check.timer << 'EOFTIMER' -[Unit] -Description=Периодическая проверка SSH туннелей - -[Timer] -OnBootSec=5min -OnUnitActiveSec=5min -AccuracySec=1min - -[Install] -WantedBy=timers.target -EOFTIMER - - # Включение служб - systemctl daemon-reload 2>/dev/null - systemctl enable tunnel-monitor.service 2>/dev/null - systemctl enable tunnel-check.timer 2>/dev/null - systemctl start tunnel-monitor.service 2>/dev/null - systemctl start tunnel-check.timer 2>/dev/null - - log_message "Systemd службы настроены" "$GREEN" - return 0 -} - -# Создание примера туннеля -create_example_tunnel() { - log_message "Создание примера SSH туннеля..." "$CYAN" - - # Загружаем настройки VPS - if [ -f /etc/ssh_tunnel/vps_settings.conf ]; then - source /etc/ssh_tunnel/vps_settings.conf - fi - - if [ -n "$VPS_HOST" ] && [ -n "$VPS_USER" ]; then - read -p "Создать пример туннеля для SSH (порт 22 -> 10022)? (y/n): " CREATE_EXAMPLE - - if [[ "$CREATE_EXAMPLE" =~ ^[Yy]$ ]]; then - cat > /etc/ssh_tunnel/example_ssh.conf << EOFEXAMPLE -# Пример туннеля для SSH доступа -TUNNEL_NAME="example_ssh" -VPS_HOST="$VPS_HOST" -VPS_PORT="$VPS_PORT" -VPS_USER="$VPS_USER" -LOCAL_PORT="22" -REMOTE_PORT="10022" -ENABLED="true" -EOFEXAMPLE - - # Создание службы для примера - cat > /etc/systemd/system/ssh-tunnel-example_ssh.service << 'EOFEXSERVICE' -[Unit] -Description=Пример SSH туннеля (22->10022) -After=network-online.target - -[Service] -Type=simple -EnvironmentFile=/etc/ssh_tunnel/example_ssh.conf +EnvironmentFile=$CONFIG_FILE ExecStart=/usr/bin/autossh -M 0 -N \ -o "ExitOnForwardFailure=yes" \ -o "ServerAliveInterval=30" \ @@ -1533,140 +421,482 @@ ExecStart=/usr/bin/autossh -M 0 -N \ -o "UserKnownHostsFile=/dev/null" \ -o "TCPKeepAlive=yes" \ -o "ConnectTimeout=30" \ - -R ${REMOTE_PORT}:localhost:${LOCAL_PORT} \ - ${VPS_USER}@${VPS_HOST} -p ${VPS_PORT} + -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:/var/log/ssh_tunnel/example_ssh.log -StandardError=append:/var/log/ssh_tunnel/example_ssh.log +StandardOutput=append:$LOG_DIR/$TUNNEL_ID.log +StandardError=append:$LOG_DIR/$TUNNEL_ID.log [Install] WantedBy=multi-user.target -EOFEXSERVICE +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") - systemctl daemon-reload 2>/dev/null - systemctl enable ssh-tunnel-example_ssh.service 2>/dev/null - systemctl start ssh-tunnel-example_ssh.service 2>/dev/null + local STATUS_COLOR="$RED" + if [ "$STATUS" == "active" ]; then + STATUS_COLOR="$GREEN" + elif [ "$STATUS" == "inactive" ]; then + STATUS_COLOR="$YELLOW" + fi - log_message "Пример туннеля создан!" "$GREEN" - echo -e "${CYAN}Для подключения используйте:${NC}" - echo -e "${BOLD}ssh -p 10022 $VPS_USER@$VPS_HOST${NC}" - echo "" - echo -e "${YELLOW}Проверьте подключение:${NC}" - echo -e " systemctl status ssh-tunnel-example_ssh.service" - echo -e " tail -f /var/log/ssh_tunnel/example_ssh.log" + printf "%-20s | %-10s | %-10s | ${STATUS_COLOR}%-20s${NC} | %-10s\n" \ + "$TUNNEL_ID" "$LOCAL_PORT" "$REMOTE_PORT" "$STATUS" "$ENABLED" + count=$((count + 1)) fi - else - echo -e "${YELLOW}Не удалось создать пример туннеля: настройки VPS не найдены${NC}" + done + + if [ "$count" -eq 0 ]; then + echo -e "${YELLOW}Туннели не найдены. Используйте опцию 2 для добавления нового.${NC}" fi - return 0 + echo "" } -# Завершение установки -finish_installation() { - echo "" - echo -e "${BOLD}${GREEN}════════════════════════════════════════════════════════════════${NC}" - echo -e "${BOLD}${GREEN} УСТАНОВКА УСПЕШНО ЗАВЕРШЕНА! ${NC}" - echo -e "${BOLD}${GREEN}════════════════════════════════════════════════════════════════${NC}" - echo "" - - log_message "Итоги установки:" "$CYAN" - echo -e "${GREEN}✓${NC} Зависимости установлены" - echo -e "${GREEN}✓${NC} SSH ключи сгенерированы и настроены" - echo -e "${GREEN}✓${NC} SSH конфигурация улучшена для стабильности" - echo -e "${GREEN}✓${NC} Основной скрипт установлен" - echo -e "${GREEN}✓${NC} Systemd службы настроены" - echo -e "${GREEN}✓${NC} Автозапуск включен" - echo "" - - # Загружаем настройки VPS для отображения - if [ -f /etc/ssh_tunnel/vps_settings.conf ]; then - source /etc/ssh_tunnel/vps_settings.conf - echo -e "${BOLD}Информация о подключении:${NC}" - echo -e " VPS: $VPS_USER@$VPS_HOST:$VPS_PORT" - echo -e " SSH ключ: /root/.ssh/id_rsa" - echo -e " Конфиг SSH: /root/.ssh/config" +# Функция просмотра логов +view_logs() { + while true; do + clear + echo -e "${BOLD}${CYAN}Просмотр логов${NC}" + echo -e "${YELLOW}=============${NC}" echo "" - fi - - echo -e "${BOLD}Команды для управления:${NC}" - echo -e " ${CYAN}tunnel-manager${NC} - запуск менеджера туннелей" - echo -e " ${CYAN}systemctl status tunnel-monitor${NC} - статус монитора" - echo -e " ${CYAN}journalctl -u tunnel-monitor -f${NC} - просмотр логов" - echo "" - - echo -e "${BOLD}Автономная работа гарантирована!${NC}" - echo -e "Система автоматически запустится после перезагрузки." - echo "" - echo -e "${YELLOW}Полный лог установки: $LOG_FILE${NC}" - echo "" - - # Запрос на перезагрузку - read -p "Перезагрузить систему для применения всех настроек? (y/n): " REBOOT_NOW - - if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]]; then - log_message "Перезагрузка системы по запросу пользователя..." "$YELLOW" - echo -e "${YELLOW}Система перезагрузится через 5 секунд...${NC}" - sleep 5 - reboot - else + echo -e "${CYAN}[1]${NC} Логи конкретного туннеля" + echo -e "${CYAN}[2]${NC} Все логи туннелей (последние 5 строк)" + echo -e "${CYAN}[3]${NC} Системные логи (journalctl)" + echo -e "${CYAN}[4]${NC} Назад" echo "" - echo -e "${GREEN}Для запуска менеджера выполните:${NC}" - echo -e "${BOLD}tunnel-manager${NC}" - echo "" - fi - return 0 + + 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 } -# Главная функция установки -main_installation() { - log_message "Начало установки автономного менеджера SSH туннелей" "$CYAN" - - # Определяем дистрибутив - detect_distro || { - echo -e "${RED}Не удалось определить дистрибутив${NC}" - exit 1 - } - - # Устанавливаем зависимости - install_dependencies || { - echo -e "${RED}Не удалось установить зависимости${NC}" - exit 1 - } - - # Настраиваем SSH - setup_ssh || { - echo -e "${RED}Не удалось настроить SSH${NC}" - exit 1 - } - - # Устанавливаем основной скрипт - install_main_script || { - echo -e "${RED}Не удалось установить основной скрипт${NC}" - exit 1 - } - - # Настраиваем systemd службы - setup_systemd_services || { - echo -e "${YELLOW}Не удалось настроить systemd службы${NC}" - } - - # Создаем пример туннеля - create_example_tunnel || { - echo -e "${YELLOW}Не удалось создать пример туннеля${NC}" - } - - # Завершаем установку - finish_installation +# Функция тестирования подключений +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 } -# Обработка ошибок и трассировка -set -eE -trap 'echo -e "${RED}Произошла ошибка в строке $LINENO. Проверьте лог: $LOG_FILE${NC}"' ERR +# Функция настройки маршрутизации (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 +} -# Запуск установки -main_installation +# Функция настройки 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 +} -exit 0 \ No newline at end of file +# 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 +} + +# --- Точка входа --- +case "$1" in + install) + install_manager + ;; + menu) + main_menu + ;; + *) + echo -e "${BOLD}${CYAN}SSH Tunnel Manager v1.0${NC}" + echo -e "Использование: sudo bash $0 {install|menu}" + echo -e " ${BOLD}install${NC} - Устанавливает зависимости и копирует скрипт в /usr/local/bin/tunnel-manager" + echo -e " ${BOLD}menu${NC} - Запускает интерактивное меню управления туннелями" + echo "" + echo -e "Рекомендуемый первый запуск: ${BOLD}sudo bash $0 install${NC}" + ;; +esac + +exit 0