Files
lou b55c0cb7bb 开源化: MIT LICENSE + 详细 README + deploy/watchdog + 全仓脱敏(云服IP/学校域/凭据 → RFC5737 占位)
- LICENSE: MIT © 2026 edgevoid
- README: 三层架构/逐字段伪装对照/部署/验证/安全边界/看门狗自启
- 脱敏(filter-repo 全历史): 8.136.202.225→203.0.113.10, .zjipc.cn→.internal.example, 学校DNS→192.0.2.53
- hook.sh 更新为安全形态(FORWARD-only 绑 WAN, 去掉 OUTPUT 全挂断网形态)
- router_deploy.sh: SSHPASS 改环境变量注入(明文密码清除)
- watchdog.sh 纳入 deploy/(接口变量化)
- 内部语境泛化(认证网关/学校DNS/寝室部署备注)
2026-09-09 18:14:10 +08:00

98 lines
4.3 KiB
Bash

#!/bin/sh
# vpn 回环伪装器一键起停(软路由 /opt/masquerader/ctl.sh)
# 用法: sh ctl.sh {start|stop|restart|status} [all|l1|l2]
# 默认 all: L1(worker+SYN规则) + L2(proxy_http/proxy_dns+套壳规则)
# l1/l2: 分层控制(安全梯度: L1 伪装 > L2-http 套壳 > L2-dns)
# 铁律: 规则全部带 --queue-bypass / 只劫 br-lan 入站; 本机 OUTPUT 零规则
# 手动控制(默认不自动启动)。开机自启: /etc/rc.local 加
# (sleep 30 && sh /opt/masquerader/ctl.sh start) &
QUEUE=100
PRELOAD=/usr/lib/libnfnetlink.so.0
WAN_IF=eth1
LAN_IF=br-lan
CFG=/opt/masquerader/config/channel.json
start_worker() {
if [ -z "$(ps w | grep '[m]asquerader.worker')" ]; then
cd /opt/masquerader || exit 1
LD_PRELOAD=$PRELOAD setsid python3 -u -m masquerader.worker \
config/masquerader.json > /tmp/worker.log 2>&1 < /dev/null &
sleep 2
head -2 /tmp/worker.log
else
echo "worker 已在运行"
fi
}
start_proxies() {
cd /opt/masquerader || exit 1
if [ -z "$(ps w | grep '[c]hannel.proxy_http')" ]; then
setsid python3 -u -m channel.proxy_http "$CFG" > /tmp/proxy_http.log 2>&1 < /dev/null &
fi
if [ -z "$(ps w | grep '[c]hannel.proxy_dns')" ]; then
setsid python3 -u -m channel.proxy_dns "$CFG" > /tmp/proxy_dns.log 2>&1 < /dev/null &
fi
sleep 2
echo "[proxy_http] $(head -1 /tmp/proxy_http.log)"
echo "[proxy_dns] $(head -1 /tmp/proxy_dns.log)"
}
start() {
MODE=${2:-all}
# 规则(幂等: 先删后加)。FORWARD-only 伪装 + PREROUTING 只劫 LAN 入站
[ "$MODE" = all ] || [ "$MODE" = l1 ] && {
start_worker
iptables -t mangle -D FORWARD -o $WAN_IF -p tcp --syn -j NFQUEUE --queue-num $QUEUE --queue-bypass 2>/dev/null
iptables -t mangle -A FORWARD -o $WAN_IF -p tcp --syn -j NFQUEUE --queue-num $QUEUE --queue-bypass
echo "[L1] SYN 伪装规则 -> NFQUEUE $QUEUE (bypass)"
}
[ "$MODE" = all ] || [ "$MODE" = l2 ] && {
start_proxies
iptables -t nat -D PREROUTING -i $LAN_IF -p tcp --dport 80 -j REDIRECT --to-ports 8080 2>/dev/null
iptables -t nat -A PREROUTING -i $LAN_IF -p tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -D PREROUTING -i $LAN_IF -p udp --dport 53 -j REDIRECT --to-ports 8053 2>/dev/null
iptables -t nat -A PREROUTING -i $LAN_IF -p udp --dport 53 -j REDIRECT --to-ports 8053
echo "[L2] HTTP->8080 / DNS->8053 套壳规则(仅 $LAN_IF 入站)"
}
}
stop() {
MODE=${2:-all}
# 先撤规则再杀进程 —— 保证杀进程窗口期不悬挂(bypass/直连兜底)
[ "$MODE" = all ] || [ "$MODE" = l2 ] && {
iptables -t nat -D PREROUTING -i $LAN_IF -p tcp --dport 80 -j REDIRECT --to-ports 8080 2>/dev/null
iptables -t nat -D PREROUTING -i $LAN_IF -p udp --dport 53 -j REDIRECT --to-ports 8053 2>/dev/null
echo "[L2] 套壳规则已撤"
for P in proxy_http proxy_dns; do
PID=$(ps w | grep "[c]hannel.$P" | awk '{print $1}' | head -1)
[ -n "$PID" ] && kill "$PID" 2>/dev/null && echo "$P($PID) 已停"
done
}
[ "$MODE" = all ] || [ "$MODE" = l1 ] && {
iptables -t mangle -D FORWARD -o $WAN_IF -p tcp --syn -j NFQUEUE --queue-num $QUEUE --queue-bypass 2>/dev/null
echo "[L1] SYN 规则已撤(bypass 放行)"
PID=$(ps w | grep '[m]asquerader.worker' | awk '{print $1}' | head -1)
[ -n "$PID" ] && kill "$PID" 2>/dev/null && echo "worker($PID) 已停"
}
}
status() {
echo "=== L1 伪装 ==="
ps w | grep '[m]asquerader.worker' | head -1 || echo " worker: 未运行"
iptables -t mangle -S FORWARD | grep -q NFQUEUE && echo " SYN 规则: 在" || echo " SYN 规则: 无"
echo "=== L2 套壳 ==="
ps w | grep '[c]hannel.proxy_http' | head -1 || echo " proxy_http: 未运行"
ps w | grep '[c]hannel.proxy_dns' | head -1 || echo " proxy_dns: 未运行"
iptables -t nat -S PREROUTING | grep -q "dport 80" && echo " HTTP 规则: 在" || echo " HTTP 规则: 无"
iptables -t nat -S PREROUTING | grep -q "dport 53" && echo " DNS 规则: 在" || echo " DNS 规则: 无"
}
case "$1" in
start) start "$@" ;;
stop) stop "$@" ;;
restart) stop "$@" 2>/dev/null; sleep 1; start "$@" ;;
status) status ;;
*) echo "用法: sh $0 {start|stop|restart|status} [all|l1|l2]"; exit 1 ;;
esac