release 1.5.0: one panel in all channels; Apple apps (iOS, new macOS tab) only in beta/dev
- stable gets the beta panel and server features (new design, presets, firewall, monthly traffic, router failover over all ports/addresses + TCP, altip, HR tab, Windows tab, update banner); ios/ macos/ windows/ sources stay out of stable - menu item "Update to N" under Settings when a new version is out - mobile: top menu no longer stretches to 200px - urllib User-Agent: Cloudflare in front of git.bobyrev.com returns 403 to Python-urllib - docs: GitHub adleibzon-rgb as source, password/uninstall/devices sections, new screenshots, PORTS.md TCP fallback and second IP Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,20 @@ resolve_install_names() {
|
||||
fi
|
||||
|
||||
if [ -f "$binary_path" ] && [ -f "$PHOBOS_DIR/${CLIENT_NAME}.conf" ]; then
|
||||
# 02.11.2026: переустановка — берём те же имена, что у этой учётки (по *.link),
|
||||
# иначе доп. учётка затёрла бы обфускатор главной
|
||||
local l n sc
|
||||
for l in "$PHOBOS_DIR"/wg-obfuscator?*.link; do
|
||||
[ "$(cat "$l" 2>/dev/null)" = "${CLIENT_NAME}" ] || continue
|
||||
n=$(basename "$l" .link); n=${n#wg-obfuscator}
|
||||
sc=$(grep -l "/wg-obfuscator${n}.conf\"\$" /opt/etc/init.d/S*wg-obfuscator 2>/dev/null | head -1)
|
||||
OBF_BINARY_NAME="wg-obfuscator${n}"
|
||||
OBF_CONF_NAME="wg-obfuscator${n}.conf"
|
||||
OBF_INIT_NAME=$(basename "${sc:-S50wg-obfuscator}")
|
||||
OBF_SERVICE_NAME="phobos-obfuscator${n}"
|
||||
OBF_WG_IFACE="phobos${n}"
|
||||
return
|
||||
done
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
@@ -417,6 +417,16 @@ show_final_info() {
|
||||
}
|
||||
|
||||
|
||||
# Убирает из crontab строки health/pull только этой учётки ($1 = "PHOBOS_ACC=<dir> "
|
||||
# для доп. учётки, "PHOBOS_ACC=" для главной — у неё строки без PHOBOS_ACC).
|
||||
drop_own_cron() {
|
||||
if [ "$1" = "PHOBOS_ACC=" ]; then
|
||||
awk '!/phobos-(health|pull)/ || /PHOBOS_ACC=/'
|
||||
else
|
||||
grep -v -F "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_health_monitor() {
|
||||
log "Развертывание монитора здоровья Phobos..."
|
||||
|
||||
@@ -428,12 +438,19 @@ deploy_health_monitor() {
|
||||
cp "phobos-health.sh" "$PHOBOS_DIR/phobos-health.sh"
|
||||
chmod +x "$PHOBOS_DIR/phobos-health.sh"
|
||||
|
||||
if [ -f "failover.conf" ]; then
|
||||
cp "failover.conf" "$PHOBOS_DIR/failover.conf"
|
||||
chmod 600 "$PHOBOS_DIR/failover.conf"
|
||||
# 02.11.2026: вторая и следующие учётки на одном роутере — свой каталог
|
||||
# (failover.conf, state, client_id, panel_*), свои строки cron с PHOBOS_ACC.
|
||||
local A="$PHOBOS_DIR" envp="" mine="PHOBOS_ACC="
|
||||
local main_cid=$(cat "$A/client_id" 2>/dev/null)
|
||||
if [ -n "$main_cid" ] && [ "$main_cid" != "{{CLIENT_NAME}}" ]; then
|
||||
A="$PHOBOS_DIR/acc/{{CLIENT_NAME}}"; envp="PHOBOS_ACC=$A "; mine="PHOBOS_ACC=$A "
|
||||
log " Дополнительная учётка: $A (главная — $main_cid)"
|
||||
fi
|
||||
mkdir -p "$A/state"
|
||||
if [ -f "failover.conf" ]; then
|
||||
cp "failover.conf" "$A/failover.conf"
|
||||
chmod 600 "$A/failover.conf"
|
||||
fi
|
||||
|
||||
mkdir -p "$PHOBOS_DIR/state"
|
||||
|
||||
# --- Phobos pull agent: panel -> router config sync (NAT-friendly) ---
|
||||
# Routers behind NAT cannot be reached by the panel over SSH, so they PULL
|
||||
@@ -441,18 +458,18 @@ deploy_health_monitor() {
|
||||
if [ -f "phobos-pull.sh" ]; then
|
||||
cp "phobos-pull.sh" "$PHOBOS_DIR/phobos-pull.sh"
|
||||
chmod +x "$PHOBOS_DIR/phobos-pull.sh"
|
||||
echo "{{CLIENT_NAME}}" > "$PHOBOS_DIR/client_id"
|
||||
[ -f "pull_token" ] && cp "pull_token" "$PHOBOS_DIR/pull_token"
|
||||
[ -f "panel_tunnel_ip" ] && cp "panel_tunnel_ip" "$PHOBOS_DIR/panel_tunnel_ip"
|
||||
[ -f "panel_port" ] && cp "panel_port" "$PHOBOS_DIR/panel_port"
|
||||
[ -f "panel_scheme" ] && cp "panel_scheme" "$PHOBOS_DIR/panel_scheme"
|
||||
[ -f "panel_url" ] && cp "panel_url" "$PHOBOS_DIR/panel_url"
|
||||
[ -f "panel_urls" ] && cp "panel_urls" "$PHOBOS_DIR/panel_urls"
|
||||
echo "{{CLIENT_NAME}}" > "$A/client_id"
|
||||
[ -f "pull_token" ] && cp "pull_token" "$A/pull_token"
|
||||
[ -f "panel_tunnel_ip" ] && cp "panel_tunnel_ip" "$A/panel_tunnel_ip"
|
||||
[ -f "panel_port" ] && cp "panel_port" "$A/panel_port"
|
||||
[ -f "panel_scheme" ] && cp "panel_scheme" "$A/panel_scheme"
|
||||
[ -f "panel_url" ] && cp "panel_url" "$A/panel_url"
|
||||
[ -f "panel_urls" ] && cp "panel_urls" "$A/panel_urls"
|
||||
log " Pull-агент установлен (client_id={{CLIENT_NAME}})"
|
||||
fi
|
||||
|
||||
local cron_line="*/1 * * * * $PHOBOS_DIR/phobos-health.sh"
|
||||
local pull_line="*/1 * * * * $PHOBOS_DIR/phobos-pull.sh"
|
||||
local cron_line="*/1 * * * * ${envp}$PHOBOS_DIR/phobos-health.sh"
|
||||
local pull_line="*/1 * * * * ${envp}$PHOBOS_DIR/phobos-pull.sh"
|
||||
[ -f "$PHOBOS_DIR/phobos-pull.sh" ] || pull_line=""
|
||||
|
||||
if [ "$ROUTER_PLATFORM" = "keenetic" ]; then
|
||||
@@ -468,21 +485,21 @@ deploy_health_monitor() {
|
||||
mkdir -p /opt/var/spool/cron/crontabs
|
||||
# 01.11.2026: демоны cron на Keenetic (busybox crond, Entware cron) читают crontab
|
||||
# пользователя root, а не /opt/etc/crontab — туда писать бесполезно
|
||||
sed -i "/phobos-health\|phobos-pull/d" /opt/etc/crontab 2>/dev/null || true
|
||||
(crontab -l 2>/dev/null | grep -v "phobos-health" | grep -v "phobos-pull"; echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line") | crontab -
|
||||
[ -z "$envp" ] && sed -i "/phobos-health\|phobos-pull/d" /opt/etc/crontab 2>/dev/null || true
|
||||
(crontab -l 2>/dev/null | drop_own_cron "$mine"; echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line") | crontab -
|
||||
log " Cron добавлен через crontab (health + pull)"
|
||||
/opt/etc/init.d/S10cron restart >/dev/null 2>&1 || true
|
||||
elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
|
||||
(crontab -l 2>/dev/null | grep -v "phobos-health" | grep -v "phobos-pull"; echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line") | crontab -
|
||||
(crontab -l 2>/dev/null | drop_own_cron "$mine"; echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line") | crontab -
|
||||
log " Cron добавлен через crontab (health + pull)"
|
||||
elif [ "$ROUTER_PLATFORM" = "linux" ]; then
|
||||
{ echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line"; } > /etc/cron.d/phobos-health
|
||||
chmod 644 /etc/cron.d/phobos-health
|
||||
{ echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line"; } > /etc/cron.d/phobos-health${envp:+-{{CLIENT_NAME}}}
|
||||
chmod 644 /etc/cron.d/phobos-health*
|
||||
log " Cron добавлен в /etc/cron.d/phobos-health (health + pull)"
|
||||
fi
|
||||
|
||||
log " Монитор здоровья: $PHOBOS_DIR/phobos-health.sh"
|
||||
log " Failover конфиг: $PHOBOS_DIR/failover.conf"
|
||||
log " Failover конфиг: $A/failover.conf"
|
||||
log " Проверка каждую минуту через cron"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/bin/sh
|
||||
export PATH=/opt/bin:/opt/sbin:/opt/usr/bin:$PATH # cron без /opt/bin -> busybox wget висел вечно (09.29)
|
||||
# ============================================================
|
||||
# Phobos Config Pull — NAT-friendly management channel.
|
||||
# Runs ON the router via cron (every 2 min). OUTBOUND ONLY:
|
||||
@@ -21,9 +22,11 @@
|
||||
# PANEL env or default below -> panel base URL
|
||||
# ============================================================
|
||||
PHOBOS_DIR="/opt/etc/Phobos"
|
||||
CONF="$PHOBOS_DIR/failover.conf"
|
||||
# 02.11.2026: доп. учётки — PHOBOS_ACC=$PHOBOS_DIR/acc/<клиент> (см. phobos-health.sh)
|
||||
ACC_DIR="${PHOBOS_ACC:-$PHOBOS_DIR}"
|
||||
CONF="$ACC_DIR/failover.conf"
|
||||
HEALTH="$PHOBOS_DIR/phobos-health.sh"
|
||||
LOG="$PHOBOS_DIR/health.log"
|
||||
LOG="$ACC_DIR/health.log"
|
||||
# Config sources, tried in order. TUNNEL FIRST: panel_tunnel_ip is the wg0 of
|
||||
# whatever server the tunnel currently terminates on, so management rides the
|
||||
# same obfuscated channel as data — survives a public-IP ban and follows
|
||||
@@ -31,15 +34,18 @@ LOG="$PHOBOS_DIR/health.log"
|
||||
# - panel_tunnel_ip:8444 -> secondary server agent (phobos-api)
|
||||
# - panel_tunnel_ip:<panel_port> -> primary server panel
|
||||
# - public panel IP -> bootstrap / if tunnel is down
|
||||
PANEL_TUNNEL_IP="${PANEL_TUNNEL_IP:-$(cat "$PHOBOS_DIR/panel_tunnel_ip" 2>/dev/null)}"
|
||||
PANEL_TUNNEL_IP="${PANEL_TUNNEL_IP:-$(cat "$ACC_DIR/panel_tunnel_ip" 2>/dev/null)}"
|
||||
[ -n "$PANEL_TUNNEL_IP" ] || PANEL_TUNNEL_IP="10.25.0.1"
|
||||
PANEL="${PANEL:-$(cat "$PHOBOS_DIR/panel_url" 2>/dev/null)}"
|
||||
PANEL_URLS="${PANEL_URLS:-$(cat "$PHOBOS_DIR/panel_urls" 2>/dev/null)}"
|
||||
PANEL="${PANEL:-$(cat "$ACC_DIR/panel_url" 2>/dev/null)}"
|
||||
PANEL_URLS="${PANEL_URLS:-$(cat "$ACC_DIR/panel_urls" 2>/dev/null)}"
|
||||
[ -n "$PANEL_URLS" ] || PANEL_URLS="http://${PANEL_TUNNEL_IP}:8444 $PANEL"
|
||||
CLIENT_ID=$(cat "$PHOBOS_DIR/client_id" 2>/dev/null || echo "home")
|
||||
TOKEN=$(cat "$PHOBOS_DIR/pull_token" 2>/dev/null)
|
||||
TMP="/tmp/failover.conf.pull"
|
||||
LOCK="/tmp/phobos-pull.lock"
|
||||
# + public URLs the panel announced in failover.conf (second IP etc., 09.33)
|
||||
_extra=$(grep "^PANEL_URLS_EXTRA=" "$CONF" 2>/dev/null | cut -d= -f2-)
|
||||
for _u in $_extra; do case " $PANEL_URLS " in *" $_u "*) ;; *) PANEL_URLS="$PANEL_URLS $_u" ;; esac; done
|
||||
CLIENT_ID=$(cat "$ACC_DIR/client_id" 2>/dev/null || echo "home")
|
||||
TOKEN=$(cat "$ACC_DIR/pull_token" 2>/dev/null)
|
||||
TMP="/tmp/failover.conf.pull${PHOBOS_ACC:+-$CLIENT_ID}"
|
||||
LOCK="/tmp/phobos-pull${PHOBOS_ACC:+-$CLIENT_ID}.lock"
|
||||
|
||||
log() { echo "$(date '+%H:%M:%S') $1" >> "$LOG"; }
|
||||
|
||||
@@ -74,8 +80,21 @@ fetch_config() {
|
||||
wget -T 8 --no-check-certificate -q -O "$TMP" "$url" 2>/dev/null || wget -T 8 -q -O "$TMP" "$url" 2>/dev/null
|
||||
}
|
||||
|
||||
# TCP channel for routers (1.5.0): the guard needs /opt/bin/udptcp when failover.conf has TCP_N.
|
||||
ensure_udptcp() {
|
||||
[ -x /opt/bin/udptcp ] && return 0
|
||||
grep -q "^TCP_[0-9]*=" "$CONF" 2>/dev/null || return 0
|
||||
case "$(uname -m)" in aarch64) a=aarch64 ;; mips*) a=mipsel ;; *) return 0 ;; esac
|
||||
command -v curl >/dev/null || return 0
|
||||
{ curl -fsSL -m 30 -o /opt/bin/udptcp.tmp "https://raw.githubusercontent.com/adleibzon-rgb/PCA_Phobos/main/udptcp/bin/udptcp-$a" 2>/dev/null \
|
||||
|| curl -fsSL -m 30 -o /opt/bin/udptcp.tmp "https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/udptcp/bin/udptcp-$a" 2>/dev/null; } \
|
||||
&& [ -s /opt/bin/udptcp.tmp ] && chmod 755 /opt/bin/udptcp.tmp && mv /opt/bin/udptcp.tmp /opt/bin/udptcp \
|
||||
&& log "PULL: udptcp installed ($a)" || rm -f /opt/bin/udptcp.tmp
|
||||
}
|
||||
|
||||
# One fetch + compare + apply pass. Returns 0 always (best-effort).
|
||||
do_pull() {
|
||||
ensure_udptcp
|
||||
# Try each source (tunnel first); accept first that returns a valid conf.
|
||||
got=0
|
||||
for base in $PANEL_URLS; do
|
||||
@@ -113,7 +132,13 @@ apply_obf_params() {
|
||||
D=$(grep "^OBF_MAX_DUMMY=" "$CONF" 2>/dev/null | cut -d= -f2-)
|
||||
I=$(grep "^OBF_IDLE=" "$CONF" 2>/dev/null | cut -d= -f2-)
|
||||
changed=0
|
||||
for OBF in "$PHOBOS_DIR"/wg-obfuscator*.conf; do
|
||||
# только свой обфускатор: у других учёток свои failover.conf
|
||||
own=""
|
||||
for l in "$PHOBOS_DIR"/wg-obfuscator*.link; do
|
||||
[ "$(cat "$l" 2>/dev/null)" = "$CLIENT_ID" ] && own="${l%.link}.conf"
|
||||
done
|
||||
[ -z "$own" ] && [ -z "$PHOBOS_ACC" ] && own="$PHOBOS_DIR/wg-obfuscator*.conf"
|
||||
for OBF in $own; do
|
||||
[ -f "$OBF" ] || continue
|
||||
cur=$(grep "^masking = " "$OBF" 2>/dev/null | sed 's/masking = //')
|
||||
[ "$cur" != "$M" ] && { sed -i "s/^masking = .*/masking = $M/" "$OBF"; changed=1; }
|
||||
@@ -129,7 +154,9 @@ apply_obf_params() {
|
||||
[ "$changed" = 0 ] && return 0
|
||||
log "PULL: obf params applied (masking=$M dummy=${D:-} idle=${I:-}), restart obfuscator"
|
||||
if ls /opt/etc/init.d/S*obfuscator* >/dev/null 2>&1; then
|
||||
for sc in /opt/etc/init.d/S*obfuscator*; do [ -x "$sc" ] && "$sc" restart >/dev/null 2>&1; done
|
||||
for sc in /opt/etc/init.d/S*obfuscator*; do
|
||||
for OBF in $own; do grep -q "/$(basename "$OBF")\"\$" "$sc" && [ -x "$sc" ] && "$sc" restart >/dev/null 2>&1; done
|
||||
done
|
||||
elif command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl restart 'wg-obfuscator*' >/dev/null 2>&1 || true
|
||||
else
|
||||
|
||||
@@ -278,11 +278,21 @@ EOF
|
||||
|
||||
# Настраиваем статический маршрут в созданный интерфейс отдельным вызовом RCI
|
||||
local route_target_net=$(echo "$client_ip_addr" | cut -d'.' -f1-2).0.0
|
||||
log "Настройка маршрута для подсети туннеля (${route_target_net}/16) -> ${interface_name}..."
|
||||
local route_mask="255.255.0.0"
|
||||
# 02.11.2026: доп. учётка (на роутере уже стоит другая): та же /16 через второй
|
||||
# интерфейс конфликтует с главной, а /32 до панели увёл бы pull главной в чужой
|
||||
# туннель — маршрут не ставим, pull доп. учётки ходит по panel_urls.
|
||||
local main_cid=$(cat /opt/etc/Phobos/client_id 2>/dev/null)
|
||||
if [ -n "$main_cid" ] && [ "$main_cid" != "${CLIENT_NAME}" ]; then
|
||||
log "Доп. учётка (главная — ${main_cid}): маршрут подсети туннеля не нужен"
|
||||
log "Интерфейс ${interface_name} создан ✓"
|
||||
return 0
|
||||
fi
|
||||
log "Настройка маршрута для туннеля (${route_target_net}/${route_mask}) -> ${interface_name}..."
|
||||
local route_json=$(cat <<EOF
|
||||
{
|
||||
"network": "${route_target_net}",
|
||||
"mask": "255.255.0.0",
|
||||
"mask": "${route_mask}",
|
||||
"interface": "${interface_name}",
|
||||
"auto": true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user