Files
PCA_Phobos/overlay/router-configure-wireguard.sh
phobos fff45ca342 turnkey installer: full primary stack one-command + session improvements
- install.sh: rewritten as self-contained turnkey primary installer (deps,
  wg-obfuscator from Ground-Zerro, wg0, obfuscator services, Phobos repo +
  PCA overlay patches, web panel, nginx, router watchdog).
- app.py: current panel (RU/EN, tunnel-pull config endpoint, fan-out, load-aware
  rebalance, online-anywhere status, '?' help).
- overlay/: patched onboarding scripts (phobos-client.sh 403 fix,
  install-router.sh.template tunnel-pull+cron+client_id, router-configure-wireguard
  public WG, phobos-pull.sh tunnel-first).
- server/: phobos-health.sh (self-heal+apply-server), phobos-pull.sh,
  phobos-router-watchdog.py, api.py (agent + /api/router-config).
2026-05-30 13:39:49 +03:00

430 lines
13 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
set -e
RCI_URL="http://localhost:79/rci/"
MAX_INTERFACE_NUM=9
check_dependencies() {
local missing=""
for cmd in curl jq date; do
if ! command -v "$cmd" >/dev/null 2>&1; then
missing="$missing $cmd"
fi
done
if [ -n "$missing" ]; then
echo "ERROR: Missing required utilities:$missing" >&2
echo "Please install them using: opkg update && opkg install$missing" >&2
return 1
fi
return 0
}
CLIENT_NAME=""
CLIENT_PRIVATE_KEY=""
CLIENT_IP=""
CLIENT_IPV6=""
SERVER_PUBLIC_KEY=""
ENDPOINT_PORT=13255
KEEPALIVE=25
MTU=1420
FALLBACK_CONFIG=""
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
error() {
echo "[ERROR] $*" >&2
log "ERROR: $*"
}
usage() {
cat <<EOF
Usage: $0 [OPTIONS]
Options:
--client-name NAME Client name (required)
--client-private-key KEY WireGuard private key (required)
--client-ip IP Client tunnel IPv4 address (required)
--client-ipv6 IP Client tunnel IPv6 address (required)
--server-public-key KEY Server WireGuard public key (required)
--endpoint-port PORT Local obfuscator port (default: 13255)
--keepalive SECONDS Keepalive interval (default: 25)
--mtu MTU Interface MTU (default: 1420)
--fallback-config PATH Path to fallback .conf file
--help Show this help
Example:
$0 --client-name Pegacomp \\
--client-private-key "ABCD..." \\
--client-ip 10.25.0.4 \\
--client-ipv6 fd00:10:25::4 \\
--server-public-key "EFGH..." \\
--endpoint-port 13255 \\
--fallback-config /opt/etc/Phobos/Pegacomp.conf
EOF
exit 1
}
parse_args() {
while [ $# -gt 0 ]; do
case "$1" in
--client-name)
CLIENT_NAME="$2"
shift 2
;;
--client-private-key)
CLIENT_PRIVATE_KEY="$2"
shift 2
;;
--client-ip)
CLIENT_IP="$2"
shift 2
;;
--client-ipv6)
CLIENT_IPV6="$2"
shift 2
;;
--server-public-key)
SERVER_PUBLIC_KEY="$2"
shift 2
;;
--endpoint-port)
ENDPOINT_PORT="$2"
shift 2
;;
--keepalive)
KEEPALIVE="$2"
shift 2
;;
--mtu)
MTU="$2"
shift 2
;;
--fallback-config)
FALLBACK_CONFIG="$2"
shift 2
;;
--help)
usage
;;
*)
error "Unknown option: $1"
usage
;;
esac
done
if [ -z "${CLIENT_NAME}" ] || [ -z "${CLIENT_PRIVATE_KEY}" ] || \
[ -z "${CLIENT_IP}" ] || [ -z "${CLIENT_IPV6}" ] || \
[ -z "${SERVER_PUBLIC_KEY}" ]; then
error "Missing required parameters"
usage
fi
}
find_phobos_interface() {
local client_name="$1"
local target_desc="Phobos-${client_name}"
log "Поиск существующего интерфейса Phobos для клиента: ${client_name}..." >&2
local i
for i in 0 1 2 3 4 5 6 7 8 9; do
local interface_json=$(curl -s "${RCI_URL}show/rc/interface/Wireguard${i}" 2>/dev/null)
if [ -n "${interface_json}" ] && echo "${interface_json}" | jq -e . >/dev/null 2>&1; then
local desc=$(echo "${interface_json}" | jq -r '.description // empty' 2>/dev/null)
if [ "${desc}" = "${target_desc}" ]; then
log "Найден существующий интерфейс: Wireguard${i}" >&2
echo "Wireguard${i}"
return 0
fi
fi
done
log "Существующий интерфейс Phobos не найден" >&2
echo ""
return 0
}
find_free_wireguard_interface() {
log "Поиск свободного интерфейса WireGuard..." >&2
local i
for i in 0 1 2 3 4 5 6 7 8 9; do
local interface_json=$(curl -s "${RCI_URL}show/interface/Wireguard${i}" 2>/dev/null)
if [ -z "${interface_json}" ] || ! echo "${interface_json}" | jq -e '.id' >/dev/null 2>&1; then
log "Найден свободный интерфейс: Wireguard${i}" >&2
echo "Wireguard${i}"
return 0
fi
done
error "Нет свободных интерфейсов WireGuard (0-${MAX_INTERFACE_NUM})"
return 1
}
remove_wireguard_interface() {
local interface_name="$1"
log "Удаление существующего интерфейса: ${interface_name}..."
if command -v ndmc >/dev/null 2>&1; then
if ndmc -c "no interface ${interface_name}" >/dev/null 2>&1; then
log "Интерфейс ${interface_name} успешно удален ✓"
return 0
else
log "Предупреждение: не удалось удалить интерфейс через ndmc"
return 1
fi
else
log "Предупреждение: команда ndmc не найдена"
return 1
fi
}
configure_wireguard_interface() {
local interface_name="$1"
local description="Phobos-${CLIENT_NAME}"
local client_ip_addr=$(echo "${CLIENT_IP}" | cut -d'/' -f1)
local client_ipv6_block="${CLIENT_IPV6}"
log "Настройка интерфейса ${interface_name}..."
local config_json=$(cat <<EOF
{
"interface": {
"${interface_name}": {
"description": "${description}",
"security-level": {
"public": true
},
"ip": {
"address": {
"address": "${client_ip_addr}",
"mask": "255.255.255.255"
},
"mtu": ${MTU},
"global": true,
"defaultgw": false,
"priority": 26622,
"tcp": {
"adjust-mss": {
"pmtu": true
}
}
},
"ipv6": {
"address": [
{"auto": false},
{"block": "${client_ipv6_block}"}
],
"prefix": [
{"auto": false}
]
},
"wireguard": {
"private-key": "${CLIENT_PRIVATE_KEY}",
"peer": [
{
"key": "${SERVER_PUBLIC_KEY}",
"comment": "Phobos VPS Server",
"endpoint": {
"address": "127.0.0.1:${ENDPOINT_PORT}"
},
"keepalive-interval": {
"interval": ${KEEPALIVE}
},
"allow-ips": [
{
"address": "0.0.0.0",
"mask": "0.0.0.0"
},
{
"address": "::",
"mask": "0"
}
]
}
]
},
"up": true
}
}
}
EOF
)
local result=$(echo "${config_json}" | curl -s -X POST \
-H "Content-Type: application/json" \
-d @- \
"${RCI_URL}" 2>/dev/null)
if echo "${result}" | jq -e '.status == "error"' >/dev/null 2>&1; then
local error_msg=$(echo "${result}" | jq -r '.message // "Unknown error"' 2>/dev/null)
error "RCI API отклонил конфигурацию: ${error_msg}"
log "JSON запрос:"
log "${config_json}"
return 1
fi
log "Интерфейс ${interface_name} создан ✓"
return 0
}
save_configuration() {
log "Сохранение конфигурации..."
local result=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"system":{"configuration":{"save":{}}}}' \
"${RCI_URL}" 2>/dev/null)
if echo "${result}" | grep -q '"status"[[:space:]]*:[[:space:]]*"message"'; then
log "Конфигурация сохранена ✓"
return 0
else
error "Ошибка сохранения конфигурации"
return 1
fi
}
verify_interface_created() {
local client_name="$1"
local interface_description="Phobos-${client_name}"
log "Проверка создания интерфейса WireGuard..."
local interfaces=$(curl -s "http://127.0.0.1:79/rci/show/interface" 2>/dev/null || echo "")
if [ -z "$interfaces" ]; then
error "Не удалось получить список интерфейсов через RCI API"
return 1
fi
if ! echo "$interfaces" | jq -e . >/dev/null 2>&1; then
error "Некорректный JSON ответ от RCI API"
return 1
fi
local found=$(echo "$interfaces" | jq -r "to_entries[] | select(.value.description == \"$interface_description\") | .key" 2>/dev/null)
if [ -n "$found" ]; then
log "✓ Интерфейс $found (Phobos-${client_name}) успешно создан"
return 0
else
error "Интерфейс с description '$interface_description' не найден"
return 1
fi
}
show_fallback_instructions() {
cat <<EOF
╔════════════════════════════════════════════════════════════╗
║ RCI API недоступен - требуется ручная настройка ║
╚════════════════════════════════════════════════════════════╝
Конфигурация сохранена в: ${FALLBACK_CONFIG}
Инструкция по ручному импорту:
1. Откройте веб-панель Keenetic (http://192.168.1.1 или http://my.keenetic.net)
2. Перейдите: Интернет → WireGuard
3. Нажмите: 'Добавить подключение'
4. Выберите: 'Загрузить конфигурацию из файла'
5. Укажите путь: ${FALLBACK_CONFIG}
6. Активируйте подключение
EOF
}
main() {
parse_args "$@"
if ! check_dependencies; then
exit 1
fi
mkdir -p /opt/etc/Phobos
log "=== Phobos WireGuard RCI Configuration ==="
log "Клиент: ${CLIENT_NAME}"
EXISTING_INTERFACE=$(find_phobos_interface "${CLIENT_NAME}") || true
if [ -n "${EXISTING_INTERFACE}" ]; then
log "Обнаружен существующий интерфейс: ${EXISTING_INTERFACE}"
if remove_wireguard_interface "${EXISTING_INTERFACE}"; then
log "Интерфейс ${EXISTING_INTERFACE} удален, будет создан заново"
else
log "Не удалось удалить интерфейс ${EXISTING_INTERFACE}, попытка пересоздать"
fi
fi
INTERFACE_NAME=$(find_free_wireguard_interface) || true
if [ -z "${INTERFACE_NAME}" ]; then
show_fallback_instructions
exit 1
fi
log "Создание нового интерфейса: ${INTERFACE_NAME}"
if ! configure_wireguard_interface "${INTERFACE_NAME}"; then
error "Не удалось настроить WireGuard через RCI API"
show_fallback_instructions
exit 1
fi
if ! save_configuration; then
error "Не удалось сохранить конфигурацию"
exit 1
fi
log "Настройка WireGuard завершена успешно! ✓"
log "Интерфейс: ${INTERFACE_NAME}"
log "Description: Phobos-${CLIENT_NAME}"
log ""
log "Проверка статуса wg-obfuscator..."
if [ -f /opt/etc/init.d/S49wg-obfuscator ]; then
local obf_status=$(/opt/etc/init.d/S49wg-obfuscator status 2>&1)
if echo "${obf_status}" | grep -q "dead"; then
log "⚠ wg-obfuscator остановлен, перезапускаем..."
/opt/etc/init.d/S49wg-obfuscator start
sleep 2
log "✓ wg-obfuscator перезапущен"
else
log "✓ wg-obfuscator работает"
fi
fi
log ""
log "Ожидание применения конфигурации..."
sleep 5
if verify_interface_created "${CLIENT_NAME}"; then
log ""
log "╔════════════════════════════════════════════════════════════╗"
log "║ WireGuard успешно настроен! ║"
log "╚════════════════════════════════════════════════════════════╝"
log ""
exit 0
else
log ""
log "⚠ Не удалось подтвердить создание интерфейса WireGuard"
log ""
log "Проверьте вручную в веб-панели Keenetic:"
log " Интернет → WireGuard"
log ""
exit 1
fi
}
main "$@"