diff --git a/install_ssh_tunnel.sh b/install_ssh_tunnel.sh index 5eccc3a..77783d7 100644 --- a/install_ssh_tunnel.sh +++ b/install_ssh_tunnel.sh @@ -1,7 +1,12 @@ -#!/bin/bash +#!/usr/bin/env bash # Установщик автономного менеджера SSH туннелей -# Использование: bash <(curl -s https://git.softuniq.eu/OpenDoor/vps_ssh_tunel/raw/branch/main/install_ssh_tunnel.sh) +# Версия: 1.0.0 +# Дата: 2025-12-22 +# Авторы: OpenDoor Team +# Лицензия: MIT + +set -euo pipefail # Цвета для вывода RED='\033[0;31m' @@ -13,1596 +18,309 @@ NC='\033[0m' BOLD='\033[1m' # Логирование -LOG_FILE="/tmp/ssh_tunnel_install.log" +LOG_FILE="/tmp/ssh_tunnel_install_$(date '+%Y%m%d_%H%M%S').log" log_message() { - echo -e "${2:-$NC}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}" | tee -a "$LOG_FILE" + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } +# Проверка прав root +if [[ $EUID -ne 0 ]]; then + echo -e "${RED}Этот скрипт требует прав root.${NC}" + exit 1 +fi + 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}" +# Определение дистрибутива +OS="" +VERSION="" +if [ -f /etc/os-release ]; then + . /etc/os-release + OS=$ID + VERSION=$VERSION_ID +elif [ -f /etc/redhat-release ]; then + OS="rhel" + VERSION=$(sed 's/.*release \([0-9]\).*/\1/' /etc/redhat-release) +else + echo -e "${RED}Неизвестная ОС.${NC}" exit 1 fi -# Функция безопасного ввода с ограничением попыток -safe_read() { - local prompt="$1" - local default="$2" - local var_name="$3" - local is_password="$4" - local max_attempts="${5:-3}" # По умолчанию 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 -} - -# Функция проверки ошибок -check_error() { - if [ $? -ne 0 ]; then - log_message "ОШИБКА: $1" "$RED" - log_message "Подробности в логе: $LOG_FILE" "$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 -} - -# Определение дистрибутива -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) - fi - - log_message "Система: $OS $VERSION" "$GREEN" - return 0 -} - # Установка зависимостей install_dependencies() { - log_message "Установка необходимых зависимостей..." "$CYAN" - + log_message "Установка зависимостей..." 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 "Не удалось установить пакеты" + apt-get update + apt-get install -y autossh openssh-client sshpass curl git net-tools ;; - 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" + dnf install -y autossh openssh-clients net-tools curl git sshpass else - yum install -y autossh openssh-clients net-tools curl git sshpass 2>&1 | tee -a "$LOG_FILE" + yum install -y autossh openssh-clients net-tools curl git sshpass fi - check_error "Не удалось установить пакеты" ;; - *) - log_message "Неизвестный дистрибутив. Попытка установки вручную..." "$YELLOW" - # Попытка установить autossh из исходников - 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 + echo -e "${RED}Не поддерживаемый дистрибутив.${NC}" + exit 1 ;; esac - - log_message "Зависимости успешно установлены!" "$GREEN" - return 0 + log_message "Зависимости установлены." } # Настройка SSH setup_ssh() { - log_message "Настройка SSH системы..." "$CYAN" - - # Создание директорий SSH если их нет + log_message "Настройка 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 attempt=1 local max_attempts=3 - - for ((attempt=1; attempt<=max_attempts; attempt++)); do - echo -e "${CYAN}Введите данные для подключения к VPS (попытка $attempt из $max_attempts):${NC}" - - # Используем обычный read для предотвращения конфликтов с safe_read - read -p "IP адрес или доменное имя VPS: " VPS_HOST + while [ $attempt -le $max_attempts ]; do + echo -e "${CYAN}Попытка $attempt из $max_attempts:${NC}" + read -p "IP адрес или домен VPS: " VPS_HOST read -p "Порт SSH (по умолчанию 22): " VPS_PORT VPS_PORT=${VPS_PORT:-22} - - echo "" - echo -e "${CYAN}Выберите пользователя для подключения:${NC}" - echo "1) root (рекомендуется для полного доступа)" - echo "2) Другой пользователь" - read -p "Ваш выбор [1-2]: " USER_CHOICE - + echo -e "${CYAN}Выберите пользователя:${NC}" + echo "1) root" + echo "2) Другой" + read -p "Выбор [1-2]: " USER_CHOICE if [ "$USER_CHOICE" == "1" ]; then VPS_USER="root" - echo -e "${YELLOW}Будет использоваться пользователь: root${NC}" else - read -p "Введите имя пользователя: " VPS_USER + 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 + + if [ -z "$VPS_HOST" ] || [ -z "$VPS_USER" ]; then + echo -e "${RED}Обязательные поля не заполнены!${NC}" + attempt=$((attempt+1)) + continue 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]$ ]]; then - vps_data_ok=true + + echo -e "${CYAN}Проверка данных:${NC}" + echo "VPS: $VPS_USER@$VPS_HOST:$VPS_PORT" + read -p "Верно? (y/n): " CONFIRM + if [[ $CONFIRM =~ ^[Yy]$ ]]; then break - else - echo -e "${YELLOW}Повторите ввод данных...${NC}" - echo "" fi + attempt=$((attempt+1)) done - - if [ "$vps_data_ok" = false ]; then - echo -e "${RED}Не удалось получить корректные данные VPS. Выход.${NC}" + + if [ $attempt -gt $max_attempts ]; then + echo -e "${RED}Превышено количество попыток. Выход.${NC}" exit 1 fi - - # Проверка подключения - log_message "Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT..." "$BLUE" - echo -e "${CYAN}Пытаюсь подключиться к VPS...${NC}" - - 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) Не блокирует ли брандмауэр подключение" - - read -p "Продолжить все равно? (y/n): " CONTINUE - - if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then - exit 1 - fi + + # Генерация ключа + if [ ! -f /root/.ssh/id_ed25519 ]; then + ssh-keygen -t ed25519 -N "" -f /root/.ssh/id_ed25519 -q + log_message "SSH ключ сгенерирован." fi - - # Генерация 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 - ssh-keygen -t rsa -b 4096 -N "" -f /root/.ssh/id_rsa -q - log_message "SSH ключ сгенерирован" "$GREEN" - fi - - # Настройка SSH конфигурации для стабильного подключения - log_message "Настройка конфигурации SSH для стабильного подключения..." "$BLUE" - - # Создание конфига для root с улучшенными настройками - cat > /root/.ssh/config << EOFCONFIG -# Основная конфигурация SSH + + # Конфиг SSH + cat > /root/.ssh/config << EOF Host tunnel-vps HostName $VPS_HOST Port $VPS_PORT User $VPS_USER - IdentityFile ~/.ssh/id_rsa - StrictHostKeyChecking no - UserKnownHostsFile /dev/null + IdentityFile ~/.ssh/id_ed25519 + StrictHostKeyChecking accept-new ServerAliveInterval 30 ServerAliveCountMax 3 - ConnectTimeout 30 - TCPKeepAlive yes - IdentitiesOnly yes ExitOnForwardFailure yes - # Увеличенные настройки для локальной сети - IPQoS throughput - Compression yes - ControlMaster auto - ControlPath ~/.ssh/control-%r@%h:%p - ControlPersist 10m - # Дополнительные настройки стабильности - 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 - +EOF chmod 600 /root/.ssh/config - - # Настройка SSH демона для локальных подключений - log_message "Настройка SSH демона для локальных подключений..." "$BLUE" - - # Бэкап оригинального конфига - 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" - else - log_message "Не удалось перезапустить SSH демон" "$YELLOW" - fi - fi - - # Копирование ключа на 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 + + # Копирование ключа + read -s -p "Пароль для $VPS_USER@$VPS_HOST (Enter для пропуска): " VPS_PASSWORD echo - - if [ -n "$VPS_PASSWORD" ]; then - echo "" - echo -e "${CYAN}Попытка копирования ключа с использованием пароля...${NC}" - - # Установка SSH_ASKPASS для автоматического ввода пароля - export SSH_ASKPASS="$(mktemp)" - cat > "$SSH_ASKPASS" << EOFASKPASS -#!/bin/bash -echo "$VPS_PASSWORD" -EOFASKPASS - chmod +x "$SSH_ASKPASS" - export DISPLAY=:0 - - # Пытаемся скопировать ключ с использованием 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 - - # Очистка временного файла - rm -f "$SSH_ASKPASS" + if [ -n "$VPS_PASSWORD" ] && command -v sshpass &> /dev/null; then + sshpass -p "$VPS_PASSWORD" ssh-copy-id -i /root/.ssh/id_ed25519.pub "$VPS_USER@$VPS_HOST" -p "$VPS_PORT" + log_message "Ключ скопирован." else - echo -e "${YELLOW}Пароль не введен, пропускаю автоматическое копирование ключа${NC}" + echo -e "${YELLOW}Скопируйте вручную: cat /root/.ssh/id_ed25519.pub${NC}" + read -p "Нажмите Enter после добавления на VPS..." fi - - # Альтернативный метод копирования ключа - 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 "" - - read -p "Нажмите Enter после добавления ключа на VPS..." WAIT - - # Тестовое подключение - log_message "Тестовое подключение к VPS..." "$BLUE" - echo -e "${CYAN}Пытаюсь подключиться без пароля...${NC}" - - if timeout 15 ssh -p "$VPS_PORT" \ - -o BatchMode=yes \ - -o ConnectTimeout=10 \ - -o StrictHostKeyChecking=no \ - "$VPS_USER@$VPS_HOST" \ - "echo 'SSH подключение успешно!'" 2>&1; then - log_message "Тестовое подключение прошло успешно!" "$GREEN" - echo -e "${GREEN}✓ SSH ключ настроен корректно${NC}" + + # Тест подключения + if ssh -o BatchMode=yes "$VPS_USER@$VPS_HOST" -p "$VPS_PORT" echo "OK"; then + log_message "Подключение успешно." 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 + echo -e "${RED}Подключение не удалось. Проверьте настройки.${NC}" + exit 1 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 - fi - - # Сохранение настроек VPS для использования в скриптах - log_message "Сохранение настроек VPS..." "$BLUE" - + + # Сохранение настроек mkdir -p /etc/ssh_tunnel - cat > /etc/ssh_tunnel/vps_settings.conf << EOFSETTINGS -# Настройки VPS для автономных туннелей + cat > /etc/ssh_tunnel/vps_settings.conf << EOF VPS_HOST="$VPS_HOST" VPS_PORT="$VPS_PORT" VPS_USER="$VPS_USER" -CONFIGURED_ON="$(date '+%Y-%m-%d %H:%M:%S')" -EOFSETTINGS - +EOF chmod 600 /etc/ssh_tunnel/vps_settings.conf - log_message "Настройки SSH сохранены в /etc/ssh_tunnel/vps_settings.conf" "$GREEN" - return 0 } -# Установка основного скрипта управления +# Установка основного скрипта install_main_script() { - log_message "Установка основного скрипта управления туннелями..." "$CYAN" - - # Создание директорий - mkdir -p /opt/ssh_tunnel_manager - mkdir -p /var/log/ssh_tunnel - mkdir -p /etc/ssh_tunnel - - # Загрузка настроек VPS если есть - if [ -f /etc/ssh_tunnel/vps_settings.conf ]; then - source /etc/ssh_tunnel/vps_settings.conf - fi - - # Создание основного скрипта менеджера с корректным завершением EOF - cat > /opt/ssh_tunnel_manager/manager.sh << 'EOFMGR' + log_message "Установка менеджера..." + mkdir -p /opt/ssh_tunnel_manager /var/log/ssh_tunnel + + cat > /opt/ssh_tunnel_manager/manager.sh << 'EOF' #!/bin/bash -# Основной скрипт менеджера SSH туннелей -# Версия 4.0 - Стабильное меню +# Автономный менеджер SSH туннелей +# Использование: tunnel-manager [команда] + +source /etc/ssh_tunnel/vps_settings.conf 2>/dev/null || { + echo "Настройки VPS не найдены!" + exit 1 +} + +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' -# Конфигурация 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 +list_tunnels() { + echo -e "${CYAN}Активные туннели:${NC}" + systemctl list-units --type=service --all | grep ssh-tunnel || echo "Нет туннелей." } -# Функция безопасного ввода -safe_read() { - 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 для продолжения..." -} - -# Создание туннеля 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 - + read -p "Локальный порт: " LOCAL_PORT + read -p "Удаленный порт на VPS: " REMOTE_PORT if [ -z "$LOCAL_PORT" ] || [ -z "$REMOTE_PORT" ]; then - echo -e "${RED}Ошибка: не все поля заполнены${NC}" - return + echo -e "${RED}Поля обязательны.${NC}" + exit 1 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 + + TUNNEL_ID="tunnel_${REMOTE_PORT}" + SERVICE_FILE="/etc/systemd/system/ssh-${TUNNEL_ID}.service" + + cat > "$SERVICE_FILE" << EOSERVICE [Unit] -Description=SSH Tunnel: $TUNNEL_ID -After=network-online.target -Wants=network-online.target +Description=SSH Tunnel ${TUNNEL_ID} +After=network.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 +ExecStart=/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NL *:${REMOTE_PORT}:localhost:${LOCAL_PORT} ${VPS_USER}@${VPS_HOST} -p ${VPS_PORT} +Restart=always +RestartSec=5 [Install] WantedBy=multi-user.target -SERVICETUN - +EOSERVICE + 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 для продолжения..." + systemctl enable ssh-${TUNNEL_ID} + systemctl start ssh-${TUNNEL_ID} + echo -e "${GREEN}Туннель создан.${NC}" } -# Быстрый 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 для продолжения..." -} - -# Управление туннелями -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 - ((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" ]; 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) - - source "$conf" 2>/dev/null || { - echo -e "${RED}Ошибка загрузки конфигурации${NC}" - return - } - - 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}" - tail -20 "/var/log/ssh_tunnel/${tunnel_name}.log" 2>/dev/null || echo "Логи отсутствуют" - 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}" - 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" ]; then - continue - fi - tunnel_name=$(basename "$conf" .conf) - systemctl enable "ssh-tunnel-${tunnel_name}.service" 2>/dev/null && \ - echo -e "${GREEN}✓ Автозапуск включен для $tunnel_name${NC}" || \ - echo -e "${RED}✗ Ошибка для $tunnel_name${NC}" - done - read -p "Нажмите Enter для продолжения..." - ;; - 2) - for conf in /etc/ssh_tunnel/*.conf; do - if [ ! -f "$conf" ]; then - continue - fi - tunnel_name=$(basename "$conf" .conf) - systemctl disable "ssh-tunnel-${tunnel_name}.service" 2>/dev/null && \ - echo -e "${YELLOW}✗ Автозапуск выключен для $tunnel_name${NC}" || \ - echo -e "${RED}✗ Ошибка для $tunnel_name${NC}" - 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 in $LOG_DIR/*.log; do - if [ ! -f "$log" ]; then - continue - fi - echo " $(basename $log)" - 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 in $LOG_DIR/*.log; do - if [ ! -f "$log" ]; then - continue - fi - echo -e "\n${YELLOW}=== $(basename $log) ===${NC}" - tail -5 "$log" - 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}"' INT - tail -f $LOG_DIR/*.log 2>/dev/null - ;; - 6) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - sleep 1 - ;; - esac - done -} - -# Тестирование подключений -test_connections() { - echo -e "${CYAN}Тестирование подключений...${NC}" - - echo "1) Тест подключения к VPS" - echo "2) Тест портов туннелей" - echo "3) Назад" - - 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" ]; 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 для продолжения..." -} - -# Настройка маршрутизации -setup_routing() { - echo -e "${CYAN}Настройка маршрутизации...${NC}" - - echo "1) Показать текущие правила iptables" - echo "2) Добавить правило перенаправления порта" - echo "3) Сохранить правила" - echo "4) Назад" - - clear_input_buffer - read -p "Выберите действие: " routing_choice - - case $routing_choice in - 1) - echo -e "${CYAN}Текущие правила iptables:${NC}" - iptables -t nat -L -n -v 2>/dev/null || echo "iptables не установлен" - ;; - 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 - 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}Не все поля заполнены${NC}" - fi - ;; - 3) - if command -v iptables-save &> /dev/null; then - mkdir -p /etc/iptables - iptables-save > /etc/iptables/rules.v4 2>/dev/null && \ - echo -e "${GREEN}Правила сохранены${NC}" || \ - echo -e "${RED}Ошибка сохранения${NC}" - else - echo -e "${RED}iptables-save не найден${NC}" - fi - ;; - 4) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - ;; - esac - - read -p "Нажмите Enter для продолжения..." -} - -# Настройки SSH -setup_ssh_config() { - echo -e "${CYAN}Настройка SSH...${NC}" - - echo "1) Показать текущую конфигурацию SSH" - echo "2) Перезапустить SSH демон" - echo "3) Проверить конфигурацию" - echo "4) Назад" - - clear_input_buffer - read -p "Выберите действие: " ssh_choice - - case $ssh_choice in - 1) - echo -e "${CYAN}Текущая конфигурация SSH:${NC}" - grep -E "^(ClientAlive|TCPKeepAlive|ServerAlive|Port|PasswordAuthentication|PermitRootLogin)" /etc/ssh/sshd_config 2>/dev/null || echo "Конфигурация не найдена" - ;; - 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 sshd -t 2>/dev/null; then - echo -e "${GREEN}✓ Конфигурация SSH корректна${NC}" - else - echo -e "${RED}✗ Ошибка в конфигурации SSH${NC}" - fi - ;; - 4) - return - ;; - *) - echo -e "${RED}Неверный выбор${NC}" - ;; - esac - - read -p "Нажмите Enter для продолжения..." -} - -# Основное меню -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; then - echo -e "${GREEN}✓ Соединение с VPS активно${NC}" - else - echo -e "${RED}✗ Нет соединения с VPS${NC}" - fi - echo "" - 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 -} - -# Главный цикл -if [ "$0" = "$BASH_SOURCE" ] || [ "$0" = "./manager.sh" ]; then - show_menu -fi -EOFMGR - - # Создание файла с цветами - 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 - - # Делаем скрипт исполняемым +case "$1" in + list) list_tunnels ;; + create) create_tunnel ;; + *) echo "Использование: tunnel-manager [list|create]" ;; +esac +EOF chmod +x /opt/ssh_tunnel_manager/manager.sh - chmod +x /opt/ssh_tunnel_manager/colors.sh - - # Создание символической ссылки - ln -sf /opt/ssh_tunnel_manager/manager.sh /usr/local/bin/tunnel-manager 2>/dev/null - - log_message "Основной скрипт установлен в /opt/ssh_tunnel_manager/" "$GREEN" - return 0 + ln -sf /opt/ssh_tunnel_manager/manager.sh /usr/local/bin/tunnel-manager } -# Настройка systemd служб -setup_systemd_services() { - log_message "Настройка systemd служб для автономной работы..." "$CYAN" - - # Основная служба мониторинга - cat > /etc/systemd/system/tunnel-monitor.service << EOFSERVICE +# Настройка монитора +setup_monitor() { + cat > /etc/systemd/system/tunnel-monitor.service << EOF [Unit] -Description=Мониторинг и восстановление SSH туннелей -After=network-online.target -Wants=network-online.target +Description=Мониторинг SSH туннелей +After=network.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' +EOF + + cat > /opt/ssh_tunnel_manager/monitor.sh << 'EOF' #!/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 - # Проверяем все конфигурации - for config in "$CONFIG_DIR"/*.conf; do - if [ -f "$config" ]; then - check_tunnel "$config" + # Проверка и перезапуск туннелей + systemctl list-units --type=service | grep ssh-tunnel | while read service; do + if ! systemctl is-active $service; then + systemctl start $service fi done - sleep 60 done -EOFMONITOR - +EOF 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 + systemctl daemon-reload + systemctl enable tunnel-monitor + systemctl start tunnel-monitor } -# Создание примера туннеля +# Пример туннеля create_example_tunnel() { - log_message "Создание примера SSH туннеля..." "$CYAN" - - 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 + source /etc/ssh_tunnel/vps_settings.conf + LOCAL_PORT=22 + REMOTE_PORT=10022 + TUNNEL_ID="example" + SERVICE_FILE="/etc/systemd/system/ssh-tunnel-${TUNNEL_ID}.service" + + cat > "$SERVICE_FILE" << EOSERVICE [Unit] -Description=Пример SSH туннеля (22->10022) -After=network-online.target +Description=Пример SSH туннеля +After=network.target [Service] -Type=simple -EnvironmentFile=/etc/ssh_tunnel/example_ssh.conf -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/example_ssh.log -StandardError=append:/var/log/ssh_tunnel/example_ssh.log +ExecStart=/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NR *:${REMOTE_PORT}:localhost:${LOCAL_PORT} ${VPS_USER}@${VPS_HOST} -p ${VPS_PORT} +Restart=always +RestartSec=5 [Install] WantedBy=multi-user.target -EOFEXSERVICE - - 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 - - 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" - fi - fi - return 0 +EOSERVICE + + systemctl daemon-reload + systemctl enable ssh-tunnel-${TUNNEL_ID} + systemctl start ssh-tunnel-${TUNNEL_ID} + echo -e "${GREEN}Пример туннеля создан (22 -> 10022).${NC}" } -# Завершение установки +# Завершение 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 "" - - if [ -n "$VPS_HOST" ]; then - 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" - 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 "" - echo -e "${GREEN}Для запуска менеджера выполните:${NC}" - echo -e "${BOLD}tunnel-manager${NC}" - echo "" - fi - return 0 + echo -e "${GREEN}Установка завершена!${NC}" + echo "Запустите tunnel-manager для управления." + log_message "Установка завершена." } -# Главная функция установки -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 -} - -# Обработка ошибок и трассировка -set -eE -trap 'echo -e "${RED}Произошла ошибка в строке $LINENO. Проверьте лог: $LOG_FILE${NC}"' ERR - -# Запуск установки -main_installation - -exit 0 \ No newline at end of file +install_dependencies +setup_ssh +install_main_script +setup_monitor +create_example_tunnel +finish_installation \ No newline at end of file