release: 1.4.0 — one version for stable/beta/dev
Light/dark theme and compact mobile layout, per-client speed limit, real speed tests, panel domain (Let's Encrypt), client address + cascade relay, RKN scanner guard, WARP, backup/restore, router web terminal, Android VPN client with split tunnelling and Android admin app. Updating from 1.2.x keeps keys, server.env and clients; tested 1.2.8 -> 1.4.0 on live VMs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
93
server/phobos-cascade.sh
Executable file
93
server/phobos-cascade.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
# PCA Phobos — cascade relay. Run on an ENTRY VPS (e.g. in Russia, "white" IP):
|
||||
# clients connect to this server, UDP obfuscator ports are forwarded to the EXIT
|
||||
# Phobos server abroad. The entry box needs no Phobos, no keys, no panel.
|
||||
# bash <(curl -fsSL .../server/phobos-cascade.sh) enable <exit_host> [ports]
|
||||
# phobos-cascade.sh disable | status | apply
|
||||
# Then in the exit server panel: Settings -> "Адрес для клиентов" -> entry IP/domain.
|
||||
set -uo pipefail
|
||||
STATE=/etc/phobos-cascade.env
|
||||
BIN=/usr/local/sbin/phobos-cascade
|
||||
SELF_URL="${SELF_URL:-https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/server/phobos-cascade.sh}"
|
||||
TAG="phobos-cascade"
|
||||
|
||||
clear_rules() {
|
||||
local t
|
||||
for t in nat filter; do
|
||||
iptables -t $t -S 2>/dev/null | grep -- "--comment $TAG" | sed 's/^-A /-D /' | \
|
||||
while read -r rule; do eval iptables -t $t $rule 2>/dev/null; done
|
||||
done
|
||||
}
|
||||
|
||||
apply() {
|
||||
[ -f "$STATE" ] || { echo "cascade: not configured"; return 0; }
|
||||
. "$STATE"
|
||||
local ip p
|
||||
ip=$(getent ahostsv4 "$EXIT_HOST" | awk 'NR==1{print $1}')
|
||||
[ -n "$ip" ] || { echo "cascade: cannot resolve $EXIT_HOST" >&2; return 1; }
|
||||
sysctl -qw net.ipv4.ip_forward=1
|
||||
clear_rules
|
||||
for p in ${PORTS//,/ }; do
|
||||
iptables -t nat -A PREROUTING -p udp --dport "$p" -m comment --comment $TAG -j DNAT --to-destination "$ip:$p"
|
||||
iptables -t nat -A POSTROUTING -p udp -d "$ip" --dport "$p" -m comment --comment $TAG -j MASQUERADE
|
||||
iptables -I FORWARD -p udp -d "$ip" --dport "$p" -m comment --comment $TAG -j ACCEPT
|
||||
iptables -I FORWARD -p udp -s "$ip" --sport "$p" -m comment --comment $TAG -j ACCEPT
|
||||
done
|
||||
echo "cascade: udp ${PORTS} -> ${EXIT_HOST} (${ip})"
|
||||
}
|
||||
|
||||
enable() {
|
||||
local host="${1:-}" ports="${2:-2083,5443,993}"
|
||||
[ -n "$host" ] || { echo "usage: $0 enable <exit_host> [ports]" >&2; exit 2; }
|
||||
[[ "$ports" =~ ^[0-9]+(,[0-9]+)*$ ]] || { echo "bad ports: $ports" >&2; exit 2; }
|
||||
command -v iptables >/dev/null || DEBIAN_FRONTEND=noninteractive apt-get install -y -qq iptables >/dev/null
|
||||
printf 'EXIT_HOST=%s\nPORTS=%s\n' "$host" "$ports" > "$STATE"
|
||||
# bash <(curl ...) gives a pipe as $0 -> fetch a real copy for the systemd unit
|
||||
if [ "$(readlink -f "$0")" != "$BIN" ]; then
|
||||
if [ -f "$0" ]; then cp "$0" "$BIN"; else curl -fsSL -m30 "$SELF_URL" -o "$BIN" || { echo "cannot save $BIN" >&2; exit 1; }; fi
|
||||
chmod +x "$BIN"
|
||||
fi
|
||||
cat > /etc/systemd/system/phobos-cascade.service <<EOF
|
||||
[Unit]
|
||||
Description=PCA Phobos cascade relay
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=$BIN apply
|
||||
ExecStop=$BIN stop
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl enable phobos-cascade.service >/dev/null 2>&1
|
||||
systemctl restart phobos-cascade.service
|
||||
apply >/dev/null
|
||||
status
|
||||
}
|
||||
|
||||
disable() {
|
||||
systemctl disable --now phobos-cascade.service >/dev/null 2>&1 || true
|
||||
clear_rules
|
||||
rm -f /etc/systemd/system/phobos-cascade.service "$STATE"
|
||||
systemctl daemon-reload
|
||||
echo "cascade: disabled"
|
||||
}
|
||||
|
||||
status() {
|
||||
local host="" ports="" rules
|
||||
[ -f "$STATE" ] && . "$STATE" && host="$EXIT_HOST" && ports="$PORTS"
|
||||
rules=$(iptables -t nat -S PREROUTING 2>/dev/null | grep -c -- "--comment $TAG")
|
||||
printf '{"enabled": %s, "exit_host": "%s", "ports": "%s", "rules": %s}\n' \
|
||||
"$([ "$rules" -gt 0 ] && echo true || echo false)" "$host" "$ports" "$rules"
|
||||
}
|
||||
|
||||
case "${1:-status}" in
|
||||
enable) enable "${2:-}" "${3:-}" ;;
|
||||
apply) apply ;;
|
||||
stop) clear_rules ;;
|
||||
disable) disable ;;
|
||||
status) status ;;
|
||||
*) echo "usage: $0 enable <exit_host> [ports]|disable|status"; exit 2 ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user