watchdog: 云端健康检查改 sshd banner 探测(TCP 握手是假阳性——黑洞特征 TCP 开但应用断, 会误拉 L2 劫持到死通道); 云端不可达自动撤 L2 规则并停 proxy, 只保 L1
This commit is contained in:
+71
-29
@@ -2,20 +2,37 @@
|
||||
# 伪装器看门狗(网关侧)
|
||||
# 每 3 分钟由 crond 调用; 正常时静默, 异常自愈并写日志
|
||||
# 幂等: 所有动作先查已有实例/规则, 绝不重复拉起
|
||||
# 可调: BASE_DIR / WAN_IF / LAN_IF / QUEUE / 端口
|
||||
# 可调: BASE_DIR / WAN_IF / LAN_IF / QUEUE / 端口 / CHANNEL_HOST
|
||||
BASE_DIR=${BASE_DIR:-/opt/masquerader}
|
||||
WAN_IF=${WAN_IF:-eth0}
|
||||
LAN_IF=${LAN_IF:-br-lan}
|
||||
QUEUE=100
|
||||
HTTP_PORT=8080
|
||||
DNS_PORT=8053
|
||||
CHANNEL_HOST=${CHANNEL_HOST:-8.136.202.225} # 云服务器(部署时改为真实地址)
|
||||
CHANNEL_PORT=${CHANNEL_PORT:-8444}
|
||||
LOG=/tmp/watchdog.log
|
||||
ts() { date '+%F %T'; }
|
||||
log() { echo "$(ts) $1" >> "$LOG"; }
|
||||
|
||||
# ── 通道健康检查(云端 OS 活着才允许 L2 存在) ──
|
||||
# 判据: sshd banner 可读 = 云端 OS 正常响应
|
||||
# (黑洞/宕机特征: TCP 握手成功但 banner 读不到 - 单纯测 TCP 是假阳性!)
|
||||
cloud_up() {
|
||||
python3 -c "
|
||||
import socket,sys
|
||||
try:
|
||||
s = socket.create_connection(('$CHANNEL_HOST', 22), timeout=3)
|
||||
s.settimeout(2)
|
||||
b = s.recv(64)
|
||||
sys.exit(0 if b.startswith(b'SSH-') else 1)
|
||||
except Exception:
|
||||
sys.exit(1)"
|
||||
}
|
||||
|
||||
need_restart=0
|
||||
|
||||
# ── L1: worker 进程 ──
|
||||
# ── L1: worker 进程(不依赖云端, 始终保活) ──
|
||||
if [ -z "$(ps w | grep '[m]asquerader.worker')" ]; then
|
||||
log "worker 不在, 拉起"
|
||||
cd "${BASE_DIR}" || exit 1
|
||||
@@ -27,20 +44,43 @@ if [ -z "$(ps w | grep '[m]asquerader.worker')" ]; then
|
||||
need_restart=1
|
||||
fi
|
||||
|
||||
# ── L2: proxy 进程 ──
|
||||
if [ -z "$(ps w | grep '[c]hannel.proxy_http')" ]; then
|
||||
log "proxy_http 不在, 拉起"
|
||||
cd "${BASE_DIR}" || exit 1
|
||||
setsid python3 -u -m channel.proxy_http config/channel.json \
|
||||
> /tmp/proxy_http.log 2>&1 < /dev/null &
|
||||
need_restart=1
|
||||
fi
|
||||
if [ -z "$(ps w | grep '[c]hannel.proxy_dns')" ]; then
|
||||
log "proxy_dns 不在, 拉起"
|
||||
cd "${BASE_DIR}" || exit 1
|
||||
setsid python3 -u -m channel.proxy_dns config/channel.json \
|
||||
> /tmp/proxy_dns.log 2>&1 < /dev/null &
|
||||
need_restart=1
|
||||
# ── L2: 仅当云端可达时保活 proxy 与套壳规则 ──
|
||||
if cloud_up; then
|
||||
if [ -z "$(ps w | grep '[c]hannel.proxy_http')" ]; then
|
||||
log "proxy_http 不在, 拉起"
|
||||
cd "${BASE_DIR}" || exit 1
|
||||
setsid python3 -u -m channel.proxy_http config/channel.json \
|
||||
> /tmp/proxy_http.log 2>&1 < /dev/null &
|
||||
need_restart=1
|
||||
fi
|
||||
if [ -z "$(ps w | grep '[c]hannel.proxy_dns')" ]; then
|
||||
log "proxy_dns 不在, 拉起"
|
||||
cd "${BASE_DIR}" || exit 1
|
||||
setsid python3 -u -m channel.proxy_dns config/channel.json \
|
||||
> /tmp/proxy_dns.log 2>&1 < /dev/null &
|
||||
need_restart=1
|
||||
fi
|
||||
else
|
||||
# 云端不可达: 撤掉 L2 劫持规则并停 proxy(否则流量被劫到死通道)
|
||||
if iptables -t nat -C PREROUTING -i "$LAN_IF" -p tcp --dport 80 \
|
||||
-j REDIRECT --to-ports "$HTTP_PORT" 2>/dev/null; then
|
||||
log "云端不可达, 撤 L2 HTTP 规则"
|
||||
iptables -t nat -D PREROUTING -i "$LAN_IF" -p tcp --dport 80 \
|
||||
-j REDIRECT --to-ports "$HTTP_PORT" 2>/dev/null
|
||||
fi
|
||||
if iptables -t nat -C PREROUTING -i "$LAN_IF" -p udp --dport 53 \
|
||||
-j REDIRECT --to-ports "$DNS_PORT" 2>/dev/null; then
|
||||
log "云端不可达, 撤 L2 DNS 规则"
|
||||
iptables -t nat -D PREROUTING -i "$LAN_IF" -p udp --dport 53 \
|
||||
-j REDIRECT --to-ports "$DNS_PORT" 2>/dev/null
|
||||
fi
|
||||
for P in proxy_http proxy_dns; do
|
||||
PID=$(ps w | grep "[c]hannel.$P" | awk '{print $1}' | head -1)
|
||||
if [ -n "$PID" ]; then
|
||||
log "云端不可达, 停 $P($PID)"
|
||||
kill "$PID" 2>/dev/null
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ── 规则自愈(进程刚拉起时挂规则可能抢跑, 统一延迟统一挂) ──
|
||||
@@ -54,20 +94,22 @@ if ! iptables -t mangle -C FORWARD -o "$WAN_IF" -p tcp --syn \
|
||||
-j NFQUEUE --queue-num "$QUEUE" --queue-bypass 2>/dev/null
|
||||
fi
|
||||
|
||||
# L2 HTTP 套壳规则(只劫 LAN 入站)
|
||||
if ! iptables -t nat -C PREROUTING -i "$LAN_IF" -p tcp --dport 80 \
|
||||
-j REDIRECT --to-ports "$HTTP_PORT" 2>/dev/null; then
|
||||
log "L2 HTTP 规则缺失, 重挂"
|
||||
iptables -t nat -A PREROUTING -i "$LAN_IF" -p tcp --dport 80 \
|
||||
-j REDIRECT --to-ports "$HTTP_PORT" 2>/dev/null
|
||||
# L2 HTTP 套壳规则(仅云端可达且已拉 proxy 时挂)
|
||||
if cloud_up && [ -n "$(ps w | grep '[c]hannel.proxy_http')" ]; then
|
||||
if ! iptables -t nat -C PREROUTING -i "$LAN_IF" -p tcp --dport 80 \
|
||||
-j REDIRECT --to-ports "$HTTP_PORT" 2>/dev/null; then
|
||||
log "L2 HTTP 规则缺失, 重挂"
|
||||
iptables -t nat -A PREROUTING -i "$LAN_IF" -p tcp --dport 80 \
|
||||
-j REDIRECT --to-ports "$HTTP_PORT" 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
# L2 DNS 套壳规则
|
||||
if ! iptables -t nat -C PREROUTING -i "$LAN_IF" -p udp --dport 53 \
|
||||
-j REDIRECT --to-ports "$DNS_PORT" 2>/dev/null; then
|
||||
log "L2 DNS 规则缺失, 重挂"
|
||||
iptables -t nat -A PREROUTING -i "$LAN_IF" -p udp --dport 53 \
|
||||
-j REDIRECT --to-ports "$DNS_PORT" 2>/dev/null
|
||||
if cloud_up && [ -n "$(ps w | grep '[c]hannel.proxy_dns')" ]; then
|
||||
if ! iptables -t nat -C PREROUTING -i "$LAN_IF" -p udp --dport 53 \
|
||||
-j REDIRECT --to-ports "$DNS_PORT" 2>/dev/null; then
|
||||
log "L2 DNS 规则缺失, 重挂"
|
||||
iptables -t nat -A PREROUTING -i "$LAN_IF" -p udp --dport 53 \
|
||||
-j REDIRECT --to-ports "$DNS_PORT" 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user