From 21112796d011b9de6d55528b14f66ad8e1e836b1 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 06:48:33 +0000 Subject: [PATCH] =?UTF-8?q?fix(core):=20=E5=85=BC=E5=AE=B9=E6=80=A7?= =?UTF-8?q?=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/agent_daemon.sh | 39 +++++++++++++++------------- core/install.sh | 31 ++++++++++++----------- master/tg_master.sh | 60 ++++++++++++++++++++++++++++---------------- 3 files changed, 76 insertions(+), 54 deletions(-) diff --git a/core/agent_daemon.sh b/core/agent_daemon.sh index ffd4b081..e489a812 100755 --- a/core/agent_daemon.sh +++ b/core/agent_daemon.sh @@ -484,27 +484,30 @@ import socket # ---------------------------------------------------------- # [核心架构] 多线程非阻塞 Socket 模型 (抵抗 Slowloris 及阻塞攻击) # ---------------------------------------------------------- -class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer): +class DualStackServer(socketserver.ThreadingMixIn, socketserver.TCPServer): allow_reuse_address = True + def server_bind(self): + # 强行解除 IPv6 独占锁,实现一个 Socket 同时接管 IPv4 和 IPv6 (全域防漏接) + if self.address_family == socket.AF_INET6: + try: + self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) + except Exception: + pass + super().server_bind() -# [v4.2.0 战术重构] 双轨通讯分离架构探底 -# Python 引擎彻底脱离养护 IP 的干扰,绝对服从 COMM_IP (专线通讯) 的协议栈维度 -bind_addr = "0.0.0.0" -address_family = socket.AF_INET +# [v4.2.2 终极架构] 彻底抛弃配置文件的 IP 束缚,强行探测系统底层的双栈能力 +bind_addr = "::" +address_family = socket.AF_INET6 +try: + # 探针:如果机器是纯 IPv4 (连 v6 模块都没有),强绑 :: 会崩溃,自动降维 + s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + s.close() +except OSError: + bind_addr = "0.0.0.0" + address_family = socket.AF_INET -config_path = '/opt/ip_sentinel/config.conf' -if os.path.exists(config_path): - with open(config_path, 'r', errors='ignore') as f: - for line in f: - if line.startswith('COMM_IP='): - comm_ip = line.split('=', 1)[1].strip('"\'') - if ':' in comm_ip: - bind_addr = "::" - address_family = socket.AF_INET6 - break - -ThreadedServer.address_family = address_family -httpd = ThreadedServer((bind_addr, PORT), AgentHandler) +DualStackServer.address_family = address_family +httpd = DualStackServer((bind_addr, PORT), AgentHandler) # ---------------------------------------------------------- # [加密通信] 强制全网挂载 TLS 加密隧道上下文 diff --git a/core/install.sh b/core/install.sh index 444d22d8..8bf436c5 100755 --- a/core/install.sh +++ b/core/install.sh @@ -488,24 +488,27 @@ if [ "$UPGRADE_MODE" == "false" ]; then SAFE_PUBLIC_IP="$PUBLIC_IP" fi - COMM_IP="$PUBLIC_IP" - if [[ "$PUBLIC_IP" == *":"* ]]; then - echo -e "\n\033[36m[4.6/7] 正在构建双轨通讯分离架构 (Control Plane Separation)...\033[0m" - echo -e " \033[33m⚠️ 检测到养护锚点为 IPv6,正在嗅探本机 IPv4 以构建防 MTU 黑洞通讯专线...\033[0m" - - if [[ -n "$DETECT_V4" ]]; then - COMM_IP="$DETECT_V4" - echo -e " \033[32m✅ 成功建立双轨架构: 养护数据流走 IPv6 ($PUBLIC_IP),中枢控制流走 IPv4 ($COMM_IP)\033[0m" - else - echo -e " \033[33m⚠️ 本机无公网 IPv4 或检测到 WARP/NAT 伪装 IP,为防阻断,双轨已安全降级为纯 IPv6 单轨模式。\033[0m" - fi + # ========================================================== + # [v4.2.2 终极架构] 智能主副容灾弹药装填 (Multi-IP Fallback) + # 不再纠结内网阻断,直接将所有存活 IP 以逗号拼接上报司令部,由司令部执行降级回退打击 + # ========================================================== + echo -e "\n\033[36m[4.6/7] 正在装填通讯容灾防线 (Multi-IP Fallback)...\033[0m" + COMM_IP="$SAFE_PUBLIC_IP" + FALLBACK_IP="" + + if [ "${IP_PREF}" == "6" ] && [ -n "$DETECT_V4" ]; then + FALLBACK_IP="$DETECT_V4" + elif [ "${IP_PREF}" == "4" ] && [ -n "$DETECT_V6" ]; then + [[ "$DETECT_V6" != *"["* ]] && FALLBACK_IP="[${DETECT_V6}]" || FALLBACK_IP="$DETECT_V6" fi - if [[ "$COMM_IP" == *":"* ]] && [[ "$COMM_IP" != *"["* ]]; then - SAFE_COMM_IP="[${COMM_IP}]" + if [ -n "$FALLBACK_IP" ]; then + COMM_IP="${COMM_IP},${FALLBACK_IP}" + echo -e " \033[32m✅ 成功建立双向容灾通讯专线: 主通道 $SAFE_PUBLIC_IP,备用通道 $FALLBACK_IP\033[0m" else - SAFE_COMM_IP="$COMM_IP" + echo -e " \033[33m⚠️ 暂无可用备用公网 IP,建立单轨通讯模式: $SAFE_PUBLIC_IP\033[0m" fi + SAFE_COMM_IP="$COMM_IP" echo -n "🕵️ 正在进行出站链路试射 (NAT环境与双栈嗅探)..." RAW_TEST_IP=$(echo "$SAFE_PUBLIC_IP" | tr -d '[]') diff --git a/master/tg_master.sh b/master/tg_master.sh index 171d3d86..21e5aa09 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -76,7 +76,36 @@ generate_signed_url() { local current_t=$(date +%s) local payload="${action_path}:${current_t}" - # [v4.1.7 致命修复] 弃用 -hmac,改用 -macopt 标准语法,彻底杜绝 TG 群组负数 ID 导致的 OpenSSL 参数注入崩溃 + +# ========================================================== +# [新增插入] v4.2.2 终极容灾火力网:自动解析多宿主 IP 并执行无缝降级重试 +# ========================================================== +call_agent() { + local ips="$1" + local port="$2" + local path="$3" + local suffix="$4" + local res="FAILED" + + # 拆解逗号分隔的 IP 列阵 (例如: [2a0b:...],66.181.x.x) + IFS=',' read -r -a ip_array <<< "$ips" + for ip in "${ip_array[@]}"; do + if [ -n "$ip" ]; then + local url=$(generate_signed_url "$ip" "$port" "$path") + [ -n "$suffix" ] && url="${url}${suffix}" + + # 缩短单次重试时间,实现用户无感知的秒级降级切换 + res=$(curl -k -s --connect-timeout 4 -m 12 "$url" || echo "FAILED") + if [ "$res" != "FAILED" ] && [ -n "$res" ]; then + echo "$res" + return + fi + fi + done + echo "FAILED" +} + +# [v4.1.7 致命修复] 弃用 -hmac,改用 -macopt 标准语法,彻底杜绝 TG 群组负数 ID 导致的 OpenSSL 参数注入崩溃 local signature=$(echo -n "$payload" | openssl dgst -sha256 -mac HMAC -macopt key:"$CHAT_ID" | awk '{print $NF}') echo "https://${target_ip}:${target_port}${action_path}?t=${current_t}&sign=${signature}" @@ -298,8 +327,7 @@ while true; do else send_msg "$CHAT_ID" "📢 **司令部指令下达:正在唤醒全舰队执行 OTA 升级...**%0A*(节点升级成功后会主动发回新的入库确认,请注意查收)*" echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do - TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_ota") - curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" > /dev/null & + call_agent "$AIP" "$APORT" "/trigger_ota" > /dev/null & sleep 0.3 done fi @@ -353,8 +381,7 @@ while true; do else send_msg "$CHAT_ID" "📢 **司令部指令下达:正在召唤所有哨兵回传简报...**%0A*(为防止触发 TG 官方限流,简报将排队依次送达,请耐心等待)*" echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do - TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_report") - curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" > /dev/null & + call_agent "$AIP" "$APORT" "/trigger_report" > /dev/null & sleep 2 done fi @@ -367,8 +394,7 @@ while true; do else send_msg "$CHAT_ID" "📢 **司令部指令下达:正在唤醒所有哨兵执行系统维护...**" echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do - TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_run") - curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" > /dev/null & + call_agent "$AIP" "$APORT" "/trigger_run" > /dev/null & sleep 0.2 done fi @@ -389,8 +415,7 @@ while true; do if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [quality] 指令,请稍候..." - TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_quality") - RESPONSE=$(curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" || echo "FAILED") + RESPONSE=$(call_agent "$AGENT_IP" "$AGENT_PORT" "/trigger_quality") if [ "$RESPONSE" == "FAILED" ]; then send_msg "$CHAT_ID" "❌ 指令下发超时或失败!请检查节点公网 IP 或防火墙端口 ($AGENT_PORT) 是否放行。" @@ -540,10 +565,7 @@ while true; do AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2) if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then - TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_toggle") - TARGET_URL="${TARGET_URL}&mod=${MOD_NAME}&state=${TARGET_STATE}" - - RESPONSE=$(curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" || echo "FAILED") + RESPONSE=$(call_agent "$AGENT_IP" "$AGENT_PORT" "/trigger_toggle" "&mod=${MOD_NAME}&state=${TARGET_STATE}") if [[ "$RESPONSE" == *"Action Accepted"* ]]; then db_exec "UPDATE nodes SET enable_${MOD_NAME}='$TARGET_STATE' WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE';" @@ -635,13 +657,9 @@ while true; do if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` 下发重命名指令,正在建立加密隧道..." - TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_rename") - # [防线穿越] 借由 Base64 编码对下发特征进行混淆与防篡改护甲加持 ALIAS_B64=$(echo -n "$NEW_ALIAS" | base64 | tr -d '\n' | tr '+/' '-_') - TARGET_URL="${TARGET_URL}&b64=${ALIAS_B64}" - - RESPONSE=$(curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" || echo "FAILED") + RESPONSE=$(call_agent "$AGENT_IP" "$AGENT_PORT" "/trigger_rename" "&b64=${ALIAS_B64}") if [ "$RESPONSE" == "FAILED" ]; then send_msg "$CHAT_ID" "❌ 指令下发超时!为防范劫持风险,已终止请求。" @@ -677,8 +695,7 @@ while true; do send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` 发送 OTA 触发报文..." fi - TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_ota") - RESPONSE=$(curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" || echo "FAILED") + RESPONSE=$(call_agent "$AGENT_IP" "$AGENT_PORT" "/trigger_ota") if [ "$RESPONSE" == "FAILED" ]; then TEXT_RES="❌ OTA 指令下发彻底失败!链路异常或严禁使用 HTTP 降级通讯。" @@ -714,8 +731,7 @@ while true; do send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [$ACTION_TYPE] 指令,请稍候..." fi - TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_${ACTION_TYPE}") - RESPONSE=$(curl -k -s --connect-timeout 5 -m 15 "$TARGET_URL" || echo "FAILED") + RESPONSE=$(call_agent "$AGENT_IP" "$AGENT_PORT" "/trigger_${ACTION_TYPE}") if [ "$RESPONSE" == "FAILED" ]; then TEXT_RES="❌ 指令下发超时或失败!为保护链路安全,已终止通信 (严禁降级为 HTTP)。"