mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
被控端 - 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%) - 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败) - 每分钟回头找局域网,自动切回快 400 倍的路径 - 画面心跳帧:静止时省流量,客户端仍知道流是活的 - 锁屏时给出可操作的提示 手表端 - 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException - 连接错误翻译成人话(证书/时间/解析/超时分别提示) - 经中转连上后用服务器报的地址刷新已配对记录 - 新增局域网连接页面、服务器延迟检测 服务器端 - 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502) - 网络调优脚本 net-tune.sh(开机自动应用) - 管理页:批量删除、网络体检、下载区 - 隧道改 HTTP/2 + 双连接 文档 - 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
141 lines
4.8 KiB
Bash
141 lines
4.8 KiB
Bash
#!/bin/bash
|
||
# 看门狗第三版:两个信号都查。
|
||
#
|
||
# 为什么还要改:
|
||
# 第二版只看 cloudflared 的 ha_connections 指标。
|
||
# 但"僵死连接"会把指标维持在 1 —— 计数还在,实际早断了。
|
||
# 这种时候看门狗以为一切正常,一直不管。
|
||
# (今早就遇到一次:浏览器 1033,指标却说有 1 条连接)
|
||
#
|
||
# 这一版:
|
||
# 信号 A:ha_connections == 0 -> 记一次"零连接"
|
||
# 信号 B:公网 /v1/health 打不通 -> 记一次"公网不通"
|
||
# 任一信号连续 2 次 -> 重启隧道
|
||
# 另外:隧道日志超过 10 分钟没新行 + 公网不通 -> 判定进程卡死,重启
|
||
set -u
|
||
|
||
RELAY_DIR=/root/lanremote-relay
|
||
URL_FILE="$RELAY_DIR/public_url.txt"
|
||
STATE_FILE="$RELAY_DIR/watchdog.state"
|
||
TUNNEL_LOG="$RELAY_DIR/tunnel.log"
|
||
METRICS=http://127.0.0.1:20241/metrics
|
||
LOG_TAG=lanremote-watchdog
|
||
|
||
# 连续几次公网不通才重启。
|
||
# 设 3(约 60 秒)而不是 2:短抖动让 cloudflared 自己重连就好,
|
||
# 频繁重启反而让它一直停在"正在重连"的状态。
|
||
THRESHOLD=3
|
||
STALE_MINUTES=10 # 日志多久没动静算卡死
|
||
# 两次重启之间至少隔这么久(秒)。
|
||
# 实测隧道重建只要 30~40 秒,原来设 120 秒太保守 ——
|
||
# 真断的时候会干等(日志里出现过"距上次重启才 118 秒,先不重启",
|
||
# 结果多断了 2 分钟)。
|
||
# 设 45 秒:既够 cloudflared 把连接建起来,又不会干等太久。
|
||
MIN_RESTART_GAP=45
|
||
|
||
log() {
|
||
logger -t "$LOG_TAG" "$1"
|
||
echo "[$(date '+%m-%d %H:%M:%S')] $1"
|
||
}
|
||
|
||
read_state() {
|
||
local key="$1" default="$2" value=""
|
||
if [ -f "$STATE_FILE" ]; then
|
||
value=$(grep "^$key=" "$STATE_FILE" 2>/dev/null | cut -d= -f2)
|
||
fi
|
||
[ -n "$value" ] && echo "$value" || echo "$default"
|
||
}
|
||
|
||
write_state() { printf 'zero=%s\nfail=%s\n' "$1" "$2" > "$STATE_FILE"; }
|
||
|
||
LAST_RESTART_FILE="$RELAY_DIR/watchdog.last_restart"
|
||
|
||
restart_tunnel() {
|
||
local why="$1"
|
||
local now last gap
|
||
now=$(date +%s)
|
||
last=0
|
||
[ -f "$LAST_RESTART_FILE" ] && last=$(cat "$LAST_RESTART_FILE" 2>/dev/null || echo 0)
|
||
gap=$((now - last))
|
||
|
||
# 连接数归零 = 真的断了,不是抖动 —— 这种不受间隔限制
|
||
local conns_now
|
||
conns_now=$(timeout 5 curl -s --max-time 4 "$METRICS" 2>/dev/null \
|
||
| grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}')
|
||
if [ "${conns_now:-1}" != "0" ] && [ "$gap" -lt "$MIN_RESTART_GAP" ]; then
|
||
# 刚重启过还没到间隔:这次先不重启,
|
||
# 让 cloudflared 自己把连接建起来(它本来就在重试)。
|
||
log "$why —— 但距上次重启才 ${gap} 秒(下限 ${MIN_RESTART_GAP} 秒),先不重启"
|
||
write_state 0 0
|
||
exit 0
|
||
fi
|
||
|
||
log "$why —— 重启隧道(距上次 ${gap} 秒)"
|
||
echo "$now" > "$LAST_RESTART_FILE"
|
||
systemctl restart lanremote-tunnel
|
||
write_state 0 0
|
||
sleep 25
|
||
log "重启后地址: $(cat "$URL_FILE" 2>/dev/null || echo '(还没拿到)')"
|
||
exit 0
|
||
}
|
||
|
||
ZERO=$(read_state zero 0)
|
||
FAIL=$(read_state fail 0)
|
||
|
||
# ---------- 信号 A:cloudflared 自报的连接数 ----------
|
||
CONNS=$(timeout 5 curl -s --max-time 4 "$METRICS" 2>/dev/null \
|
||
| grep '^cloudflared_tunnel_ha_connections' | awk '{print $2}')
|
||
[ -z "$CONNS" ] && CONNS=""
|
||
|
||
# ---------- 信号 B:公网真的通吗 ----------
|
||
URL=$(cat "$URL_FILE" 2>/dev/null | tr -d '\r\n')
|
||
CODE="000"
|
||
if [ -n "$URL" ]; then
|
||
CODE=$(timeout 20 curl -4 -s -o /dev/null -w '%{http_code}' \
|
||
-H 'User-Agent: LanRemote/1.4.0' "$URL/v1/health" 2>/dev/null)
|
||
CODE=${CODE:-000}
|
||
fi
|
||
PUBLIC_OK=0
|
||
[ "$CODE" = "200" ] && PUBLIC_OK=1
|
||
|
||
# ---------- 信号 C:日志僵死了吗 ----------
|
||
LOG_STALE=0
|
||
if [ -f "$TUNNEL_LOG" ]; then
|
||
LAST=$(stat -c %Y "$TUNNEL_LOG" 2>/dev/null || echo 0)
|
||
NOW=$(date +%s)
|
||
if [ "$LAST" -gt 0 ] && [ $((NOW - LAST)) -gt $((STALE_MINUTES * 60)) ]; then
|
||
LOG_STALE=1
|
||
fi
|
||
fi
|
||
|
||
# ---------- 判断 ----------
|
||
if [ "$PUBLIC_OK" = "1" ]; then
|
||
# 公网通就是真的通,计数器清零
|
||
if [ "$ZERO" != "0" ] || [ "$FAIL" != "0" ]; then
|
||
log "公网恢复(HTTP 200),计数清零(之前 zero=$ZERO fail=$FAIL)"
|
||
fi
|
||
write_state 0 0
|
||
exit 0
|
||
fi
|
||
|
||
# 公网不通 —— 看是哪种原因
|
||
DETAIL="HTTP $CODE"
|
||
[ -n "$CONNS" ] && DETAIL="$DETAIL,ha_connections=$CONNS"
|
||
|
||
if [ "$LOG_STALE" = "1" ] && [ "$FAIL" -ge 1 ]; then
|
||
restart_tunnel "日志 ${STALE_MINUTES} 分钟没动静加上公网不通(进程卡死)"
|
||
fi
|
||
|
||
FAIL=$((FAIL + 1))
|
||
if [ -n "$CONNS" ] && [ "$CONNS" = "0" ]; then
|
||
ZERO=$((ZERO + 1))
|
||
fi
|
||
|
||
log "公网不通($DETAIL),连续第 $FAIL 次(零连接 $ZERO 次)"
|
||
|
||
if [ "$FAIL" -ge "$THRESHOLD" ] || [ "$ZERO" -ge "$THRESHOLD" ]; then
|
||
restart_tunnel "连续 $FAIL 次公网不通(含 $ZERO 次零连接)"
|
||
fi
|
||
|
||
write_state "$ZERO" "$FAIL"
|