#!/bin/sh set -e PHOBOS_DIR="" ROUTER_PLATFORM="" . "$(dirname "$0")/lib-client.sh" remove_obfuscator_instance() { local bin="$1" local init="$2" local service="$3" if [ -n "$init" ] && [ -f "/opt/etc/init.d/${init}" ]; then "/opt/etc/init.d/${init}" stop >/dev/null 2>&1 || true rm -f "/opt/etc/init.d/${init}" log " ✓ Удалён init-скрипт: /opt/etc/init.d/${init}" fi if [ -n "$service" ] && [ -f "/etc/init.d/${service}" ]; then "/etc/init.d/${service}" stop >/dev/null 2>&1 || true "/etc/init.d/${service}" disable >/dev/null 2>&1 || true rm -f "/etc/init.d/${service}" log " ✓ Удалён procd init: /etc/init.d/${service}" fi if [ -n "$service" ] && command -v systemctl >/dev/null 2>&1 && [ -f "/etc/systemd/system/${service}.service" ]; then systemctl stop "${service}" >/dev/null 2>&1 || true systemctl disable "${service}" >/dev/null 2>&1 || true rm -f "/etc/systemd/system/${service}.service" systemctl daemon-reload >/dev/null 2>&1 || true log " ✓ Удалён systemd сервис: ${service}" fi local dir for dir in /opt/bin /usr/bin /usr/local/bin; do if [ -n "$bin" ] && [ -f "${dir}/${bin}" ]; then rm -f "${dir}/${bin}" log " ✓ Удалён бинарник: ${dir}/${bin}" fi done } remove_wg_interface_keenetic() { local desc="$1" if ! command -v curl >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then log " curl/jq недоступны, пропуск удаления интерфейса Keenetic" return 0 fi local list list=$(curl -s "http://127.0.0.1:79/rci/show/interface" 2>/dev/null || echo "") if ! echo "$list" | jq -e . >/dev/null 2>&1; then log " RCI API недоступен, пропуск удаления интерфейса" return 0 fi local id id=$(echo "$list" | jq -r --arg d "$desc" 'to_entries[] | select((.value.description? // "") == $d) | .key' 2>/dev/null | head -1) if [ -z "$id" ]; then log " Интерфейс Keenetic '${desc}' не найден" return 0 fi printf '{"interface":{"%s":{"no":true}}}' "$id" | curl -s -X POST \ -H "Content-Type: application/json" -d @- "http://127.0.0.1:79/rci/" >/dev/null 2>&1 || true curl -s -X POST -H "Content-Type: application/json" \ -d '{"system":{"configuration":{"save":{}}}}' "http://127.0.0.1:79/rci/" >/dev/null 2>&1 || true log " ✓ Интерфейс Keenetic ${id} (${desc}) удалён" } remove_wg_interface_openwrt() { local iface="$1" command -v uci >/dev/null 2>&1 || return 0 ifdown "$iface" >/dev/null 2>&1 || true uci -q delete "network.wgpeer_${iface}" || true local section for section in $(uci show network 2>/dev/null | grep "=wireguard_${iface}$" | cut -d. -f2 | cut -d= -f1); do uci -q delete "network.${section}" || true done uci -q delete "network.${iface}" || true uci commit network if uci -q get "firewall.${iface}" >/dev/null 2>&1; then uci -q delete "firewall.${iface}" || true uci commit firewall /etc/init.d/firewall restart >/dev/null 2>&1 || true fi /etc/init.d/network restart >/dev/null 2>&1 || true log " ✓ Интерфейс OpenWRT ${iface} удалён" } remove_socks5_openwrt() { [ -f /etc/redsocks.conf ] || [ -f /etc/nftables.d/30-phobos-socks5.nft ] || return 0 log " Удаление SOCKS5 (redsocks + nft redirect)..." if [ -x /etc/init.d/phobos-redsocks ]; then /etc/init.d/phobos-redsocks stop >/dev/null 2>&1 || true /etc/init.d/phobos-redsocks disable >/dev/null 2>&1 || true fi [ -x /etc/init.d/redsocks ] && /etc/init.d/redsocks stop >/dev/null 2>&1 || true [ -f /var/run/redsocks.pid ] && kill "$(cat /var/run/redsocks.pid)" 2>/dev/null || true pkill -f /usr/sbin/redsocks 2>/dev/null || true rm -f /var/run/redsocks.pid /etc/redsocks.conf /etc/nftables.d/30-phobos-socks5.nft /etc/init.d/phobos-redsocks nft delete chain inet fw4 phobos_socks5_dstnat 2>/dev/null || true nft delete chain inet fw4 phobos_socks5_input 2>/dev/null || true fw4 reload >/dev/null 2>&1 || /etc/init.d/firewall reload >/dev/null 2>&1 || true log " ✓ SOCKS5 (redsocks) удалён" } remove_wg_interface_linux() { local iface="$1" command -v systemctl >/dev/null 2>&1 || return 0 systemctl stop "wg-quick@${iface}" >/dev/null 2>&1 || true systemctl disable "wg-quick@${iface}" >/dev/null 2>&1 || true rm -rf "/etc/systemd/system/wg-quick@${iface}.service.d" rm -f "/etc/wireguard/${iface}.conf" systemctl daemon-reload >/dev/null 2>&1 || true log " ✓ Интерфейс Linux ${iface} удалён" } remove_client() { local client="$1" local line line=$(registry_line_for_client "$client") if [ -z "$line" ]; then log "Клиент ${client} не найден в реестре" return 1 fi local obf_conf obf_bin init service iface obf_conf=$(registry_field "$line" 4) obf_bin=$(registry_field "$line" 5) init=$(registry_field "$line" 6) service=$(registry_field "$line" 7) iface=$(registry_field "$line" 8) log "Удаление клиента: ${client}" remove_obfuscator_instance "$obf_bin" "$init" "$service" case "$ROUTER_PLATFORM" in keenetic) remove_wg_interface_keenetic "$iface" ;; openwrt) remove_socks5_openwrt; remove_wg_interface_openwrt "$iface" ;; linux) remove_wg_interface_linux "$iface" ;; esac rm -f "$PHOBOS_DIR/${obf_conf}" rm -f "$PHOBOS_DIR/${client}.conf" registry_remove_client "$client" log " ✓ Клиент ${client} удалён" } remove_phobos_dir() { [ -d "$PHOBOS_DIR" ] || return 0 rm -rf "$PHOBOS_DIR" log "✓ Удалена директория: $PHOBOS_DIR" } purge_without_registry() { log "Реестр не найден — полная очистка артефактов Phobos..." local f for f in /opt/etc/init.d/S[0-9]*wg-obfuscator /etc/init.d/phobos-obfuscator*; do [ -f "$f" ] || continue "$f" stop >/dev/null 2>&1 || true "$f" disable >/dev/null 2>&1 || true rm -f "$f" log " ✓ Удалён init/сервис: $f" done if command -v systemctl >/dev/null 2>&1; then for f in /etc/systemd/system/phobos-obfuscator*.service; do [ -f "$f" ] || continue local unit unit=$(basename "$f") systemctl stop "$unit" >/dev/null 2>&1 || true systemctl disable "$unit" >/dev/null 2>&1 || true rm -f "$f" log " ✓ Удалён systemd сервис: $unit" done systemctl daemon-reload >/dev/null 2>&1 || true fi for f in /opt/bin/wg-obfuscator* /usr/bin/wg-obfuscator* /usr/local/bin/wg-obfuscator*; do [ -f "$f" ] || continue rm -f "$f" log " ✓ Удалён бинарник: $f" done if command -v pkill >/dev/null 2>&1; then pkill -f wg-obfuscator >/dev/null 2>&1 || true fi remove_phobos_dir } remove_all() { local client for client in $(registry_clients); do [ -n "$client" ] && remove_client "$client" done remove_phobos_dir } select_and_remove() { local clients count clients=$(registry_clients) count=$(printf '%s\n' "$clients" | grep -vc '^$') if [ "$count" -eq 0 ]; then purge_without_registry return fi if [ "$count" -eq 1 ]; then remove_client "$clients" remove_phobos_dir return fi log "" log "Обнаружено несколько клиентов:" log "" local i=1 line port target for client in $clients; do line=$(registry_line_for_client "$client") port=$(registry_field "$line" 3) target=$(registry_field "$line" 9) log " ${i}) ${client} [порт ${port}, сервер ${target}]" 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 remove_all return fi if [ "$answer" -lt 1 ] || [ "$answer" -ge "$all_num" ]; then log "ОШИБКА: Номер вне диапазона" exit 1 fi local selected="" i=1 for client in $clients; do if [ "$i" -eq "$answer" ]; then selected="$client" break fi i=$((i + 1)) done remove_client "$selected" if [ -z "$(registry_clients)" ]; then remove_phobos_dir fi } main() { ROUTER_PLATFORM=$(detect_router_platform) PHOBOS_DIR=$(detect_phobos_dir "$ROUTER_PLATFORM") log "==> Удаление Phobos (платформа: $ROUTER_PLATFORM)" log "==> Директория: $PHOBOS_DIR" check_root select_and_remove log "" log "╔════════════════════════════════════════════════════════════╗" log "║ Удаление завершено ║" log "╚════════════════════════════════════════════════════════════╝" log "" } main "$@"