фикс: v1.3.9 - переход на нативную авторизацию Nginx (Basic Auth) для стабильности
This commit is contained in:
parent
0c7180e52d
commit
e4762d02cd
90
rproxy
90
rproxy
|
|
@ -3,7 +3,7 @@
|
||||||
# Публикация локальных сервисов через SSH-туннели + nginx на VPS
|
# Публикация локальных сервисов через SSH-туннели + nginx на VPS
|
||||||
# http://5.104.75.50:3000/Petro1990/rProxy
|
# http://5.104.75.50:3000/Petro1990/rProxy
|
||||||
|
|
||||||
VERSION="1.3.8"
|
VERSION="1.3.9"
|
||||||
CONF_DIR="/opt/etc/rproxy"
|
CONF_DIR="/opt/etc/rproxy"
|
||||||
CONF_FILE="$CONF_DIR/rproxy.conf"
|
CONF_FILE="$CONF_DIR/rproxy.conf"
|
||||||
SERVICES_DIR="$CONF_DIR/services"
|
SERVICES_DIR="$CONF_DIR/services"
|
||||||
|
|
@ -194,15 +194,21 @@ get_router_ip() {
|
||||||
}
|
}
|
||||||
|
|
||||||
enable_router_basic_auth() {
|
enable_router_basic_auth() {
|
||||||
msg "Настраиваю роутер на использование Basic Auth для совместимости..."
|
# Функция оставлена для обратной совместимости, но более не требуется для v1.3.9
|
||||||
# Для новых версий KeeneticOS
|
return 0
|
||||||
ndmq -p "web-server auth basic" >/dev/null 2>&1
|
}
|
||||||
# Для старых версий или альтернативных API
|
|
||||||
ndmq -p "ip http auth basic" >/dev/null 2>&1
|
gen_htpasswd() {
|
||||||
# Принудительно задаем realm
|
local user="$1"
|
||||||
ndmq -p "web-server realm Keenetic" >/dev/null 2>&1
|
local pass="$2"
|
||||||
# ОЧЕНЬ ВАЖНО: Сохраняем конфигурацию
|
# Пытаемся использовать openssl если он есть в Entware
|
||||||
ndmq -p "system configuration save" >/dev/null 2>&1
|
if command -v openssl >/dev/null 2>&1; then
|
||||||
|
local hash=$(openssl passwd -apr1 "$pass")
|
||||||
|
echo "$user:$hash"
|
||||||
|
else
|
||||||
|
# Запасной вариант если openssl нет (обычный текст, Nginx его понимает)
|
||||||
|
echo "$user:$pass"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
next_free_ext_port() {
|
next_free_ext_port() {
|
||||||
|
|
@ -502,12 +508,18 @@ do_add_interactive() {
|
||||||
printf " ${BOLD}Туннель:${NC} порт $tunnel_port\n"
|
printf " ${BOLD}Туннель:${NC} порт $tunnel_port\n"
|
||||||
[ -n "$domain" ] && printf " ${BOLD}Домен:${NC} $domain\n"
|
[ -n "$domain" ] && printf " ${BOLD}Домен:${NC} $domain\n"
|
||||||
printf " ${BOLD}Внешний порт:${NC} $ext_port\n"
|
printf " ${BOLD}Внешний порт:${NC} $ext_port\n"
|
||||||
prompt "Защитить сервис паролем от роутера? (д/н) [н]: "
|
prompt "Защитить сервис паролем? (д/н) [н]: "
|
||||||
local use_ndm_auth="no"
|
local use_ndm_auth="no"
|
||||||
|
local htpasswd_line=""
|
||||||
case "$REPLY" in
|
case "$REPLY" in
|
||||||
д|Д|y|Y|да|yes)
|
д|Д|y|Y|да|yes)
|
||||||
use_ndm_auth="yes"
|
use_ndm_auth="yes"
|
||||||
enable_router_basic_auth
|
prompt "Введите имя пользователя [admin]: "
|
||||||
|
local user="${REPLY:-admin}"
|
||||||
|
prompt "Введите пароль для '$user' (можно от роутера): "
|
||||||
|
local pass="$REPLY"
|
||||||
|
[ -z "$pass" ] && { warn "Пароль не может быть пустым"; pause; return; }
|
||||||
|
htpasswd_line=$(gen_htpasswd "$user" "$pass")
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
@ -524,35 +536,10 @@ do_add_interactive() {
|
||||||
|
|
||||||
# Конфигурация авторизации
|
# Конфигурация авторизации
|
||||||
local auth_config=""
|
local auth_config=""
|
||||||
local router_ip="127.0.0.1"
|
|
||||||
if [ "$use_ndm_auth" = "yes" ]; then
|
if [ "$use_ndm_auth" = "yes" ]; then
|
||||||
router_ip=$(get_router_ip)
|
|
||||||
local auth_port=$((tunnel_port + 1))
|
|
||||||
auth_config="
|
auth_config="
|
||||||
location /rproxy_auth {
|
auth_basic \"Restricted Access\";
|
||||||
internal;
|
auth_basic_user_file /etc/nginx/rproxy_$name.htpasswd;
|
||||||
proxy_pass http://127.0.0.1:$auth_port/rci/system/hostname;
|
|
||||||
proxy_pass_request_body off;
|
|
||||||
proxy_set_header Content-Length \"\";
|
|
||||||
proxy_set_header Authorization \$http_authorization;
|
|
||||||
|
|
||||||
# Фикс для Keenetic RCI: принудительный 401 вместо 302 редиректа
|
|
||||||
proxy_set_header X-Requested-With XMLHttpRequest;
|
|
||||||
proxy_set_header X-NDM-Auth-Type Basic;
|
|
||||||
proxy_set_header Accept \"application/json\";
|
|
||||||
proxy_set_header Cookie \"\";
|
|
||||||
|
|
||||||
# Стелс-режим для авторизации (используем LAN IP роутера)
|
|
||||||
proxy_set_header Host \"$router_ip\";
|
|
||||||
proxy_set_header Origin \"http://$router_ip\";
|
|
||||||
proxy_set_header Referer \"http://$router_ip/\";
|
|
||||||
proxy_set_header X-NDM-Realm \"Keenetic\";
|
|
||||||
}
|
|
||||||
|
|
||||||
location @auth_required {
|
|
||||||
add_header WWW-Authenticate 'Basic realm=\"Keenetic\"' always;
|
|
||||||
return 401;
|
|
||||||
}
|
|
||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -563,7 +550,6 @@ do_add_interactive() {
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name "$domain";
|
server_name "$domain";
|
||||||
recursive_error_pages on;
|
|
||||||
|
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
proxy_request_buffering off;
|
proxy_request_buffering off;
|
||||||
|
|
@ -572,8 +558,7 @@ server {
|
||||||
proxy_busy_buffers_size 256k;
|
proxy_busy_buffers_size 256k;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
$( [ "$use_ndm_auth" = "yes" ] && echo "auth_request /rproxy_auth;" )
|
$auth_config
|
||||||
$( [ "$use_ndm_auth" = "yes" ] && echo "error_page 401 403 = @auth_required;" )
|
|
||||||
proxy_pass http://127.0.0.1:$tunnel_port;
|
proxy_pass http://127.0.0.1:$tunnel_port;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
proxy_set_header Upgrade \$http_upgrade;
|
||||||
|
|
@ -606,7 +591,6 @@ NGINXEOF
|
||||||
cat > "$tmp" << NGINXEOF
|
cat > "$tmp" << NGINXEOF
|
||||||
server {
|
server {
|
||||||
listen $ext_port;
|
listen $ext_port;
|
||||||
recursive_error_pages on;
|
|
||||||
|
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
proxy_request_buffering off;
|
proxy_request_buffering off;
|
||||||
|
|
@ -615,8 +599,7 @@ server {
|
||||||
proxy_busy_buffers_size 256k;
|
proxy_busy_buffers_size 256k;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
$( [ "$use_ndm_auth" = "yes" ] && echo "auth_request /rproxy_auth;" )
|
$auth_config
|
||||||
$( [ "$use_ndm_auth" = "yes" ] && echo "error_page 401 403 = @auth_required;" )
|
|
||||||
proxy_pass http://127.0.0.1:$tunnel_port;
|
proxy_pass http://127.0.0.1:$tunnel_port;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade \$http_upgrade;
|
proxy_set_header Upgrade \$http_upgrade;
|
||||||
|
|
@ -648,6 +631,15 @@ NGINXEOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Деплой
|
# Деплой
|
||||||
|
# Деплой htpasswd если нужно
|
||||||
|
if [ "$use_ndm_auth" = "yes" ]; then
|
||||||
|
local ht_tmp="/tmp/rproxy_$name.htpasswd"
|
||||||
|
echo "$htpasswd_line" > "$ht_tmp"
|
||||||
|
scp_cmd "$ht_tmp" "$VPS_USER@$VPS_HOST:/etc/nginx/rproxy_$name.htpasswd"
|
||||||
|
rm -f "$ht_tmp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Деплой nginx
|
||||||
scp_cmd "$tmp" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_$name.conf" || { err "Ошибка деплоя nginx"; rm -f "$tmp"; pause; return; }
|
scp_cmd "$tmp" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_$name.conf" || { err "Ошибка деплоя nginx"; rm -f "$tmp"; pause; return; }
|
||||||
ssh_cmd "nginx -t && systemctl reload nginx" >/dev/null 2>&1
|
ssh_cmd "nginx -t && systemctl reload nginx" >/dev/null 2>&1
|
||||||
|
|
||||||
|
|
@ -668,7 +660,7 @@ SVC_EXT_PORT="$ext_port"
|
||||||
SVC_DOMAIN="$domain"
|
SVC_DOMAIN="$domain"
|
||||||
SVC_SSL="$use_ssl"
|
SVC_SSL="$use_ssl"
|
||||||
SVC_NDM_AUTH="$use_ndm_auth"
|
SVC_NDM_AUTH="$use_ndm_auth"
|
||||||
SVC_ROUTER_IP="$router_ip"
|
SVC_HTPASSWD=\"$htpasswd_line\"
|
||||||
SVC_ENABLED="yes"
|
SVC_ENABLED="yes"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
@ -711,6 +703,10 @@ do_edit_interactive() {
|
||||||
if is_running "$name"; then
|
if is_running "$name"; then
|
||||||
do_stop_service "$name"
|
do_stop_service "$name"
|
||||||
sleep 1
|
sleep 1
|
||||||
|
# Обновление htpasswd на VPS если включено
|
||||||
|
if [ "$SVC_NDM_AUTH" = "yes" ]; then
|
||||||
|
ssh_cmd "echo '$SVC_HTPASSWD' > /etc/nginx/rproxy_$name.htpasswd"
|
||||||
|
fi
|
||||||
do_start_service "$name"
|
do_start_service "$name"
|
||||||
else
|
else
|
||||||
msg "Сервис был остановлен. Настройки вступят в силу при следующем запуске."
|
msg "Сервис был остановлен. Настройки вступят в силу при следующем запуске."
|
||||||
|
|
@ -1099,11 +1095,9 @@ do_start_service() {
|
||||||
|
|
||||||
msg "Синхронизация с VPS (очистка портов)..."
|
msg "Синхронизация с VPS (очистка портов)..."
|
||||||
ssh_cmd "fuser -k $SVC_TUNNEL_PORT/tcp >/dev/null 2>&1 || true"
|
ssh_cmd "fuser -k $SVC_TUNNEL_PORT/tcp >/dev/null 2>&1 || true"
|
||||||
[ "$SVC_NDM_AUTH" = "yes" ] && ssh_cmd "fuser -k $((SVC_TUNNEL_PORT+1))/tcp >/dev/null 2>&1 || true"
|
|
||||||
|
|
||||||
local ssh_opts="-o StrictHostKeyChecking=no -o ServerAliveInterval=10 -o ServerAliveCountMax=3 -o ConnectTimeout=10 -o ExitOnForwardFailure=yes"
|
local ssh_opts="-o StrictHostKeyChecking=no -o ServerAliveInterval=10 -o ServerAliveCountMax=3 -o ConnectTimeout=10 -o ExitOnForwardFailure=yes"
|
||||||
local tunnel_args="-R 0.0.0.0:$SVC_TUNNEL_PORT:$SVC_TARGET_HOST:$SVC_TARGET_PORT"
|
local tunnel_args="-R 0.0.0.0:$SVC_TUNNEL_PORT:$SVC_TARGET_HOST:$SVC_TARGET_PORT"
|
||||||
[ "$SVC_NDM_AUTH" = "yes" ] && tunnel_args="$tunnel_args -R 0.0.0.0:$((SVC_TUNNEL_PORT+1)):${SVC_ROUTER_IP:-127.0.0.1}:80"
|
|
||||||
|
|
||||||
if [ "$VPS_AUTH" = "password" ]; then
|
if [ "$VPS_AUTH" = "password" ]; then
|
||||||
AUTOSSH_GATETIME=0 sshpass -p "$VPS_PASS" autossh -M 0 -f -N \
|
AUTOSSH_GATETIME=0 sshpass -p "$VPS_PASS" autossh -M 0 -f -N \
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# test_keenetic_auth.sh
|
||||||
|
# Использование: ./test_keenetic_auth.sh [USER] [PASS] [IP]
|
||||||
|
|
||||||
|
USER="${1:-admin}"
|
||||||
|
PASS="${2:-12985654}"
|
||||||
|
IP="${3:-192.168.60.1}"
|
||||||
|
AUTH_BASE64=$(echo -n "$USER:$PASS" | base64)
|
||||||
|
|
||||||
|
echo "=== Диагностика авторизации Keenetic RCI ($IP) ==="
|
||||||
|
echo "Пользователь: $USER"
|
||||||
|
|
||||||
|
test_request() {
|
||||||
|
local name="$1"
|
||||||
|
local port="$2"
|
||||||
|
local headers="$3"
|
||||||
|
echo -n "Тест: $name (Порт $port)... "
|
||||||
|
|
||||||
|
# Используем curl с таймаутом, чтобы не висело вечно
|
||||||
|
local start_time=$(date +%s%3N)
|
||||||
|
local out
|
||||||
|
# В Windows curl может вести себя иначе, но мы предполагаем запуск на роутере или в bash
|
||||||
|
out=$(curl -s -i -m 10 \
|
||||||
|
$headers \
|
||||||
|
"http://$IP:$port/rci/system/hostname" 2>&1)
|
||||||
|
local status=$?
|
||||||
|
local end_time=$(date +%s%3N)
|
||||||
|
local duration=$((end_time - start_time))
|
||||||
|
|
||||||
|
if [ $status -eq 0 ]; then
|
||||||
|
local code=$(echo "$out" | grep "HTTP/" | tail -1 | awk '{print $2}')
|
||||||
|
echo "OK [$code] ($duration ms)"
|
||||||
|
if [ "$code" = "401" ]; then
|
||||||
|
echo " Заголовки WWW-Authenticate:"
|
||||||
|
echo "$out" | grep -i "WWW-Authenticate" | sed 's/^/ / '
|
||||||
|
fi
|
||||||
|
elif [ $status -eq 28 ]; then
|
||||||
|
echo "TIMEOUT (Зависло!)"
|
||||||
|
else
|
||||||
|
echo "ERROR (Код curl: $status)"
|
||||||
|
echo "$out" | head -n 3 | sed 's/^/ / '
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "--- Начинаем тесты ---"
|
||||||
|
|
||||||
|
# 1. Базовый порт 80, чистый Basic Auth
|
||||||
|
test_request "Port 80 + Basic Auth" 80 "-H \"Authorization: Basic $AUTH_BASE64\""
|
||||||
|
|
||||||
|
# 2. Порт 80 + Метод v1.3.8 (XMLHttpRequest)
|
||||||
|
test_request "Port 80 + XMLHttpRequest" 80 "-H \"Authorization: Basic $AUTH_BASE64\" -H \"X-Requested-With: XMLHttpRequest\""
|
||||||
|
|
||||||
|
# 3. Порт 80 + Метод v1.3.8 (Full X-Headers)
|
||||||
|
test_request "Port 80 + Full X-Headers" 80 "-H \"Authorization: Basic $AUTH_BASE64\" -H \"X-Requested-With: XMLHttpRequest\" -H \"X-NDM-Auth-Type: Basic\" -H \"Accept: application/json\""
|
||||||
|
|
||||||
|
# 4. Порт 79 (Служебный) - Чистый Basic
|
||||||
|
test_request "Port 79 + Basic Auth" 79 "-H \"Authorization: Basic $AUTH_BASE64\""
|
||||||
|
|
||||||
|
# 5. Порт 79 + XMLHttpRequest
|
||||||
|
test_request "Port 79 + XMLHttpRequest" 79 "-H \"Authorization: Basic $AUTH_BASE64\" -H \"X-Requested-With: XMLHttpRequest\""
|
||||||
|
|
||||||
|
echo "--- Диагностика завершена ---"
|
||||||
Loading…
Reference in New Issue