mirror of
https://github.com/andrey271192/PCA_Phobos.git
synced 2026-09-20 11:55:32 +00:00
544 lines
18 KiB
Bash
Executable File
544 lines
18 KiB
Bash
Executable File
#!/bin/sh
|
||
set -e
|
||
|
||
PHOBOS_DIR=""
|
||
ROUTER_PLATFORM=""
|
||
SELECTED_CONF=""
|
||
IS_FULL_REMOVAL="1"
|
||
OBFUSCATOR_CONFIGS=""
|
||
OBFUSCATOR_CONFIG_COUNT=0
|
||
|
||
. "$(dirname "$0")/lib-client.sh"
|
||
|
||
collect_obf_configs() {
|
||
OBFUSCATOR_CONFIGS=""
|
||
OBFUSCATOR_CONFIG_COUNT=0
|
||
[ -d "$PHOBOS_DIR" ] || return
|
||
for f in "$PHOBOS_DIR"/wg-obfuscator*.conf; do
|
||
[ -f "$f" ] || continue
|
||
OBFUSCATOR_CONFIGS="${OBFUSCATOR_CONFIGS}$(basename "$f" .conf) "
|
||
OBFUSCATOR_CONFIG_COUNT=$((OBFUSCATOR_CONFIG_COUNT + 1))
|
||
done
|
||
}
|
||
|
||
get_config_label() {
|
||
local obf_conf_base="$1"
|
||
local idx_suffix="${obf_conf_base#wg-obfuscator}"
|
||
local wg_iface="phobos${idx_suffix}"
|
||
local addr=""
|
||
if [ -f "/etc/wireguard/${wg_iface}.conf" ]; then
|
||
addr=$(grep '^Address' "/etc/wireguard/${wg_iface}.conf" 2>/dev/null | cut -d'=' -f2 | tr -d ' ' | cut -d'/' -f1 | cut -d',' -f1) || addr=""
|
||
fi
|
||
if [ -n "$addr" ]; then
|
||
printf "%s [интерфейс: %s, адрес: %s]" "$obf_conf_base" "$wg_iface" "$addr"
|
||
else
|
||
printf "%s" "$obf_conf_base"
|
||
fi
|
||
}
|
||
|
||
select_config_to_remove() {
|
||
collect_obf_configs
|
||
|
||
if [ "$OBFUSCATOR_CONFIG_COUNT" -eq 0 ]; then
|
||
IS_FULL_REMOVAL="1"
|
||
SELECTED_CONF="all"
|
||
return
|
||
fi
|
||
|
||
if [ "$OBFUSCATOR_CONFIG_COUNT" -eq 1 ]; then
|
||
SELECTED_CONF=$(echo "$OBFUSCATOR_CONFIGS" | tr -s ' ' '\n' | grep -v '^$' | head -1)
|
||
IS_FULL_REMOVAL="1"
|
||
log "Обнаружена конфигурация: ${SELECTED_CONF}"
|
||
return
|
||
fi
|
||
|
||
log ""
|
||
log "Обнаружено несколько конфигураций:"
|
||
log ""
|
||
|
||
local i=1
|
||
for conf_base in $OBFUSCATOR_CONFIGS; do
|
||
local label
|
||
label=$(get_config_label "$conf_base")
|
||
log " ${i}) ${label}"
|
||
i=$((i + 1))
|
||
done
|
||
|
||
local all_num=$i
|
||
log " ${all_num}) Удалить все"
|
||
log ""
|
||
|
||
printf "Введите номер конфигурации для удаления: "
|
||
read -r answer || answer=""
|
||
|
||
case "$answer" in
|
||
''|*[!0-9]*)
|
||
log "ОШИБКА: Неверный ввод"
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
if [ "$answer" -eq "$all_num" ]; then
|
||
IS_FULL_REMOVAL="1"
|
||
SELECTED_CONF="all"
|
||
return
|
||
fi
|
||
|
||
if [ "$answer" -lt 1 ] || [ "$answer" -ge "$all_num" ]; then
|
||
log "ОШИБКА: Номер вне диапазона"
|
||
exit 1
|
||
fi
|
||
|
||
local selected_i=1
|
||
for conf_base in $OBFUSCATOR_CONFIGS; do
|
||
if [ "$selected_i" -eq "$answer" ]; then
|
||
SELECTED_CONF="$conf_base"
|
||
IS_FULL_REMOVAL="0"
|
||
return
|
||
fi
|
||
selected_i=$((selected_i + 1))
|
||
done
|
||
}
|
||
|
||
remove_single_obfuscator_instance() {
|
||
local obf_conf_base="$1"
|
||
local idx_suffix="${obf_conf_base#wg-obfuscator}"
|
||
local binary_name="wg-obfuscator${idx_suffix}"
|
||
local service_name="phobos-obfuscator${idx_suffix}"
|
||
local wg_iface="phobos${idx_suffix}"
|
||
|
||
log "Удаление конфигурации ${obf_conf_base}..."
|
||
|
||
local link_file="$PHOBOS_DIR/${obf_conf_base}.link"
|
||
local linked_client=""
|
||
if [ -f "$link_file" ]; then
|
||
linked_client=$(cat "$link_file" 2>/dev/null) || linked_client=""
|
||
fi
|
||
|
||
local privkey_fallback=""
|
||
if [ -z "$linked_client" ] && [ "$ROUTER_PLATFORM" = "linux" ] && [ -f "/etc/wireguard/${wg_iface}.conf" ]; then
|
||
privkey_fallback=$(grep '^PrivateKey' "/etc/wireguard/${wg_iface}.conf" 2>/dev/null | cut -d'=' -f2- | tr -d ' \t') || privkey_fallback=""
|
||
fi
|
||
|
||
for f in /opt/etc/init.d/S[0-9]*wg-obfuscator*; do
|
||
[ -f "$f" ] || continue
|
||
if grep -q "^PROCS=${binary_name}$" "$f" 2>/dev/null; then
|
||
"$f" stop >/dev/null 2>&1 || true
|
||
rm -f "$f"
|
||
log " ✓ Удален init-скрипт: $f"
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [ -f "/etc/init.d/${service_name}" ]; then
|
||
/etc/init.d/${service_name} stop >/dev/null 2>&1 || true
|
||
/etc/init.d/${service_name} disable >/dev/null 2>&1 || true
|
||
rm -f "/etc/init.d/${service_name}"
|
||
log " ✓ Удален procd init-скрипт: /etc/init.d/${service_name}"
|
||
fi
|
||
|
||
if command -v systemctl >/dev/null 2>&1 && [ -f "/etc/systemd/system/${service_name}.service" ]; then
|
||
systemctl stop "${service_name}" >/dev/null 2>&1 || true
|
||
systemctl disable "${service_name}" >/dev/null 2>&1 || true
|
||
rm -f "/etc/systemd/system/${service_name}.service"
|
||
log " ✓ Удален systemd сервис: /etc/systemd/system/${service_name}.service"
|
||
fi
|
||
|
||
for dir in /opt/bin /usr/bin /usr/local/bin; do
|
||
if [ -f "${dir}/${binary_name}" ]; then
|
||
rm -f "${dir}/${binary_name}"
|
||
log " ✓ Удален бинарник: ${dir}/${binary_name}"
|
||
fi
|
||
done
|
||
|
||
if [ "$ROUTER_PLATFORM" = "linux" ] && command -v systemctl >/dev/null 2>&1; then
|
||
systemctl stop "wg-quick@${wg_iface}" >/dev/null 2>&1 || true
|
||
systemctl disable "wg-quick@${wg_iface}" >/dev/null 2>&1 || true
|
||
if [ -d "/etc/systemd/system/wg-quick@${wg_iface}.service.d" ]; then
|
||
rm -rf "/etc/systemd/system/wg-quick@${wg_iface}.service.d"
|
||
log " ✓ Удален systemd override: wg-quick@${wg_iface}"
|
||
fi
|
||
if [ -f "/etc/wireguard/${wg_iface}.conf" ]; then
|
||
rm -f "/etc/wireguard/${wg_iface}.conf"
|
||
log " ✓ Удален WireGuard конфиг: /etc/wireguard/${wg_iface}.conf"
|
||
fi
|
||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||
elif [ "$ROUTER_PLATFORM" = "keenetic" ]; then
|
||
if command -v curl >/dev/null 2>&1 && command -v jq >/dev/null 2>&1 && [ -n "$linked_client" ]; then
|
||
local target_desc="Phobos-${linked_client}"
|
||
log " Удаление WireGuard интерфейса Keenetic: ${target_desc}..."
|
||
local iface_list=$(curl -s "http://127.0.0.1:79/rci/show/interface" 2>/dev/null || echo "")
|
||
if [ -n "$iface_list" ] && echo "$iface_list" | jq -e . >/dev/null 2>&1; then
|
||
local iface_id=$(echo "$iface_list" | jq -r --arg desc "$target_desc" 'to_entries[] | select((.value.description? // "") == $desc) | .key' 2>/dev/null)
|
||
if [ -n "$iface_id" ]; then
|
||
local del_json=$(cat <<EOF
|
||
{
|
||
"interface": {
|
||
"$iface_id": {
|
||
"no": true
|
||
}
|
||
}
|
||
}
|
||
EOF
|
||
)
|
||
local del_result=$(echo "$del_json" | curl -s -X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d @- \
|
||
"http://127.0.0.1:79/rci/" 2>/dev/null)
|
||
if echo "$del_result" | jq -e '.status == "error"' >/dev/null 2>&1; then
|
||
local err_msg=$(echo "$del_result" | jq -r '.message // "Unknown error"' 2>/dev/null)
|
||
log " ОШИБКА при удалении ${iface_id}: $err_msg"
|
||
else
|
||
log " ✓ Интерфейс ${iface_id} (${target_desc}) удален"
|
||
curl -s -X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"system":{"configuration":{"save":{}}}}' \
|
||
"http://127.0.0.1:79/rci/" >/dev/null 2>&1
|
||
log " ✓ Конфигурация сохранена"
|
||
fi
|
||
else
|
||
log " Интерфейс с описанием '${target_desc}' не найден"
|
||
fi
|
||
else
|
||
log " RCI API недоступен, пропускаем удаление интерфейса Keenetic"
|
||
fi
|
||
else
|
||
log " curl/jq не доступны или имя клиента не определено, пропускаем удаление интерфейса Keenetic"
|
||
fi
|
||
elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
|
||
remove_wireguard_interfaces_openwrt
|
||
remove_firewall_zone_openwrt
|
||
fi
|
||
|
||
if [ -f "$PHOBOS_DIR/${obf_conf_base}.conf" ]; then
|
||
rm -f "$PHOBOS_DIR/${obf_conf_base}.conf"
|
||
log " ✓ Удален конфиг obfuscator: $PHOBOS_DIR/${obf_conf_base}.conf"
|
||
fi
|
||
|
||
[ -f "$link_file" ] && rm -f "$link_file"
|
||
|
||
if [ -n "$linked_client" ] && [ -f "$PHOBOS_DIR/${linked_client}.conf" ]; then
|
||
rm -f "$PHOBOS_DIR/${linked_client}.conf"
|
||
log " ✓ Удален конфиг клиента: ${linked_client}.conf"
|
||
elif [ -n "$privkey_fallback" ]; then
|
||
for client_conf in "$PHOBOS_DIR"/*.conf; do
|
||
[ -f "$client_conf" ] || continue
|
||
case "$(basename "$client_conf")" in
|
||
wg-obfuscator*.conf) continue ;;
|
||
esac
|
||
if grep -qF "PrivateKey = ${privkey_fallback}" "$client_conf" 2>/dev/null; then
|
||
rm -f "$client_conf"
|
||
log " ✓ Удален конфиг клиента: $(basename "$client_conf")"
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
|
||
local remaining=0
|
||
for f in "$PHOBOS_DIR"/*.conf; do
|
||
[ -f "$f" ] && remaining=$((remaining + 1))
|
||
done
|
||
|
||
if [ "$remaining" -eq 0 ] && [ -d "$PHOBOS_DIR" ]; then
|
||
rm -rf "$PHOBOS_DIR"
|
||
log " ✓ Удалена директория: $PHOBOS_DIR"
|
||
fi
|
||
}
|
||
|
||
stop_obfuscator() {
|
||
log "Остановка wg-obfuscator..."
|
||
|
||
for f in /opt/etc/init.d/S[0-9]*wg-obfuscator*; do
|
||
[ -f "$f" ] && "$f" stop >/dev/null 2>&1 || true
|
||
done
|
||
|
||
for f in /etc/init.d/phobos-obfuscator*; do
|
||
if [ -f "$f" ]; then
|
||
"$f" stop >/dev/null 2>&1 || true
|
||
"$f" disable >/dev/null 2>&1 || true
|
||
fi
|
||
done
|
||
|
||
if command -v systemctl >/dev/null 2>&1; then
|
||
systemctl list-units --no-legend --plain 'phobos-obfuscator*.service' | awk '{print $1}' | while read -r unit; do
|
||
systemctl stop "$unit" >/dev/null 2>&1 || true
|
||
systemctl disable "$unit" >/dev/null 2>&1 || true
|
||
done
|
||
fi
|
||
|
||
if ps | grep -v grep | grep -q wg-obfuscator; then
|
||
log " Принудительное завершение процесса..."
|
||
pkill -f wg-obfuscator >/dev/null 2>&1 || true
|
||
fi
|
||
}
|
||
|
||
remove_wireguard_interfaces_keenetic() {
|
||
log "Удаление WireGuard интерфейсов Phobos (Keenetic)..."
|
||
|
||
if ! command -v curl >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
|
||
log " curl или jq не установлен, пропускаем удаление интерфейсов"
|
||
return 0
|
||
fi
|
||
|
||
local interfaces=$(curl -s "http://127.0.0.1:79/rci/show/interface" 2>/dev/null || echo "")
|
||
|
||
if [ -z "$interfaces" ] || ! echo "$interfaces" | jq -e . >/dev/null 2>&1; then
|
||
log " RCI API недоступен или вернул некорректный JSON"
|
||
return 0
|
||
fi
|
||
|
||
local removed_count=0
|
||
|
||
local phobos_interfaces=$(echo "$interfaces" | jq -r 'to_entries[] | select(.value.description? // "" | startswith("Phobos-")) | .key' 2>/dev/null)
|
||
|
||
if [ -z "$phobos_interfaces" ]; then
|
||
log " Интерфейсы Phobos не найдены в системе"
|
||
return 0
|
||
fi
|
||
|
||
echo "$phobos_interfaces" | while read -r interface_id; do
|
||
if [ -z "$interface_id" ]; then
|
||
continue
|
||
fi
|
||
|
||
local interface_desc=$(echo "$interfaces" | jq -r --arg id "$interface_id" '.[$id].description // "unknown"' 2>/dev/null)
|
||
|
||
log " Удаление интерфейса: $interface_id ($interface_desc)"
|
||
|
||
local delete_json=$(cat <<EOF
|
||
{
|
||
"interface": {
|
||
"$interface_id": {
|
||
"no": true
|
||
}
|
||
}
|
||
}
|
||
EOF
|
||
)
|
||
|
||
local result=$(echo "$delete_json" | curl -s -X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d @- \
|
||
"http://127.0.0.1:79/rci/" 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)
|
||
log " ОШИБКА при удалении $interface_id: $error_msg"
|
||
else
|
||
log " ✓ Интерфейс $interface_id удален"
|
||
removed_count=$((removed_count + 1))
|
||
fi
|
||
done
|
||
|
||
local save_result=$(curl -s -X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"system":{"configuration":{"save":{}}}}' \
|
||
"http://127.0.0.1:79/rci/" 2>/dev/null)
|
||
|
||
if [ $removed_count -gt 0 ]; then
|
||
log "✓ Удалено интерфейсов: $removed_count"
|
||
log "✓ Конфигурация сохранена"
|
||
fi
|
||
}
|
||
|
||
remove_wireguard_interfaces_openwrt() {
|
||
log "Удаление WireGuard интерфейсов Phobos (OpenWRT)..."
|
||
|
||
if ! command -v uci >/dev/null 2>&1; then
|
||
log " uci не установлен, пропускаем удаление интерфейсов"
|
||
return 0
|
||
fi
|
||
|
||
local interface_name="phobos_wg"
|
||
|
||
if uci -q get network.${interface_name} >/dev/null 2>&1; then
|
||
log " Удаление интерфейса: ${interface_name}"
|
||
|
||
ifdown ${interface_name} >/dev/null 2>&1 || true
|
||
|
||
uci -q delete network.${interface_name} || true
|
||
|
||
local peers=$(uci show network 2>/dev/null | grep "wireguard_${interface_name}" | cut -d'.' -f2 | cut -d'=' -f1 | sort -u)
|
||
for peer in $peers; do
|
||
uci -q delete network.$peer || true
|
||
done
|
||
|
||
uci commit network
|
||
|
||
log " ✓ Интерфейс ${interface_name} удален"
|
||
else
|
||
log " Интерфейс ${interface_name} не найден"
|
||
fi
|
||
|
||
/etc/init.d/network reload >/dev/null 2>&1 || true
|
||
}
|
||
|
||
remove_firewall_zone_openwrt() {
|
||
log "Удаление файрволл зоны Phobos (OpenWRT)..."
|
||
|
||
if ! command -v uci >/dev/null 2>&1; then
|
||
log " uci не установлен, пропускаем удаление зоны"
|
||
return 0
|
||
fi
|
||
|
||
local zone_name="phobos"
|
||
|
||
if uci -q get firewall.${zone_name} >/dev/null 2>&1; then
|
||
log " Удаление зоны: ${zone_name}"
|
||
uci -q delete firewall.${zone_name} || true
|
||
uci commit firewall
|
||
log " ✓ Зона ${zone_name} удалена"
|
||
|
||
/etc/init.d/firewall reload >/dev/null 2>&1 || true
|
||
else
|
||
log " Зона ${zone_name} не найдена"
|
||
fi
|
||
}
|
||
|
||
remove_wireguard_interfaces_linux() {
|
||
log "Удаление WireGuard интерфейсов Phobos (Linux)..."
|
||
|
||
if ! command -v systemctl >/dev/null 2>&1; then
|
||
log " systemctl не найден, пропускаем удаление интерфейсов"
|
||
return 0
|
||
fi
|
||
|
||
for wg_conf in /etc/wireguard/phobos*.conf; do
|
||
[ -f "$wg_conf" ] || continue
|
||
local wg_interface
|
||
wg_interface=$(basename "$wg_conf" .conf)
|
||
|
||
if systemctl is-enabled --quiet wg-quick@${wg_interface} 2>/dev/null || systemctl is-active --quiet wg-quick@${wg_interface} 2>/dev/null; then
|
||
log " Остановка и удаление WireGuard сервиса: wg-quick@${wg_interface}"
|
||
systemctl stop wg-quick@${wg_interface} >/dev/null 2>&1 || true
|
||
systemctl disable wg-quick@${wg_interface} >/dev/null 2>&1 || true
|
||
log " ✓ Сервис wg-quick@${wg_interface} остановлен и отключен"
|
||
fi
|
||
|
||
if [ -d "/etc/systemd/system/wg-quick@${wg_interface}.service.d" ]; then
|
||
log " Удаление systemd override: /etc/systemd/system/wg-quick@${wg_interface}.service.d"
|
||
rm -rf "/etc/systemd/system/wg-quick@${wg_interface}.service.d"
|
||
log " ✓ Systemd override удален"
|
||
fi
|
||
|
||
log " Удаление конфигурации: $wg_conf"
|
||
rm -f "$wg_conf"
|
||
log " ✓ Конфигурационный файл WireGuard удален"
|
||
done
|
||
|
||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||
}
|
||
|
||
remove_files() {
|
||
log "Удаление файлов Phobos..."
|
||
|
||
for f in /opt/etc/init.d/S[0-9]*wg-obfuscator*; do
|
||
if [ -f "$f" ]; then
|
||
rm -f "$f"
|
||
log " ✓ Удален init-скрипт: $f"
|
||
fi
|
||
done
|
||
|
||
for f in /etc/init.d/phobos-obfuscator*; do
|
||
if [ -f "$f" ]; then
|
||
rm -f "$f"
|
||
log " ✓ Удален procd init-скрипт: $f"
|
||
fi
|
||
done
|
||
|
||
for f in /opt/bin/wg-obfuscator*; do
|
||
if [ -f "$f" ]; then
|
||
rm -f "$f"
|
||
log " ✓ Удален бинарник: $f"
|
||
fi
|
||
done
|
||
|
||
for f in /usr/bin/wg-obfuscator*; do
|
||
if [ -f "$f" ]; then
|
||
rm -f "$f"
|
||
log " ✓ Удален бинарник: $f"
|
||
fi
|
||
done
|
||
|
||
for f in /usr/local/bin/wg-obfuscator*; do
|
||
if [ -f "$f" ]; then
|
||
rm -f "$f"
|
||
log " ✓ Удален бинарник: $f"
|
||
fi
|
||
done
|
||
|
||
local daemon_reload_needed=0
|
||
for f in /etc/systemd/system/phobos-obfuscator*.service; do
|
||
if [ -f "$f" ]; then
|
||
rm -f "$f"
|
||
daemon_reload_needed=1
|
||
log " ✓ Удален systemd сервис: $f"
|
||
fi
|
||
done
|
||
|
||
if [ $daemon_reload_needed -eq 1 ]; then
|
||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||
fi
|
||
|
||
if [ -d "$PHOBOS_DIR" ]; then
|
||
rm -rf "$PHOBOS_DIR"
|
||
log " ✓ Удалена директория: $PHOBOS_DIR"
|
||
fi
|
||
}
|
||
|
||
show_final_info() {
|
||
log ""
|
||
log "╔════════════════════════════════════════════════════════════╗"
|
||
log "║ Phobos успешно удален ║"
|
||
log "╚════════════════════════════════════════════════════════════╝"
|
||
log ""
|
||
log "Удалены компоненты:"
|
||
log " - wg-obfuscator (процесс, init-скрипт/сервис, бинарник)"
|
||
log " - WireGuard интерфейсы Phobos"
|
||
log " - Конфигурационные файлы"
|
||
log ""
|
||
}
|
||
|
||
main() {
|
||
ROUTER_PLATFORM=$(detect_router_platform)
|
||
PHOBOS_DIR=$(detect_phobos_dir "$ROUTER_PLATFORM")
|
||
|
||
log "==> Начало удаления Phobos (платформа: $ROUTER_PLATFORM)"
|
||
log "==> Директория: $PHOBOS_DIR"
|
||
|
||
check_root
|
||
|
||
select_config_to_remove
|
||
|
||
if [ "$IS_FULL_REMOVAL" = "1" ]; then
|
||
stop_obfuscator
|
||
|
||
if [ "$ROUTER_PLATFORM" = "keenetic" ]; then
|
||
remove_wireguard_interfaces_keenetic
|
||
elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
|
||
remove_wireguard_interfaces_openwrt
|
||
remove_firewall_zone_openwrt
|
||
elif [ "$ROUTER_PLATFORM" = "linux" ]; then
|
||
remove_wireguard_interfaces_linux
|
||
else
|
||
log "ПРЕДУПРЕЖДЕНИЕ: Неизвестная платформа, пропускаем удаление WireGuard интерфейсов"
|
||
fi
|
||
|
||
remove_files
|
||
|
||
show_final_info
|
||
else
|
||
log "==> Удаление конфигурации: ${SELECTED_CONF}"
|
||
remove_single_obfuscator_instance "$SELECTED_CONF"
|
||
log ""
|
||
log "╔════════════════════════════════════════════════════════════╗"
|
||
log "║ Конфигурация успешно удалена ║"
|
||
log "╚════════════════════════════════════════════════════════════╝"
|
||
log ""
|
||
fi
|
||
|
||
log "==> Удаление завершено."
|
||
}
|
||
|
||
main "$@"
|