diff --git a/install_ssh_tunnel.sh b/install_ssh_tunnel.sh index 77783d7..00178e5 100644 --- a/install_ssh_tunnel.sh +++ b/install_ssh_tunnel.sh @@ -1,12 +1,7 @@ -#!/usr/bin/env bash +#!/bin/bash # Установщик автономного менеджера SSH туннелей -# Версия: 1.0.0 -# Дата: 2025-12-22 -# Авторы: OpenDoor Team -# Лицензия: MIT - -set -euo pipefail +# Использование: bash <(curl -s https://git.softuniq.eu/OpenDoor/vps_ssh_tunel/raw/branch/main/install_ssh_tunnel.sh) # Цвета для вывода RED='\033[0;31m' @@ -18,309 +13,1660 @@ NC='\033[0m' BOLD='\033[1m' # Логирование -LOG_FILE="/tmp/ssh_tunnel_install_$(date '+%Y%m%d_%H%M%S').log" +LOG_FILE="/tmp/ssh_tunnel_install.log" log_message() { - echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" + echo -e "${2:-$NC}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}" | 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 "" -# Определение дистрибутива -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}" +# Проверка прав 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 +} + +# Функция проверки ошибок +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 "Установка зависимостей..." + log_message "Установка необходимых зависимостей..." "$CYAN" + case $OS in ubuntu|debian) - apt-get update - apt-get install -y autossh openssh-client sshpass curl git net-tools + 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 + 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 + 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 ;; - *) - echo -e "${RED}Не поддерживаемый дистрибутив.${NC}" - exit 1 - ;; esac - log_message "Зависимости установлены." + + log_message "Зависимости успешно установлены!" "$GREEN" + return 0 } # Настройка SSH setup_ssh() { - log_message "Настройка 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 "" - - local attempt=1 + + # Запрос данных VPS с проверкой + local vps_data_ok=false local max_attempts=3 - while [ $attempt -le $max_attempts ]; do - echo -e "${CYAN}Попытка $attempt из $max_attempts:${NC}" - read -p "IP адрес или домен VPS: " VPS_HOST + 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 "" + + read -p "IP адрес или доменное имя VPS: " VPS_HOST read -p "Порт SSH (по умолчанию 22): " VPS_PORT VPS_PORT=${VPS_PORT:-22} - echo -e "${CYAN}Выберите пользователя:${NC}" - echo "1) root" - echo "2) Другой" - read -p "Выбор [1-2]: " USER_CHOICE - if [ "$USER_CHOICE" == "1" ]; then + + echo "" + echo -e "${CYAN}Выберите пользователя для подключения:${NC}" + echo "1) root (рекомендуется для полного доступа)" + echo "2) Другой пользователь" + read -p "Ваш выбор [1-2]: " USER_CHOICE + + if [ "$USER_CHOICE" = "1" ] || [ -z "$USER_CHOICE" ]; 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}" - attempt=$((attempt+1)) - continue + + # Проверка заполнения обязательных полей + 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 -e "${CYAN}Проверка данных:${NC}" - echo "VPS: $VPS_USER@$VPS_HOST:$VPS_PORT" - read -p "Верно? (y/n): " CONFIRM - if [[ $CONFIRM =~ ^[Yy]$ ]]; then + + 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 "" fi - attempt=$((attempt+1)) done - - if [ $attempt -gt $max_attempts ]; then - echo -e "${RED}Превышено количество попыток. Выход.${NC}" + + if [ "$vps_data_ok" = false ]; then + echo -e "${RED}Не удалось получить корректные данные VPS. Выход.${NC}" exit 1 fi - - # Генерация ключа - if [ ! -f /root/.ssh/id_ed25519 ]; then - ssh-keygen -t ed25519 -N "" -f /root/.ssh/id_ed25519 -q - log_message "SSH ключ сгенерирован." + + # Проверка подключения + 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 fi - - # Конфиг SSH - cat > /root/.ssh/config << EOF + + # Генерация 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 Host tunnel-vps HostName $VPS_HOST Port $VPS_PORT User $VPS_USER - IdentityFile ~/.ssh/id_ed25519 - StrictHostKeyChecking accept-new + IdentityFile ~/.ssh/id_rsa + StrictHostKeyChecking no + UserKnownHostsFile /dev/null ServerAliveInterval 30 ServerAliveCountMax 3 + ConnectTimeout 30 + TCPKeepAlive yes + IdentitiesOnly yes ExitOnForwardFailure yes -EOF + # Увеличенные настройки для локальной сети + 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 + + # Замена переменных в конфиге + 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 - - # Копирование ключа - read -s -p "Пароль для $VPS_USER@$VPS_HOST (Enter для пропуска): " VPS_PASSWORD + + # Настройка 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 echo - 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 "Ключ скопирован." + + 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 else - echo -e "${YELLOW}Скопируйте вручную: cat /root/.ssh/id_ed25519.pub${NC}" - read -p "Нажмите Enter после добавления на VPS..." + echo -e "${YELLOW}Пароль не введен, пропускаю автоматическое копирование ключа${NC}" fi - - # Тест подключения - if ssh -o BatchMode=yes "$VPS_USER@$VPS_HOST" -p "$VPS_PORT" echo "OK"; then - log_message "Подключение успешно." + + # Альтернативный метод копирования ключа + 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 | tee -a "$LOG_FILE"; then + log_message "Тестовое подключение прошло успешно!" "$GREEN" + echo -e "${GREEN}✓ SSH ключ настроен корректно${NC}" else - echo -e "${RED}Подключение не удалось. Проверьте настройки.${NC}" - exit 1 + 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 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 << EOF + cat > /etc/ssh_tunnel/vps_settings.conf << EOFSETTINGS +# Настройки VPS для автономных туннелей VPS_HOST="$VPS_HOST" VPS_PORT="$VPS_PORT" VPS_USER="$VPS_USER" -EOF +CONFIGURED_ON="$(date '+%Y-%m-%d %H:%M:%S')" +EOFSETTINGS + chmod 600 /etc/ssh_tunnel/vps_settings.conf + log_message "Настройки SSH сохранены в /etc/ssh_tunnel/vps_settings.conf" "$GREEN" + + # Экспорт переменных для других функций + export VPS_HOST + export VPS_PORT + export VPS_USER + return 0 } -# Установка основного скрипта +# Установка основного скрипта управления install_main_script() { - log_message "Установка менеджера..." - mkdir -p /opt/ssh_tunnel_manager /var/log/ssh_tunnel - - cat > /opt/ssh_tunnel_manager/manager.sh << 'EOF' + 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 + + # Создание основного скрипта менеджера + cat > /opt/ssh_tunnel_manager/manager.sh << 'EOFMGR' #!/bin/bash -# Автономный менеджер SSH туннелей -# Использование: tunnel-manager [команда] +# Основной скрипт менеджера SSH туннелей +# Версия 4.0 - Стабильное меню -source /etc/ssh_tunnel/vps_settings.conf 2>/dev/null || { - echo "Настройки VPS не найдены!" - exit 1 -} +# Конфигурация +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' -CONFIG_DIR="/etc/ssh_tunnel" -LOG_DIR="/var/log/ssh_tunnel" +# Глобальные переменные +VPS_HOST="" +VPS_PORT="22" +VPS_USER="" -list_tunnels() { - echo -e "${CYAN}Активные туннели:${NC}" - systemctl list-units --type=service --all | grep ssh-tunnel || echo "Нет туннелей." +# Загрузка настроек 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 } -create_tunnel() { - read -p "Локальный порт: " LOCAL_PORT - read -p "Удаленный порт на VPS: " REMOTE_PORT - if [ -z "$LOCAL_PORT" ] || [ -z "$REMOTE_PORT" ]; then - echo -e "${RED}Поля обязательны.${NC}" - exit 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 +} - TUNNEL_ID="tunnel_${REMOTE_PORT}" - SERVICE_FILE="/etc/systemd/system/ssh-${TUNNEL_ID}.service" +# Очистка входного буфера +clear_input_buffer() { + while read -t 0.1 -n 1000 discard; do :; done +} - cat > "$SERVICE_FILE" << EOSERVICE +# Функция проверки подключения +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.target +Description=SSH Tunnel: $TUNNEL_ID +After=network-online.target +Wants=network-online.target [Service] -User=root -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} +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=5 +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 -EOSERVICE - +SERVICETUN + systemctl daemon-reload - systemctl enable ssh-${TUNNEL_ID} - systemctl start ssh-${TUNNEL_ID} - echo -e "${GREEN}Туннель создан.${NC}" + 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 } -case "$1" in - list) list_tunnels ;; - create) create_tunnel ;; - *) echo "Использование: tunnel-manager [list|create]" ;; -esac -EOF - chmod +x /opt/ssh_tunnel_manager/manager.sh - ln -sf /opt/ssh_tunnel_manager/manager.sh /usr/local/bin/tunnel-manager -} - -# Настройка монитора -setup_monitor() { - cat > /etc/systemd/system/tunnel-monitor.service << EOF +# Быстрый 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 туннелей -After=network.target +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}" + 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 [[ "${BASH_SOURCE[0]}" == "${0}" ]]; 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 + + # Делаем скрипт исполняемым + 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 +} + +# Настройка systemd служб +setup_systemd_services() { + log_message "Настройка systemd служб для автономной работы..." "$CYAN" + + # Основная служба мониторинга + cat > /etc/systemd/system/tunnel-monitor.service << 'EOFSERVICE' +[Unit] +Description=Мониторинг и восстановление SSH туннелей +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 -EOF - - cat > /opt/ssh_tunnel_manager/monitor.sh << 'EOF' +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 - # Проверка и перезапуск туннелей - systemctl list-units --type=service | grep ssh-tunnel | while read service; do - if ! systemctl is-active $service; then - systemctl start $service + # Проверяем все конфигурации (кроме 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 -EOF +EOFMONITOR + chmod +x /opt/ssh_tunnel_manager/monitor.sh + + # Создание таймера для периодической проверки + cat > /etc/systemd/system/tunnel-check.timer << 'EOFTIMER' +[Unit] +Description=Периодическая проверка SSH туннелей - systemctl daemon-reload - systemctl enable tunnel-monitor - systemctl start tunnel-monitor +[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() { - 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 + 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 туннеля -After=network.target +Description=Пример SSH туннеля (22->10022) +After=network-online.target [Service] -User=root -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} +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=5 +RestartSec=10 +User=root + +StandardOutput=append:/var/log/ssh_tunnel/example_ssh.log +StandardError=append:/var/log/ssh_tunnel/example_ssh.log [Install] WantedBy=multi-user.target -EOSERVICE - - systemctl daemon-reload - systemctl enable ssh-tunnel-${TUNNEL_ID} - systemctl start ssh-tunnel-${TUNNEL_ID} - echo -e "${GREEN}Пример туннеля создан (22 -> 10022).${NC}" +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 + else + echo -e "${YELLOW}Не удалось создать пример туннеля: настройки VPS не найдены${NC}" + fi + return 0 } -# Завершение +# Завершение установки finish_installation() { - echo -e "${GREEN}Установка завершена!${NC}" - echo "Запустите tunnel-manager для управления." - log_message "Установка завершена." + 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" + 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 } -install_dependencies -setup_ssh -install_main_script -setup_monitor -create_example_tunnel -finish_installation \ No newline at end of file +# Главная функция установки +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