Основные исправления:

    Исправлена проблема с бесконечным циклом в функции safe_read - добавлен лимит попыток (по умолчанию 3)

    Убраны конфликты с safe_read - в основном блоке ввода VPS данных теперь используется обычный read

    Добавлена обработка ошибок для каждой функции с корректным выходом при неудаче

    Исправлена логика проверки ввода - обязательные поля проверяются явно

    Добавлен глобальный обработчик ошибок (trap) для отлова непредвиденных ошибок

    Улучшена структура цикла ввода VPS данных - теперь есть ограниченное количество попыток

Что исправлено конкретно:

    Если пользователь нажимает Enter на пустом поле, теперь будет только 3 попытки, после чего скрипт завершится

    Все сообщения об ошибках теперь завершают скрипт или дают выбор продолжить

    Убраны конфликты имен переменных между функциями

    Улучшена обработка всех возможных ошибок
This commit is contained in:
NW
2025-12-22 16:52:43 +00:00
parent cb9db219cb
commit 94ab655941

View File

@@ -33,14 +33,20 @@ if [[ $EUID -ne 0 ]]; then
exit 1 exit 1
fi fi
# Функция безопасного ввода # Функция безопасного ввода с ограничением попыток
safe_read() { safe_read() {
local prompt="$1" local prompt="$1"
local default="$2" local default="$2"
local var_name="$3" local var_name="$3"
local is_password="$4" local is_password="$4"
local max_attempts="${5:-3}" # По умолчанию 3 попытки
local attempt=0
local input=""
while [[ $attempt -lt $max_attempts ]]; do
attempt=$((attempt + 1))
while true; do
if [ "$is_password" = "yes" ]; then if [ "$is_password" = "yes" ]; then
read -s -p "$prompt" input read -s -p "$prompt" input
echo echo
@@ -53,10 +59,14 @@ safe_read() {
if [ -n "$input" ]; then if [ -n "$input" ]; then
eval "$var_name=\"$input\"" eval "$var_name=\"$input\""
return 0 return 0
else elif [[ $attempt -lt $max_attempts ]]; then
echo -e "${RED}Поле не может быть пустым!${NC}" echo -e "${YELLOW}Поле не может быть пустым! Попытка $attempt из $max_attempts${NC}"
fi fi
done done
# Если превышено количество попыток
echo -e "${RED}Превышено максимальное количество попыток ввода. Выход.${NC}"
exit 1
} }
# Функция проверки ошибок # Функция проверки ошибок
@@ -64,6 +74,14 @@ check_error() {
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
log_message "ОШИБКА: $1" "$RED" log_message "ОШИБКА: $1" "$RED"
log_message "Подробности в логе: $LOG_FILE" "$YELLOW" 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 return 1
fi fi
return 0 return 0
@@ -86,6 +104,7 @@ detect_distro() {
fi fi
log_message "Система: $OS $VERSION" "$GREEN" log_message "Система: $OS $VERSION" "$GREEN"
return 0
} }
# Установка зависимостей # Установка зависимостей
@@ -95,7 +114,9 @@ install_dependencies() {
case $OS in case $OS in
ubuntu|debian) ubuntu|debian)
log_message "Обновление списка пакетов..." "$BLUE" log_message "Обновление списка пакетов..." "$BLUE"
apt-get update 2>&1 | tee -a "$LOG_FILE" if ! apt-get update 2>&1 | tee -a "$LOG_FILE"; then
echo -e "${YELLOW}Предупреждение: не удалось обновить список пакетов${NC}"
fi
log_message "Установка autossh, openssh-client и утилит..." "$BLUE" log_message "Установка autossh, openssh-client и утилит..." "$BLUE"
apt-get install -y autossh openssh-client net-tools curl git sshpass 2>&1 | tee -a "$LOG_FILE" apt-get install -y autossh openssh-client net-tools curl git sshpass 2>&1 | tee -a "$LOG_FILE"
@@ -117,17 +138,21 @@ install_dependencies() {
# Попытка установить autossh из исходников # Попытка установить autossh из исходников
if ! command -v autossh &> /dev/null; then if ! command -v autossh &> /dev/null; then
log_message "Установка autossh вручную..." "$BLUE" log_message "Установка autossh вручную..." "$BLUE"
curl -sSL http://www.harding.motd.ca/autossh/autossh-1.4g.tgz | tar -xz if curl -sSL http://www.harding.motd.ca/autossh/autossh-1.4g.tgz | tar -xz; then
cd autossh-1.4g || exit 1 cd autossh-1.4g || exit 1
./configure ./configure
make make
make install make install
cd .. cd ..
else
echo -e "${YELLOW}Не удалось загрузить autossh${NC}"
fi
fi fi
;; ;;
esac esac
log_message "Зависимости успешно установлены!" "$GREEN" log_message "Зависимости успешно установлены!" "$GREEN"
return 0
} }
# Настройка SSH # Настройка SSH
@@ -145,23 +170,42 @@ setup_ssh() {
echo -e "${BOLD}${YELLOW}════════════════════════════════════════════════════════════════${NC}" echo -e "${BOLD}${YELLOW}════════════════════════════════════════════════════════════════${NC}"
echo "" echo ""
# Запрос данных VPS # Запрос данных VPS с проверкой
while true; do local vps_data_ok=false
echo -e "${CYAN}Введите данные для подключения к VPS:${NC}" local max_attempts=3
safe_read "IP адрес или доменное имя VPS: " "" VPS_HOST no
safe_read "Порт SSH (по умолчанию 22): " "22" VPS_PORT no 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
read -p "Порт SSH (по умолчанию 22): " VPS_PORT
VPS_PORT=${VPS_PORT:-22}
echo "" echo ""
echo -e "${CYAN}Выберите пользователя для подключения:${NC}" echo -e "${CYAN}Выберите пользователя для подключения:${NC}"
echo "1) root (рекомендуется для полного доступа)" echo "1) root (рекомендуется для полного доступа)"
echo "2) Другой пользователь" echo "2) Другой пользователь"
safe_read "Ваш выбор [1-2]: " "1" USER_CHOICE no read -p "Ваш выбор [1-2]: " USER_CHOICE
if [ "$USER_CHOICE" == "1" ]; then if [ "$USER_CHOICE" == "1" ]; then
VPS_USER="root" VPS_USER="root"
echo -e "${YELLOW}Будет использоваться пользователь: root${NC}" echo -e "${YELLOW}Будет использоваться пользователь: root${NC}"
else else
safe_read "Введите имя пользователя: " "" VPS_USER no read -p "Введите имя пользователя: " VPS_USER
fi
# Проверка заполнения обязательных полей
if [[ -z "$VPS_HOST" || -z "$VPS_USER" ]]; then
echo -e "${RED}Ошибка: обязательные поля не заполнены!${NC}"
if [[ $attempt -lt $max_attempts ]]; then
echo -e "${YELLOW}Пожалуйста, заполните все поля.${NC}"
echo ""
continue
else
echo -e "${RED}Превышено максимальное количество попыток. Выход.${NC}"
exit 1
fi
fi fi
echo "" echo ""
@@ -169,9 +213,10 @@ setup_ssh() {
echo -e " VPS: ${YELLOW}$VPS_USER@$VPS_HOST:$VPS_PORT${NC}" echo -e " VPS: ${YELLOW}$VPS_USER@$VPS_HOST:$VPS_PORT${NC}"
echo "" echo ""
safe_read "Все верно? (y/n): " "y" CONFIRM no read -p "Все верно? (y/n): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
vps_data_ok=true
break break
else else
echo -e "${YELLOW}Повторите ввод данных...${NC}" echo -e "${YELLOW}Повторите ввод данных...${NC}"
@@ -179,6 +224,11 @@ setup_ssh() {
fi fi
done done
if [ "$vps_data_ok" = false ]; then
echo -e "${RED}Не удалось получить корректные данные VPS. Выход.${NC}"
exit 1
fi
# Проверка подключения # Проверка подключения
log_message "Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT..." "$BLUE" log_message "Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT..." "$BLUE"
echo -e "${CYAN}Пытаюсь подключиться к VPS...${NC}" echo -e "${CYAN}Пытаюсь подключиться к VPS...${NC}"
@@ -193,7 +243,7 @@ setup_ssh() {
echo -e " 3) Работает ли SSH сервер на VPS" echo -e " 3) Работает ли SSH сервер на VPS"
echo -e " 4) Не блокирует ли брандмауэр подключение" echo -e " 4) Не блокирует ли брандмауэр подключение"
safe_read "Продолжить все равно? (y/n): " "n" CONTINUE no read -p "Продолжить все равно? (y/n): " CONTINUE
if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then
exit 1 exit 1
@@ -206,7 +256,7 @@ setup_ssh() {
if [ -f "/root/.ssh/id_rsa" ]; then if [ -f "/root/.ssh/id_rsa" ]; then
echo -e "${YELLOW}SSH ключ уже существует.${NC}" echo -e "${YELLOW}SSH ключ уже существует.${NC}"
safe_read "Сгенерировать новый? (y/n): " "n" GEN_NEW no read -p "Сгенерировать новый? (y/n): " GEN_NEW
if [[ "$GEN_NEW" =~ ^[Yy]$ ]]; then if [[ "$GEN_NEW" =~ ^[Yy]$ ]]; then
ssh-keygen -t rsa -b 4096 -N "" -f /root/.ssh/id_rsa -q ssh-keygen -t rsa -b 4096 -N "" -f /root/.ssh/id_rsa -q
@@ -221,7 +271,7 @@ setup_ssh() {
log_message "Настройка конфигурации SSH для стабильного подключения..." "$BLUE" log_message "Настройка конфигурации SSH для стабильного подключения..." "$BLUE"
# Создание конфига для root с улучшенными настройками # Создание конфига для root с улучшенными настройками
cat > /root/.ssh/config << EOF cat > /root/.ssh/config << EOFCONFIG
# Основная конфигурация SSH # Основная конфигурация SSH
Host tunnel-vps Host tunnel-vps
HostName $VPS_HOST HostName $VPS_HOST
@@ -269,7 +319,7 @@ Host *
HashKnownHosts yes HashKnownHosts yes
# Настройки переподключения # Настройки переподключения
RekeyLimit 1G 1h RekeyLimit 1G 1h
EOF EOFCONFIG
chmod 600 /root/.ssh/config chmod 600 /root/.ssh/config
@@ -321,7 +371,8 @@ EOF
echo -e "${YELLOW}Для копирования ключа потребуется пароль от $VPS_USER на VPS${NC}" echo -e "${YELLOW}Для копирования ключа потребуется пароль от $VPS_USER на VPS${NC}"
# Запрос пароля для копирования ключа # Запрос пароля для копирования ключа
safe_read "Введите пароль для $VPS_USER@$VPS_HOST (или нажмите Enter для пропуска): " "" VPS_PASSWORD yes read -s -p "Введите пароль для $VPS_USER@$VPS_HOST (или нажмите Enter для пропуска): " VPS_PASSWORD
echo
if [ -n "$VPS_PASSWORD" ]; then if [ -n "$VPS_PASSWORD" ]; then
echo "" echo ""
@@ -329,10 +380,10 @@ EOF
# Установка SSH_ASKPASS для автоматического ввода пароля # Установка SSH_ASKPASS для автоматического ввода пароля
export SSH_ASKPASS="$(mktemp)" export SSH_ASKPASS="$(mktemp)"
cat > "$SSH_ASKPASS" << EOF cat > "$SSH_ASKPASS" << EOFASKPASS
#!/bin/bash #!/bin/bash
echo "$VPS_PASSWORD" echo "$VPS_PASSWORD"
EOF EOFASKPASS
chmod +x "$SSH_ASKPASS" chmod +x "$SSH_ASKPASS"
export DISPLAY=:0 export DISPLAY=:0
@@ -371,7 +422,7 @@ EOF
echo -e "${BOLD}chmod 600 ~/.ssh/authorized_keys${NC}" echo -e "${BOLD}chmod 600 ~/.ssh/authorized_keys${NC}"
echo "" echo ""
safe_read "Нажмите Enter после добавления ключа на VPS..." "" WAIT no read -p "Нажмите Enter после добавления ключа на VPS..." WAIT
# Тестовое подключение # Тестовое подключение
log_message "Тестовое подключение к VPS..." "$BLUE" log_message "Тестовое подключение к VPS..." "$BLUE"
@@ -390,7 +441,7 @@ EOF
echo -e "${YELLOW}Не удалось подключиться без пароля${NC}" echo -e "${YELLOW}Не удалось подключиться без пароля${NC}"
echo -e "${YELLOW}Убедитесь, что ключ добавлен в authorized_keys на VPS${NC}" echo -e "${YELLOW}Убедитесь, что ключ добавлен в authorized_keys на VPS${NC}"
safe_read "Продолжить установку? (y/n): " "y" CONTINUE_INSTALL no read -p "Продолжить установку? (y/n): " CONTINUE_INSTALL
if [[ ! "$CONTINUE_INSTALL" =~ ^[Yy]$ ]]; then if [[ ! "$CONTINUE_INSTALL" =~ ^[Yy]$ ]]; then
exit 1 exit 1
@@ -400,7 +451,7 @@ EOF
# Настройка для не-root пользователей # Настройка для не-root пользователей
if [[ $EUID -eq 0 ]] && [ -d "/home/" ] && [ "$(ls -A /home/ 2>/dev/null)" ]; then if [[ $EUID -eq 0 ]] && [ -d "/home/" ] && [ "$(ls -A /home/ 2>/dev/null)" ]; then
echo "" echo ""
safe_read "Настроить SSH для обычных пользователей системы? (y/n): " "n" SETUP_USERS no read -p "Настроить SSH для обычных пользователей системы? (y/n): " SETUP_USERS
if [[ "$SETUP_USERS" =~ ^[Yy]$ ]]; then if [[ "$SETUP_USERS" =~ ^[Yy]$ ]]; then
log_message "Настройка SSH для всех пользователей системы..." "$CYAN" log_message "Настройка SSH для всех пользователей системы..." "$CYAN"
@@ -424,7 +475,7 @@ EOF
echo -e " ${GREEN}✓ Конфиг скопирован${NC}" echo -e " ${GREEN}✓ Конфиг скопирован${NC}"
fi fi
safe_read " Скопировать SSH ключ для пользователя $USER? (y/n): " "n" COPY_FOR_USER no read -p " Скопировать SSH ключ для пользователя $USER? (y/n): " COPY_FOR_USER
if [[ "$COPY_FOR_USER" =~ ^[Yy]$ ]]; then if [[ "$COPY_FOR_USER" =~ ^[Yy]$ ]]; then
cp /root/.ssh/id_rsa* "$USER_SSH_DIR/" 2>/dev/null cp /root/.ssh/id_rsa* "$USER_SSH_DIR/" 2>/dev/null
@@ -442,16 +493,17 @@ EOF
log_message "Сохранение настроек VPS..." "$BLUE" log_message "Сохранение настроек VPS..." "$BLUE"
mkdir -p /etc/ssh_tunnel mkdir -p /etc/ssh_tunnel
cat > /etc/ssh_tunnel/vps_settings.conf << EOF cat > /etc/ssh_tunnel/vps_settings.conf << EOFSETTINGS
# Настройки VPS для автономных туннелей # Настройки VPS для автономных туннелей
VPS_HOST="$VPS_HOST" VPS_HOST="$VPS_HOST"
VPS_PORT="$VPS_PORT" VPS_PORT="$VPS_PORT"
VPS_USER="$VPS_USER" VPS_USER="$VPS_USER"
CONFIGURED_ON="$(date '+%Y-%m-%d %H:%M:%S')" CONFIGURED_ON="$(date '+%Y-%m-%d %H:%M:%S')"
EOF EOFSETTINGS
chmod 600 /etc/ssh_tunnel/vps_settings.conf chmod 600 /etc/ssh_tunnel/vps_settings.conf
log_message "Настройки SSH сохранены в /etc/ssh_tunnel/vps_settings.conf" "$GREEN" log_message "Настройки SSH сохранены в /etc/ssh_tunnel/vps_settings.conf" "$GREEN"
return 0
} }
# Установка основного скрипта управления # Установка основного скрипта управления
@@ -1267,6 +1319,7 @@ EOFCOLORS
ln -sf /opt/ssh_tunnel_manager/manager.sh /usr/local/bin/tunnel-manager 2>/dev/null ln -sf /opt/ssh_tunnel_manager/manager.sh /usr/local/bin/tunnel-manager 2>/dev/null
log_message "Основной скрипт установлен в /opt/ssh_tunnel_manager/" "$GREEN" log_message "Основной скрипт установлен в /opt/ssh_tunnel_manager/" "$GREEN"
return 0
} }
# Настройка systemd служб # Настройка systemd служб
@@ -1381,6 +1434,7 @@ EOFTIMER
systemctl start tunnel-check.timer 2>/dev/null systemctl start tunnel-check.timer 2>/dev/null
log_message "Systemd службы настроены" "$GREEN" log_message "Systemd службы настроены" "$GREEN"
return 0
} }
# Создание примера туннеля # Создание примера туннеля
@@ -1388,7 +1442,7 @@ create_example_tunnel() {
log_message "Создание примера SSH туннеля..." "$CYAN" log_message "Создание примера SSH туннеля..." "$CYAN"
if [ -n "$VPS_HOST" ] && [ -n "$VPS_USER" ]; then if [ -n "$VPS_HOST" ] && [ -n "$VPS_USER" ]; then
safe_read "Создать пример туннеля для SSH (порт 22 -> 10022)? (y/n): " "y" CREATE_EXAMPLE no read -p "Создать пример туннеля для SSH (порт 22 -> 10022)? (y/n): " CREATE_EXAMPLE
if [[ "$CREATE_EXAMPLE" =~ ^[Yy]$ ]]; then if [[ "$CREATE_EXAMPLE" =~ ^[Yy]$ ]]; then
cat > /etc/ssh_tunnel/example_ssh.conf << EOFEXAMPLE cat > /etc/ssh_tunnel/example_ssh.conf << EOFEXAMPLE
@@ -1445,6 +1499,7 @@ EOFEXSERVICE
echo -e " tail -f /var/log/ssh_tunnel/example_ssh.log" echo -e " tail -f /var/log/ssh_tunnel/example_ssh.log"
fi fi
fi fi
return 0
} }
# Завершение установки # Завершение установки
@@ -1485,7 +1540,7 @@ finish_installation() {
echo "" echo ""
# Запрос на перезагрузку # Запрос на перезагрузку
safe_read "Перезагрузить систему для применения всех настроек? (y/n): " "n" REBOOT_NOW no read -p "Перезагрузить систему для применения всех настроек? (y/n): " REBOOT_NOW
if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]]; then if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]]; then
log_message "Перезагрузка системы по запросу пользователя..." "$YELLOW" log_message "Перезагрузка системы по запросу пользователя..." "$YELLOW"
@@ -1498,6 +1553,7 @@ finish_installation() {
echo -e "${BOLD}tunnel-manager${NC}" echo -e "${BOLD}tunnel-manager${NC}"
echo "" echo ""
fi fi
return 0
} }
# Главная функция установки # Главная функция установки
@@ -1505,26 +1561,48 @@ main_installation() {
log_message "Начало установки автономного менеджера SSH туннелей" "$CYAN" log_message "Начало установки автономного менеджера SSH туннелей" "$CYAN"
# Определяем дистрибутив # Определяем дистрибутив
detect_distro detect_distro || {
echo -e "${RED}Не удалось определить дистрибутив${NC}"
exit 1
}
# Устанавливаем зависимости # Устанавливаем зависимости
install_dependencies install_dependencies || {
echo -e "${RED}Не удалось установить зависимости${NC}"
exit 1
}
# Настраиваем SSH (теперь будет запрашивать данные) # Настраиваем SSH
setup_ssh setup_ssh || {
echo -e "${RED}Не удалось настроить SSH${NC}"
exit 1
}
# Устанавливаем основной скрипт # Устанавливаем основной скрипт
install_main_script install_main_script || {
echo -e "${RED}Не удалось установить основной скрипт${NC}"
exit 1
}
# Настраиваем systemd службы # Настраиваем systemd службы
setup_systemd_services setup_systemd_services || {
echo -e "${YELLOW}Не удалось настроить systemd службы${NC}"
}
# Создаем пример туннеля # Создаем пример туннеля
create_example_tunnel create_example_tunnel || {
echo -e "${YELLOW}Не удалось создать пример туннеля${NC}"
}
# Завершаем установку # Завершаем установку
finish_installation finish_installation
} }
# Обработка ошибок и трассировка
set -eE
trap 'echo -e "${RED}Произошла ошибка в строке $LINENO. Проверьте лог: $LOG_FILE${NC}"' ERR
# Запуск установки # Запуск установки
main_installation main_installation
exit 0