From f218291720d5b32b7916329ca479655749ba3068 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 07:47:18 +0000 Subject: [PATCH 01/10] =?UTF-8?q?feat(arch):=20=E8=B7=83=E5=8D=87=20v4.2.2?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E6=9E=84=E6=8E=A7=E5=88=B6=E9=9D=A2=E9=80=9A?= =?UTF-8?q?=E8=AE=AF=E9=93=BE=E8=B7=AF=EF=BC=8C=E5=BC=95=E5=85=A5=E3=80=8C?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=A4=9A=E5=AE=BF=E4=B8=BB=E5=AE=B9?= =?UTF-8?q?=E7=81=BE=E5=AF=BB=E5=9D=80=20(Multi-homing=20Fallback)?= =?UTF-8?q?=E3=80=8D=E6=9C=BA=E5=88=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E5=85=A8?= =?UTF-8?q?=E5=9F=9F=E5=8F=8C=E6=A0=88=E7=9B=91=E5=90=AC=E4=B8=8E=E6=AF=AB?= =?UTF-8?q?=E7=A7=92=E7=BA=A7=E9=98=B2=E9=BB=91=E6=B4=9E=E9=87=8D=E8=AF=95?= =?UTF-8?q?=E6=89=93=E5=87=BB=EF=BC=8C=E5=BD=BB=E5=BA=95=E5=85=8D=E7=96=AB?= =?UTF-8?q?=E7=BA=AF=20IPv6=E3=80=81LXC=E3=80=81=E5=A4=A7=E5=86=85?= =?UTF-8?q?=E7=BD=91=20WARP=20=E7=AD=89=E9=AB=98=E5=8D=B1=E9=98=BB?= =?UTF-8?q?=E6=96=AD=E5=9C=BA=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/agent_daemon.sh | 56 +++++++++++++------ core/install.sh | 124 +++++++++++++++++++++++++++++++++++++++---- master/tg_master.sh | 62 +++++++++++++--------- 3 files changed, 189 insertions(+), 53 deletions(-) diff --git a/core/agent_daemon.sh b/core/agent_daemon.sh index e4a327d9..9945bf8a 100755 --- a/core/agent_daemon.sh +++ b/core/agent_daemon.sh @@ -55,21 +55,29 @@ if [ -n "$AGENT_IP" ]; then fi fi -# [v4.1.8 核心修复] 彻底解决 IPv6 致命耳聋漏洞 (Socket Binding Mismatch) -# 在拉起 Python 引擎前,由 Bash 强行锁定底层网络栈监听维度,抛弃脆弱的内部解析 -if [[ "$AGENT_IP" == *":"* ]]; then - export BIND_ADDR="::" - echo "🌐 [Agent] 协议栈识别: 侦测到 IPv6 基因,底层路由强锁定至 [::]" -else - export BIND_ADDR="0.0.0.0" - echo "🌐 [Agent] 协议栈识别: 侦测到 IPv4 基因,底层路由强锁定至 0.0.0.0" -fi +# [v4.2.2 终极架构] 彻底剥离 Bash 对底层网络栈的干预,将控制权全权移交 Python 全域引擎 +echo "🌐 [Agent] 底层网络栈已解锁,准备切入全域双栈监听模式 (Dual-Stack Universal Bind)" # ========================================================== # [加密通信] 强制构建自签名 TLS 装甲,屏蔽中间人嗅探 # ========================================================== CERT_FILE="${INSTALL_DIR}/core/cert.pem" KEY_FILE="${INSTALL_DIR}/core/key.pem" + +# [v4.2.2 热修复] 检查证书是否过于陈旧,若是则强制销毁重铸 (保障平滑升级的 TLS 健康) +if [ -f "$CERT_FILE" ]; then + CERT_DATE=$(openssl x509 -noout -startdate -in "$CERT_FILE" 2>/dev/null | cut -d= -f2) + if [[ -n "$CERT_DATE" ]]; then + CERT_EPOCH=$(date -d "$CERT_DATE" +%s 2>/dev/null || echo 0) + V422_EPOCH=$(date -d "2026-05-31" +%s 2>/dev/null || echo 1780185600) + if [ "$CERT_EPOCH" -lt "$V422_EPOCH" ]; then + echo "🧹 [Agent] 侦测到旧版 (v4.2.2 前) 遗留 TLS 装甲,正在执行强制物理销毁..." + rm -f "$CERT_FILE" "$KEY_FILE" + fi + fi +fi +CERT_FILE="${INSTALL_DIR}/core/cert.pem" +KEY_FILE="${INSTALL_DIR}/core/key.pem" if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then echo "🔐 [Agent] 正在生成本地自签名 TLS 加密证书 (2048位 RSA)..." openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ @@ -479,17 +487,31 @@ import socket # ---------------------------------------------------------- # [核心架构] 多线程非阻塞 Socket 模型 (抵抗 Slowloris 及阻塞攻击) # ---------------------------------------------------------- -class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer): +class DualStackServer(socketserver.ThreadingMixIn, socketserver.TCPServer): allow_reuse_address = True + def server_bind(self): + # [核心魔改] 强行解除 Linux/Unix 的 IPv6 独占锁 + # 实现一个 Socket 对象同时接管 IPv4 (0.0.0.0) 和 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.1.8 终极修复] 废除脆弱的 Python 内置解析,直接读取 Bash 注入的底层环境变量 -bind_addr = os.environ.get('BIND_ADDR', '0.0.0.0') -if bind_addr == "::": - ThreadedServer.address_family = socket.AF_INET6 -else: - ThreadedServer.address_family = socket.AF_INET +# [v4.2.2 终极架构] 彻底抛弃配置文件的 IP 束缚,强行探测系统底层的双栈能力 +bind_addr = "::" +address_family = socket.AF_INET6 +try: + # 探针:如果机器是纯 IPv4 (连内核级的 IPv6 模块都没有被加载),强绑 :: 会引发 OSError,此时自动降维 + s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + s.close() +except OSError: + bind_addr = "0.0.0.0" + address_family = socket.AF_INET -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 8bc923d7..14cbc6da 100755 --- a/core/install.sh +++ b/core/install.sh @@ -219,9 +219,13 @@ done rm -f /etc/local.d/ip_sentinel.start 2>/dev/null if [ "$UPGRADE_MODE" == "true" ]; then + # [v4.2.2 终极保障] 平滑升级时强制销毁旧版 TLS 证书与旧版 IP 缓存,逼迫下层组件重铸健康双栈装甲 + rm -f "${INSTALL_DIR}/core/cert.pem" "${INSTALL_DIR}/core/key.pem" "${INSTALL_DIR}/core/.last_ip" 2>/dev/null + echo -e "🧹 历史底层缓存及残旧 TLS 证书已强制销毁,准备重铸安全装甲。" + if [ "$KEEP_LOGS" == "false" ]; then rm -rf "${INSTALL_DIR}/logs" 2>/dev/null - echo -e "🗑️ 历史日志已按指令清空。" + echo -e "🗑️ 历史战地日志已按指令清空。" else echo -e "📦 历史配置与战地日志已妥善保留。" fi @@ -411,8 +415,31 @@ if [ "$UPGRADE_MODE" == "false" ]; then # ---------------------------------------------------------- echo -e "\n\033[36m[4.5/7] 正在探测本机网络栈与可用出口 (多节点雷达扫描中)...\033[0m" - DETECT_V4=$( (curl -4 -s -m 3 api.ip.sb/ip || curl -4 -s -m 3 ifconfig.me || curl -4 -s -m 3 ipv4.icanhazip.com) 2>/dev/null | grep -E "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | head -n 1 | tr -d '[:space:]') - DETECT_V6=$( (curl -6 -s -m 3 api.ip.sb/ip || curl -6 -s -m 3 ifconfig.me || curl -6 -s -m 3 ipv6.icanhazip.com) 2>/dev/null | grep -E "^[0-9a-fA-F:]+.*:" | head -n 1 | tr -d '[:space:]') + RAW_DETECT_V4=$( (curl -4 -s -m 3 api.ip.sb/ip || curl -4 -s -m 3 ifconfig.me || curl -4 -s -m 3 ipv4.icanhazip.com) 2>/dev/null | grep -E "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | head -n 1 | tr -d '[:space:]') + RAW_DETECT_V6=$( (curl -6 -s -m 3 api.ip.sb/ip || curl -6 -s -m 3 ifconfig.me || curl -6 -s -m 3 ipv6.icanhazip.com) 2>/dev/null | grep -E "^[0-9a-fA-F:]+.*:" | head -n 1 | tr -d '[:space:]') + + # [v4.2.2 源头防线] 引入工业级网卡追踪,双重过滤 WARP/TUN/NAT 等假公网环境 + DETECT_V4="" + if [[ -n "$RAW_DETECT_V4" ]]; then + V4_DEV=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) + if [[ "$V4_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || \ + [[ "$RAW_DETECT_V4" =~ ^104\.28\. ]] || \ + [[ "$RAW_DETECT_V4" =~ ^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\. ]]; then + echo -e " \033[33m⚠️ 雷达警告: 发现异常 IPv4 出口 ($RAW_DETECT_V4) 经由虚拟网卡 ($V4_DEV),已从通讯候选池中隔离。\033[0m" + else + DETECT_V4="$RAW_DETECT_V4" + fi + fi + + DETECT_V6="" + if [[ -n "$RAW_DETECT_V6" ]]; then + V6_DEV=$(ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) + if [[ "$V6_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || [[ "$RAW_DETECT_V6" =~ ^fe80:|^::1 ]]; then + echo -e " \033[33m⚠️ 雷达警告: 发现异常 IPv6 出口 ($RAW_DETECT_V6) 经由虚拟网卡 ($V6_DEV),已从通讯候选池中隔离。\033[0m" + else + DETECT_V6="$RAW_DETECT_V6" + fi + fi IP_OPTIONS=() IP_PROTO=() @@ -461,7 +488,34 @@ if [ "$UPGRADE_MODE" == "false" ]; then SAFE_PUBLIC_IP="$PUBLIC_IP" fi + # ========================================================== + # [v4.2.2 终极架构] 智能主副容灾弹药装填 (Multi-IP Fallback) + # 严格排序: 1.养护IP (SAFE_PUBLIC_IP) 2.可用IPv4 3.可用IPv6 + # ========================================================== + echo -e "\n\033[36m[4.6/7] 正在装填通讯容灾防线 (Multi-IP Fallback)...\033[0m" + COMM_IP="$SAFE_PUBLIC_IP" + + # 注入次发弹药 (可用 IPv4) + if [[ -n "$DETECT_V4" ]] && [[ "$DETECT_V4" != "$PUBLIC_IP" ]]; then + COMM_IP="${COMM_IP},${DETECT_V4}" + fi + + # 注入保底弹药 (可用 IPv6,带括号保护) + if [[ -n "$DETECT_V6" ]] && [[ "$DETECT_V6" != "$PUBLIC_IP" ]]; then + [[ "$DETECT_V6" != *"["* ]] && SAFE_V6="[${DETECT_V6}]" || SAFE_V6="$DETECT_V6" + COMM_IP="${COMM_IP},${SAFE_V6}" + fi + + SAFE_COMM_IP="$COMM_IP" + + if [[ "$COMM_IP" == *","* ]]; then + echo -e " \033[32m✅ 成功组装多宿主容灾通讯专线: $SAFE_COMM_IP\033[0m" + else + echo -e " \033[33m⚠️ 本机仅有单一出口,建立单轨通讯模式: $SAFE_COMM_IP\033[0m" + fi + echo -n "🕵️ 正在进行出站链路试射 (NAT环境与双栈嗅探)..." + RAW_TEST_IP=$(echo "$SAFE_PUBLIC_IP" | tr -d '[]') if [[ "$RAW_TEST_IP" == *":"* ]]; then @@ -536,6 +590,7 @@ LOG_FILE="${INSTALL_DIR}/logs/sentinel.log" IP_PREF="$IP_PREF" PUBLIC_IP="$SAFE_PUBLIC_IP" BIND_IP="$BIND_IP" +COMM_IP="$SAFE_COMM_IP" NODE_NAME="$NODE_NAME" NODE_ALIAS="$NODE_ALIAS" @@ -582,6 +637,41 @@ if [ "$UPGRADE_MODE" == "true" ]; then SAFE_PUBLIC_IP="${PUBLIC_IP}" fi + # [v4.2.2 热修复] 为老版本平滑补齐多宿主容灾通讯 IP + if ! grep -q "^COMM_IP=" "$CONFIG_FILE"; then + echo -e "\n🔄 [平滑迁移] 正在为老节点无损注入 v4.2.2 容灾通讯架构..." + TMP_PUB_IP=$(grep "^PUBLIC_IP=" "$CONFIG_FILE" | cut -d'"' -f2 | tr -d '[]') + + RAW_V4=$(curl -4 -s -m 3 api.ip.sb/ip 2>/dev/null | tr -d '[:space:]') + RAW_V6=$(curl -6 -s -m 3 api.ip.sb/ip 2>/dev/null | tr -d '[:space:]') + + V4_DEV=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) + if [[ "$V4_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || [[ "$RAW_V4" =~ ^104\.28\. ]] || [[ "$RAW_V4" =~ ^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\. ]]; then + RAW_V4="" + fi + + V6_DEV=$(ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) + if [[ "$V6_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || [[ "$RAW_V6" =~ ^fe80:|^::1 ]]; then + RAW_V6="" + fi + + [[ "$TMP_PUB_IP" == *":"* ]] && NEW_COMM_IP="[${TMP_PUB_IP}]" || NEW_COMM_IP="$TMP_PUB_IP" + + if [[ -n "$RAW_V4" ]] && [[ "$RAW_V4" != "$TMP_PUB_IP" ]]; then + NEW_COMM_IP="${NEW_COMM_IP},${RAW_V4}" + fi + + if [[ -n "$RAW_V6" ]] && [[ "$RAW_V6" != "$TMP_PUB_IP" ]]; then + NEW_COMM_IP="${NEW_COMM_IP},[${RAW_V6}]" + fi + + echo "COMM_IP=\"$NEW_COMM_IP\"" >> "$CONFIG_FILE" + SAFE_COMM_IP="$NEW_COMM_IP" + echo -e " \033[32m✅ 成功注入容灾通讯专线: $SAFE_COMM_IP\033[0m" + else + SAFE_COMM_IP=$(grep "^COMM_IP=" "$CONFIG_FILE" | cut -d'"' -f2) + fi + if ! grep -q "^NODE_NAME=" "$CONFIG_FILE"; then TMP_HASH=$(echo "${SAFE_PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z') NODE_NAME="$(hostname | tr -cd 'a-zA-Z0-9' | cut -c 1-10)-${TMP_HASH}" @@ -873,7 +963,8 @@ EOF # ---------------------------------------------------------- if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then - REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${SAFE_PUBLIC_IP}|${AGENT_PORT}|${NODE_ALIAS}|${ENABLE_OTA}" + # 注册报文中塞入多宿主弹匣 SAFE_COMM_IP + REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${SAFE_COMM_IP}|${AGENT_PORT}|${NODE_ALIAS}|${ENABLE_OTA}" if [ "$UPGRADE_MODE" == "true" ]; then OLD_VERSION=$(grep "^AGENT_VERSION=" "$CONFIG_FILE" | cut -d'"' -f2) @@ -883,7 +974,8 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then echo -e "\n📡 [路由枢纽] 正在执行跨代架构重组 (v${OLD_VERSION} -> v${TARGET_VERSION})..." TEXT_MSG="✨ *IP-Sentinel 引擎热更新完成!* 📍 节点:\`${NODE_ALIAS}\` -🌐 IP:\`${SAFE_PUBLIC_IP}\` +🌐 养护 IP:\`${SAFE_PUBLIC_IP}\` +📡 容灾 IP:\`${SAFE_COMM_IP}\` 🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署 ⚠️ *战区架构已重组,请务必点击下方指令并发送,以同步新的防撞档案:* @@ -898,7 +990,8 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then echo -e "\n📡 [路由枢纽] 正在执行静默平滑升级 (v${OLD_VERSION} -> v${TARGET_VERSION})..." TEXT_MSG="✨ *IP-Sentinel 引擎热更新完成!* 📍 节点:\`${NODE_ALIAS}\` -🌐 IP:\`${SAFE_PUBLIC_IP}\` +🌐 养护 IP:\`${SAFE_PUBLIC_IP}\` +📡 容灾 IP:\`${SAFE_COMM_IP}\` 🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署" JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}') @@ -918,7 +1011,8 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then echo -e "\n📡 正在向指挥部发送注册暗号..." TEXT_MSG="✨ *IP-Sentinel 部署成功!* 📍 区域:${REGION_NAME} -🌐 IP:${SAFE_PUBLIC_IP} +🌐 养护 IP:${SAFE_PUBLIC_IP} +📡 容灾 IP:${SAFE_COMM_IP} 🔌 端口:${AGENT_PORT} 🔑 *请点击下方指令复制并回复给机器人:* @@ -946,22 +1040,30 @@ echo "⚙️ 哨兵现已开启 [每20分钟] 的高频高拟真养护循环。" if [[ -n "$TG_TOKEN" ]]; then echo "📡 Webhook 监听已启动 (端口: $AGENT_PORT) 并向中枢发送了注册请求。" + # [v4.2.2 防火墙修正] 适配多宿主 IP 提示 + IS_V6_COMM="false" + [[ "$SAFE_COMM_IP" == *":"* ]] && IS_V6_COMM="true" + FW_MSG="" if command -v ufw >/dev/null 2>&1 && ufw status | grep -qw active; then FW_MSG="ufw allow $AGENT_PORT/tcp" elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld | grep -qw active; then FW_MSG="firewall-cmd --zone=public --add-port=$AGENT_PORT/tcp --permanent && firewall-cmd --reload" elif command -v iptables >/dev/null 2>&1; then - if [[ "$SAFE_PUBLIC_IP" == *":"* ]]; then - FW_MSG="ip6tables -I INPUT -p tcp --dport $AGENT_PORT -j ACCEPT" + if [ "$IS_V6_COMM" == "true" ]; then + if command -v ip6tables >/dev/null 2>&1; then + FW_MSG="ip6tables -I INPUT -p tcp --dport $AGENT_PORT -j ACCEPT" + else + FW_MSG="iptables -I INPUT -p tcp --dport $AGENT_PORT -j ACCEPT # 提示: 系统缺失 ip6tables" + fi else FW_MSG="iptables -I INPUT -p tcp --dport $AGENT_PORT -j ACCEPT" fi fi - echo -e "\n\033[31m⚠️ 【高危警告】您的节点身份已永久锁定为公网 IP: $SAFE_PUBLIC_IP\033[0m" + echo -e "\n\033[31m⚠️ 【高危警告】您的节点通讯寻址池已锁定为: $SAFE_COMM_IP\033[0m" echo -e "\033[33m为确保 Master 司令部能够成功下发指令,您【必须】前往云服务商 (如 AWS/Oracle/阿里云 等) 的网页控制台中,将安全组 (Security Group) 防火墙的 TCP $AGENT_PORT 端口彻底放行!\033[0m" - echo -e "\033[31m⛔ 禁止尝试通过修改脚本强行绑定局域网/内网 IP 来绕过通信阻断,这无异于掩耳盗铃,将彻底摧毁本系统“公网IP信用养护”的核心目标!\033[0m\n" + echo -e "\033[31m⛔ 本系统已开启全域双栈监听,禁止尝试通过修改脚本强行绑定局域网 IP 来绕过通信阻断!\033[0m\n" if [ -n "$FW_MSG" ]; then echo "💡 检测到本地系统防火墙开启,您可以尝试执行以下命令放行本机端口 (注意: 云端安全组仍需您手动放行):" echo -e "\033[36m $FW_MSG\033[0m" diff --git a/master/tg_master.sh b/master/tg_master.sh index 171d3d86..34fe827e 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -82,6 +82,33 @@ generate_signed_url() { echo "https://${target_ip}:${target_port}${action_path}?t=${current_t}&sign=${signature}" } +# ========================================================== +# [新增插入] 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" +} # ========================================================== # 2. 数据库热升级自愈系统 @@ -298,8 +325,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 +379,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 +392,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 +413,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 +563,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 +655,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" "❌ 指令下发超时!为防范劫持风险,已终止请求。" @@ -670,15 +686,13 @@ while true; do AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1) AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2) - if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then - if [ -n "$MSG_ID" ]; then + if [ -n "$MSG_ID" ]; then edit_msg "$CHAT_ID" "$MSG_ID" "⏳ 正在向 \`$TARGET_NODE\` 发送 OTA 触发报文..." else 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 降级通讯。" @@ -707,15 +721,13 @@ while true; do AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1) AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2) - if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then - if [ -n "$MSG_ID" ]; then + if [ -n "$MSG_ID" ]; then edit_msg "$CHAT_ID" "$MSG_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [$ACTION_TYPE] 指令,请稍候..." else 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)。" From ed65f412f4fc32200a0d70cdc6ae15cafae9511e Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 07:52:27 +0000 Subject: [PATCH 02/10] =?UTF-8?q?feat(arch):=20=E8=B7=83=E5=8D=87=20v4.2.2?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E6=9E=84=E5=85=A8=E9=93=BE=E8=B7=AF=E5=AE=B9?= =?UTF-8?q?=E7=81=BE=E4=BD=93=E7=B3=BB=E3=80=82=E5=BC=95=E5=85=A5=E3=80=8C?= =?UTF-8?q?=E5=A4=9A=E5=AE=BF=E4=B8=BB=E6=99=BA=E8=83=BD=E5=9B=9E=E9=80=80?= =?UTF-8?q?=20(Multi-homing=20Fallback)=E3=80=8D=E6=9C=BA=E5=88=B6?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=85=A8=E5=9F=9F=E5=8F=8C=E6=A0=88?= =?UTF-8?q?=E7=9B=91=E5=90=AC=E4=B8=8E=E6=AF=AB=E7=A7=92=E7=BA=A7=E9=98=B2?= =?UTF-8?q?=E9=BB=91=E6=B4=9E=E9=87=8D=E8=AF=95=E6=89=93=E5=87=BB=EF=BC=8C?= =?UTF-8?q?=E5=BD=BB=E5=BA=95=E5=85=8D=E7=96=AB=E7=BA=AF=20IPv6=E3=80=81LX?= =?UTF-8?q?C=E3=80=81=E5=A4=A7=E5=86=85=E7=BD=91=20WARP=20=E7=AD=89?= =?UTF-8?q?=E9=AB=98=E5=8D=B1=E9=98=BB=E6=96=AD=E5=9C=BA=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- master/tg_master.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/master/tg_master.sh b/master/tg_master.sh index 34fe827e..8888d158 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -686,7 +686,9 @@ while true; do AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1) AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2) - if [ -n "$MSG_ID" ]; then + # [修正点] 必须保留这层外壳判断 + if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then + if [ -n "$MSG_ID" ]; then edit_msg "$CHAT_ID" "$MSG_ID" "⏳ 正在向 \`$TARGET_NODE\` 发送 OTA 触发报文..." else send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` 发送 OTA 触发报文..." @@ -721,7 +723,9 @@ while true; do AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1) AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2) - if [ -n "$MSG_ID" ]; then + # [修正点] 必须保留这层外壳判断 + if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then + if [ -n "$MSG_ID" ]; then edit_msg "$CHAT_ID" "$MSG_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [$ACTION_TYPE] 指令,请稍候..." else send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [$ACTION_TYPE] 指令,请稍候..." From 54839f52d5abb4a9d0d3e797eacb96cbfae38d20 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 07:55:18 +0000 Subject: [PATCH 03/10] =?UTF-8?q?test(env):=20=E4=B8=B4=E6=97=B6=E5=B0=86?= =?UTF-8?q?=20REPO=5FRAW=5FURL=20=E6=8C=87=E5=90=91=20feature/v4.2.0-dual-?= =?UTF-8?q?stack=20=E5=88=86=E6=94=AF=EF=BC=8C=E5=BC=80=E5=90=AF=E5=85=A8?= =?UTF-8?q?=E9=93=BE=E8=B7=AF=E5=AE=B9=E7=81=BE=E6=B2=99=E7=9B=92=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/install.sh | 2 +- master/install_master.sh | 2 +- master/tg_master.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/install.sh b/core/install.sh index 14cbc6da..578cd11e 100755 --- a/core/install.sh +++ b/core/install.sh @@ -61,7 +61,7 @@ fi echo -e "======================================\n" sleep 1 -REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main" +REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/feature/v4.2.0-dual-stack" INSTALL_DIR="/opt/ip_sentinel" CONFIG_FILE="${INSTALL_DIR}/config.conf" diff --git a/master/install_master.sh b/master/install_master.sh index 1397b2b0..da9ed9c1 100755 --- a/master/install_master.sh +++ b/master/install_master.sh @@ -60,7 +60,7 @@ fi echo -e "======================================\n" sleep 1 -REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main" +REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/feature/v4.2.0-dual-stack" # [链路容灾] 双栈冗余防抖抓取,确立本地态势版本号 TARGET_VERSION=$( (curl -fsSL --connect-timeout 5 --retry 2 "${REPO_RAW_URL}/version.txt" || curl -4 -fsSL --connect-timeout 5 --retry 2 "${REPO_RAW_URL}/version.txt") 2>/dev/null | grep "^MASTER_VERSION=" | cut -d'=' -f2 | tr -d '[:space:]') diff --git a/master/tg_master.sh b/master/tg_master.sh index 8888d158..4c658667 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -9,7 +9,7 @@ CONF="/opt/ip_sentinel_master/master.conf" [ ! -f "$CONF" ] && exit 1 source "$CONF" -REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main" +REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/feature/v4.2.0-dual-stack" MASTER_VERSION=${MASTER_VERSION:-"3.5.0"} OFFSET_FILE="${MASTER_DIR}/.tg_offset" From 58c08213bf6dac60fde9bc18c16fcbecc93cfe5d Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 08:05:12 +0000 Subject: [PATCH 04/10] =?UTF-8?q?fix(master):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E8=A7=A3=E5=8C=85=E6=95=B0=E6=8D=AE=E9=93=BE?= =?UTF-8?q?=EF=BC=8C=E5=AE=8C=E7=BE=8E=E5=9B=BA=E5=8C=96=E9=80=97=E5=8F=B7?= =?UTF-8?q?=E5=88=86=E9=9A=94=E7=9A=84=E5=A4=9A=E5=AE=BF=E4=B8=BB=E9=80=9A?= =?UTF-8?q?=E8=AE=AF=E5=AF=BB=E5=9D=80=E6=B1=A0=EF=BC=8C=E5=AF=B9=E9=BD=90?= =?UTF-8?q?=20v4.2.2=20=E5=AE=B9=E7=81=BE=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- master/tg_master.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/master/tg_master.sh b/master/tg_master.sh index 4c658667..f4252645 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -262,8 +262,18 @@ while true; do continue fi + # [v4.2.2 容灾对齐] 允许 agent_ip 字段以逗号分隔的形式完整固化多路由通道 db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen, region, node_alias, enable_ota) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP, '$AGENT_REGION', '$NODE_ALIAS', '$AGENT_OTA') ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP, region='$AGENT_REGION', node_alias='$NODE_ALIAS', enable_ota='$AGENT_OTA';" - send_msg "$CHAT_ID" "✅ **司令部确认 (v${MASTER_VERSION})**%0A节点 \`${NODE_ALIAS}\` 档案已录入!" + + # 动态人性化回执:在 TG 侧清晰地向管理者展示主备双通道的录入态势 + MAIN_SHOW_IP=$(echo "$AGENT_IP" | cut -d',' -f1) + BACKUP_SHOW_IP=$(echo "$AGENT_IP" | cut -d',' -f2-) + if [ -n "$BACKUP_SHOW_IP" ]; then + SHOW_MSG="✅ **司令部确认 (v${MASTER_VERSION})**%0A节点 \`${NODE_ALIAS}\` 档案已录入!%0A🌐 主通讯:\`${MAIN_SHOW_IP}\`%0A📡 容灾备用:\`${BACKUP_SHOW_IP}\`" + else + SHOW_MSG="✅ **司令部确认 (v${MASTER_VERSION})**%0A节点 \`${NODE_ALIAS}\` 档案已录入!%0A🌐 通讯 IP:\`${MAIN_SHOW_IP}\`" + fi + send_msg "$CHAT_ID" "$SHOW_MSG" REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;") if [ -n "$REGION_DATA" ]; then From 591100a27f8b47ad33c1a480fd42f4555aea2c27 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 08:10:49 +0000 Subject: [PATCH 05/10] =?UTF-8?q?fix(install):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=B7=A8=E4=BB=A3=E7=83=AD=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=BC=BA=E5=88=B6=E4=BD=8E=E4=BA=8E=20v4.2.2=20?= =?UTF-8?q?=E7=9A=84=E8=80=81=E8=8A=82=E7=82=B9=E5=9C=A8=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E5=90=8E=E4=B8=BB=E5=8A=A8=E5=90=8C=E6=AD=A5=E3=80=8C=E5=A4=9A?= =?UTF-8?q?=E5=AE=BF=E4=B8=BB=E5=AE=B9=E7=81=BE=E5=BC=B9=E5=8C=A3=E3=80=8D?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9D=20Master=20=E6=8C=87=E6=8E=A7?= =?UTF-8?q?=E9=93=BE=E8=B7=AF=E4=B8=8D=E4=B8=A2=E5=A4=B1=E5=A4=87=E7=94=A8?= =?UTF-8?q?=20IP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/install.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/install.sh b/core/install.sh index 578cd11e..fbe61c1e 100755 --- a/core/install.sh +++ b/core/install.sh @@ -970,15 +970,17 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then OLD_VERSION=$(grep "^AGENT_VERSION=" "$CONFIG_FILE" | cut -d'"' -f2) [ -z "$OLD_VERSION" ] && OLD_VERSION="3.3.1" - if version_lt "$OLD_VERSION" "3.3.2"; then - echo -e "\n📡 [路由枢纽] 正在执行跨代架构重组 (v${OLD_VERSION} -> v${TARGET_VERSION})..." - TEXT_MSG="✨ *IP-Sentinel 引擎热更新完成!* + # [v4.2.2 跨代升级防线] 只要是从低于 4.2.2 的版本升上来,强制要求用户点击注册指令同步多宿主弹匣 + if version_lt "$OLD_VERSION" "4.2.2"; then + echo -e "\n📡 [路由枢纽] 正在执行容灾架构重组 (v${OLD_VERSION} -> v${TARGET_VERSION})..." + TEXT_MSG="✨ *IP-Sentinel 容灾引擎热更新完成!* 📍 节点:\`${NODE_ALIAS}\` 🌐 养护 IP:\`${SAFE_PUBLIC_IP}\` -📡 容灾 IP:\`${SAFE_COMM_IP}\` -🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署 +📡 容灾弹匣:\`${SAFE_COMM_IP}\` +🚀 状态:v${TARGET_VERSION} 全域双栈引擎已部署 -⚠️ *战区架构已重组,请务必点击下方指令并发送,以同步新的防撞档案:* +⚠️ *通讯架构已升级为多宿主容灾模式!* +👉 **请务必点击下方指令并发送,将新版通讯弹匣同步至司令部:** \`${REG_MSG}\`" JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}') From 4375fac814fb8b0a61683b4427204ff4cb66c684 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 08:16:31 +0000 Subject: [PATCH 06/10] =?UTF-8?q?fix(install):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=B9=B3=E6=BB=91=E5=8D=87=E7=BA=A7=E6=97=B6=E9=95=BF=E6=95=88?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E8=A6=86=E7=9B=96=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=BC=BA=E8=A1=8C=E4=BB=A5=20SAFE=5FPUBLIC=5FIP=20=E4=B8=BA?= =?UTF-8?q?=E5=9F=BA=E5=BA=A7=E9=87=8D=E9=93=B8=E5=A4=9A=E5=AE=BF=E4=B8=BB?= =?UTF-8?q?=E5=BC=B9=E5=8C=A3=EF=BC=8C=E5=BD=BB=E5=BA=95=E9=98=B2=E6=AD=A2?= =?UTF-8?q?=E9=A6=96=E5=8F=91=20IPv6=20=E9=81=97=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/install.sh | 69 ++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/core/install.sh b/core/install.sh index fbe61c1e..af450cb6 100755 --- a/core/install.sh +++ b/core/install.sh @@ -637,40 +637,43 @@ if [ "$UPGRADE_MODE" == "true" ]; then SAFE_PUBLIC_IP="${PUBLIC_IP}" fi - # [v4.2.2 热修复] 为老版本平滑补齐多宿主容灾通讯 IP - if ! grep -q "^COMM_IP=" "$CONFIG_FILE"; then - echo -e "\n🔄 [平滑迁移] 正在为老节点无损注入 v4.2.2 容灾通讯架构..." - TMP_PUB_IP=$(grep "^PUBLIC_IP=" "$CONFIG_FILE" | cut -d'"' -f2 | tr -d '[]') - - RAW_V4=$(curl -4 -s -m 3 api.ip.sb/ip 2>/dev/null | tr -d '[:space:]') - RAW_V6=$(curl -6 -s -m 3 api.ip.sb/ip 2>/dev/null | tr -d '[:space:]') - - V4_DEV=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) - if [[ "$V4_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || [[ "$RAW_V4" =~ ^104\.28\. ]] || [[ "$RAW_V4" =~ ^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\. ]]; then - RAW_V4="" - fi - - V6_DEV=$(ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) - if [[ "$V6_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || [[ "$RAW_V6" =~ ^fe80:|^::1 ]]; then - RAW_V6="" - fi - - [[ "$TMP_PUB_IP" == *":"* ]] && NEW_COMM_IP="[${TMP_PUB_IP}]" || NEW_COMM_IP="$TMP_PUB_IP" - - if [[ -n "$RAW_V4" ]] && [[ "$RAW_V4" != "$TMP_PUB_IP" ]]; then - NEW_COMM_IP="${NEW_COMM_IP},${RAW_V4}" - fi - - if [[ -n "$RAW_V6" ]] && [[ "$RAW_V6" != "$TMP_PUB_IP" ]]; then - NEW_COMM_IP="${NEW_COMM_IP},[${RAW_V6}]" - fi - - echo "COMM_IP=\"$NEW_COMM_IP\"" >> "$CONFIG_FILE" - SAFE_COMM_IP="$NEW_COMM_IP" - echo -e " \033[32m✅ 成功注入容灾通讯专线: $SAFE_COMM_IP\033[0m" - else - SAFE_COMM_IP=$(grep "^COMM_IP=" "$CONFIG_FILE" | cut -d'"' -f2) + # [v4.2.2 热修复] 为所有老节点 (无论是否已有残缺的 COMM_IP) 强行重铸多宿主容灾弹匣 + echo -e "\n🔄 [平滑迁移] 正在对老节点执行 v4.2.2 全域容灾弹匣重构..." + + RAW_V4=$(curl -4 -s -m 3 api.ip.sb/ip 2>/dev/null | tr -d '[:space:]') + RAW_V6=$(curl -6 -s -m 3 api.ip.sb/ip 2>/dev/null | tr -d '[:space:]') + + V4_DEV=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) + if [[ "$V4_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || [[ "$RAW_V4" =~ ^104\.28\. ]] || [[ "$RAW_V4" =~ ^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^100\.(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-7])\. ]]; then + RAW_V4="" fi + + V6_DEV=$(ip -6 route get 2001:4860:4860::8888 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -n 1) + if [[ "$V6_DEV" =~ ^(warp|wgcf|tun|tap|docker|br-|lo) ]] || [[ "$RAW_V6" =~ ^fe80:|^::1 ]]; then + RAW_V6="" + fi + + # 绝对基座:始终确保养护 IP (SAFE_PUBLIC_IP) 处于弹匣的首发位置 + NEW_COMM_IP="$SAFE_PUBLIC_IP" + RAW_BASE_IP=$(echo "$SAFE_PUBLIC_IP" | tr -d '[]') + + # 追加 V4 容灾备弹 + if [[ -n "$RAW_V4" ]] && [[ "$RAW_V4" != "$RAW_BASE_IP" ]]; then + NEW_COMM_IP="${NEW_COMM_IP},${RAW_V4}" + fi + + # 追加 V6 容灾备弹 + if [[ -n "$RAW_V6" ]] && [[ "$RAW_V6" != "$RAW_BASE_IP" ]]; then + [[ "$RAW_V6" != *"["* ]] && SAFE_V6="[${RAW_V6}]" || SAFE_V6="$RAW_V6" + NEW_COMM_IP="${NEW_COMM_IP},${SAFE_V6}" + fi + + # 强制覆盖 config.conf 中的旧 COMM_IP 记录 + sed -i '/^COMM_IP=/d' "$CONFIG_FILE" + echo "COMM_IP=\"$NEW_COMM_IP\"" >> "$CONFIG_FILE" + SAFE_COMM_IP="$NEW_COMM_IP" + + echo -e " \033[32m✅ 重铸容灾通讯专线完成: $SAFE_COMM_IP\033[0m" if ! grep -q "^NODE_NAME=" "$CONFIG_FILE"; then TMP_HASH=$(echo "${SAFE_PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z') From f57a4cd9e031ce3820631da59e35fbf46b66b4b4 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 08:21:01 +0000 Subject: [PATCH 07/10] =?UTF-8?q?fix(install):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=B9=B3=E6=BB=91=E5=8D=87=E7=BA=A7=E6=97=B6=E5=AE=B9=E7=81=BE?= =?UTF-8?q?=E5=BC=B9=E5=8C=A3=E7=BB=84=E8=A3=85=E7=BC=BA=E5=B0=91=E9=80=97?= =?UTF-8?q?=E5=8F=B7=E5=88=86=E9=9A=94=E7=AC=A6=E7=9A=84=E8=87=B4=E5=91=BD?= =?UTF-8?q?=E6=8B=BC=E6=8E=A5=E9=94=99=E8=AF=AF=EF=BC=8C=E4=BF=9D=E9=9A=9C?= =?UTF-8?q?=20Master=20=E6=8C=87=E4=BB=A4=E8=A7=A3=E6=9E=90=E5=99=A8?= =?UTF-8?q?=E5=85=8D=E9=81=AD=E6=88=AA=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/install.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/install.sh b/core/install.sh index af450cb6..d045982c 100755 --- a/core/install.sh +++ b/core/install.sh @@ -658,14 +658,16 @@ if [ "$UPGRADE_MODE" == "true" ]; then RAW_BASE_IP=$(echo "$SAFE_PUBLIC_IP" | tr -d '[]') # 追加 V4 容灾备弹 - if [[ -n "$RAW_V4" ]] && [[ "$RAW_V4" != "$RAW_BASE_IP" ]]; then + if [[ -n "$RAW_V4" ]] && [[ "$NEW_COMM_IP" != *"$RAW_V4"* ]]; then NEW_COMM_IP="${NEW_COMM_IP},${RAW_V4}" fi # 追加 V6 容灾备弹 - if [[ -n "$RAW_V6" ]] && [[ "$RAW_V6" != "$RAW_BASE_IP" ]]; then + if [[ -n "$RAW_V6" ]]; then [[ "$RAW_V6" != *"["* ]] && SAFE_V6="[${RAW_V6}]" || SAFE_V6="$RAW_V6" - NEW_COMM_IP="${NEW_COMM_IP},${SAFE_V6}" + if [[ "$NEW_COMM_IP" != *"$SAFE_V6"* ]]; then + NEW_COMM_IP="${NEW_COMM_IP},${SAFE_V6}" + fi fi # 强制覆盖 config.conf 中的旧 COMM_IP 记录 From 56dc23009bc9b8aeceb92c022d1b2bedbe51fc9d Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 12:27:00 +0000 Subject: [PATCH 08/10] =?UTF-8?q?fix(core):=20=E6=9B=BF=E6=8D=A2=E5=AE=B9?= =?UTF-8?q?=E7=81=BE=E5=A4=9A=E5=AE=BF=E4=B8=BB=20IP=20=E5=BC=B9=E5=8C=A3?= =?UTF-8?q?=E7=9A=84=E6=8B=BC=E6=8E=A5=E7=AC=A6=EF=BC=88=E4=BB=8E=E9=80=97?= =?UTF-8?q?=E5=8F=B7=E6=94=B9=E4=B8=BA=E4=B8=8B=E5=88=92=E7=BA=BF=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E5=BD=BB=E5=BA=95=E8=A7=A3=E5=86=B3=E5=9B=A0=20Telegr?= =?UTF-8?q?am=20=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=8F=8A=20API=20=E7=89=B9?= =?UTF-8?q?=E6=AE=8A=E5=AD=97=E7=AC=A6=E6=88=AA=E6=96=AD=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E5=A4=9A=20IP=20=E7=B2=98=E8=BF=9E=E5=A4=B1=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/install.sh | 10 +++++----- master/tg_master.sh | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/install.sh b/core/install.sh index d045982c..c3ae377b 100755 --- a/core/install.sh +++ b/core/install.sh @@ -497,18 +497,18 @@ if [ "$UPGRADE_MODE" == "false" ]; then # 注入次发弹药 (可用 IPv4) if [[ -n "$DETECT_V4" ]] && [[ "$DETECT_V4" != "$PUBLIC_IP" ]]; then - COMM_IP="${COMM_IP},${DETECT_V4}" + COMM_IP="${COMM_IP}_${DETECT_V4}" fi # 注入保底弹药 (可用 IPv6,带括号保护) if [[ -n "$DETECT_V6" ]] && [[ "$DETECT_V6" != "$PUBLIC_IP" ]]; then [[ "$DETECT_V6" != *"["* ]] && SAFE_V6="[${DETECT_V6}]" || SAFE_V6="$DETECT_V6" - COMM_IP="${COMM_IP},${SAFE_V6}" + COMM_IP="${COMM_IP}_${SAFE_V6}" fi SAFE_COMM_IP="$COMM_IP" - if [[ "$COMM_IP" == *","* ]]; then + if [[ "$COMM_IP" == *"_"* ]]; then echo -e " \033[32m✅ 成功组装多宿主容灾通讯专线: $SAFE_COMM_IP\033[0m" else echo -e " \033[33m⚠️ 本机仅有单一出口,建立单轨通讯模式: $SAFE_COMM_IP\033[0m" @@ -659,14 +659,14 @@ if [ "$UPGRADE_MODE" == "true" ]; then # 追加 V4 容灾备弹 if [[ -n "$RAW_V4" ]] && [[ "$NEW_COMM_IP" != *"$RAW_V4"* ]]; then - NEW_COMM_IP="${NEW_COMM_IP},${RAW_V4}" + NEW_COMM_IP="${NEW_COMM_IP}_${RAW_V4}" fi # 追加 V6 容灾备弹 if [[ -n "$RAW_V6" ]]; then [[ "$RAW_V6" != *"["* ]] && SAFE_V6="[${RAW_V6}]" || SAFE_V6="$RAW_V6" if [[ "$NEW_COMM_IP" != *"$SAFE_V6"* ]]; then - NEW_COMM_IP="${NEW_COMM_IP},${SAFE_V6}" + NEW_COMM_IP="${NEW_COMM_IP}_${SAFE_V6}" fi fi diff --git a/master/tg_master.sh b/master/tg_master.sh index f4252645..f58a4e27 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -92,8 +92,8 @@ call_agent() { local suffix="$4" local res="FAILED" - # 拆解逗号分隔的 IP 列阵 (例如: [2a0b:...],66.181.x.x) - IFS=',' read -r -a ip_array <<< "$ips" + # 拆解下划线分隔的 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") @@ -266,8 +266,8 @@ while true; do db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen, region, node_alias, enable_ota) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP, '$AGENT_REGION', '$NODE_ALIAS', '$AGENT_OTA') ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP, region='$AGENT_REGION', node_alias='$NODE_ALIAS', enable_ota='$AGENT_OTA';" # 动态人性化回执:在 TG 侧清晰地向管理者展示主备双通道的录入态势 - MAIN_SHOW_IP=$(echo "$AGENT_IP" | cut -d',' -f1) - BACKUP_SHOW_IP=$(echo "$AGENT_IP" | cut -d',' -f2-) + MAIN_SHOW_IP=$(echo "$AGENT_IP" | cut -d'_' -f1) + BACKUP_SHOW_IP=$(echo "$AGENT_IP" | cut -d'_' -f2-) if [ -n "$BACKUP_SHOW_IP" ]; then SHOW_MSG="✅ **司令部确认 (v${MASTER_VERSION})**%0A节点 \`${NODE_ALIAS}\` 档案已录入!%0A🌐 主通讯:\`${MAIN_SHOW_IP}\`%0A📡 容灾备用:\`${BACKUP_SHOW_IP}\`" else From 0782487b8aeeb26bf5f7da81cd157b790dea6b91 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 12:36:12 +0000 Subject: [PATCH 09/10] =?UTF-8?q?fix(master):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9E=81=E5=BA=A6=E9=9A=90=E8=94=BD=E7=9A=84=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E8=BF=87=E5=BA=A6=E6=B8=85=E6=B4=97=E6=BC=8F=E6=B4=9E=E3=80=82?= =?UTF-8?q?=E6=89=A9=E5=85=85=20agent=5Fip=20=E5=AD=97=E6=AE=B5=E6=AD=A3?= =?UTF-8?q?=E5=88=99=E7=99=BD=E5=90=8D=E5=8D=95=E5=8F=8A=E9=95=BF=E5=BA=A6?= =?UTF-8?q?=E6=88=AA=E6=96=AD=E9=98=88=E5=80=BC=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E9=80=97=E5=8F=B7/=E4=B8=8B=E5=88=92=E7=BA=BF=E5=88=86?= =?UTF-8?q?=E9=9A=94=E7=9A=84=E5=A4=9A=E5=AE=BF=E4=B8=BB=E5=BC=B9=E5=8C=A3?= =?UTF-8?q?=E8=83=BD=E5=AE=8C=E6=95=B4=E6=97=A0=E6=8D=9F=E5=85=A5=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- master/tg_master.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/master/tg_master.sh b/master/tg_master.sh index f58a4e27..f8c75894 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -92,8 +92,9 @@ call_agent() { local suffix="$4" local res="FAILED" - # 拆解下划线分隔的 IP 列阵 (例如: [2a0b...]_66.181.x.x) - IFS='_' read -r -a ip_array <<< "$ips" + # 将长串中的下划线统一洗回逗号,确保万无一失的弹匣拆解 + local clean_ips=$(echo "$ips" | tr '_' ',') + IFS=',' read -r -a ip_array <<< "$clean_ips" for ip in "${ip_array[@]}"; do if [ -n "$ip" ]; then local url=$(generate_signed_url "$ip" "$port" "$path") @@ -244,7 +245,7 @@ while true; do CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-') AGENT_REGION=$(echo "$RAW_REGION" | tr -cd 'a-zA-Z0-9' | cut -c 1-10) NODE_NAME=$(echo "$RAW_NODE" | tr -cd 'a-zA-Z0-9_.-' | cut -c 1-30) - AGENT_IP=$(echo "$RAW_IP" | tr -cd 'a-zA-Z0-9.:\[\]-' | cut -c 1-50) + AGENT_IP=$(echo "$RAW_IP" | tr -cd 'a-zA-Z0-9.:\[\]-_,' | cut -c 1-150) AGENT_PORT=$(echo "$RAW_PORT" | tr -cd '0-9' | cut -c 1-5) NODE_ALIAS=$(echo "$RAW_ALIAS" | tr -d '"'\''\`\$\|&;<>\n\r' | cut -c 1-30) [ -z "$NODE_ALIAS" ] && NODE_ALIAS="$NODE_NAME" @@ -265,9 +266,10 @@ while true; do # [v4.2.2 容灾对齐] 允许 agent_ip 字段以逗号分隔的形式完整固化多路由通道 db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen, region, node_alias, enable_ota) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP, '$AGENT_REGION', '$NODE_ALIAS', '$AGENT_OTA') ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP, region='$AGENT_REGION', node_alias='$NODE_ALIAS', enable_ota='$AGENT_OTA';" - # 动态人性化回执:在 TG 侧清晰地向管理者展示主备双通道的录入态势 - MAIN_SHOW_IP=$(echo "$AGENT_IP" | cut -d'_' -f1) - BACKUP_SHOW_IP=$(echo "$AGENT_IP" | cut -d'_' -f2-) + # 统一将下划线替换为逗号,再进行格式化输出,兼容您的所有测试版本 + FMT_AGENT_IP=$(echo "$AGENT_IP" | tr '_' ',') + MAIN_SHOW_IP=$(echo "$FMT_AGENT_IP" | cut -d',' -f1) + BACKUP_SHOW_IP=$(echo "$FMT_AGENT_IP" | cut -d',' -f2-) if [ -n "$BACKUP_SHOW_IP" ]; then SHOW_MSG="✅ **司令部确认 (v${MASTER_VERSION})**%0A节点 \`${NODE_ALIAS}\` 档案已录入!%0A🌐 主通讯:\`${MAIN_SHOW_IP}\`%0A📡 容灾备用:\`${BACKUP_SHOW_IP}\`" else From 019e755ebfdc5bd0d9511cdc852236bcba8aeba3 Mon Sep 17 00:00:00 2001 From: hotyue <52734432+hotyue@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:20:53 +0000 Subject: [PATCH 10/10] =?UTF-8?q?chore(release):=20=E9=A2=84=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E5=87=86=E5=A4=87=EF=BC=8C=E5=AF=B9=E9=BD=90=E5=85=A8?= =?UTF-8?q?=E9=93=BE=E8=B7=AF=E7=BD=91=E7=BB=9C=E4=BB=93=E5=BA=93=E6=BA=90?= =?UTF-8?q?=E8=87=B3=20main=20=E5=88=86=E6=94=AF=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=85=A8=E7=AB=99=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E8=87=B3=20v4.2.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/install.sh | 2 +- master/install_master.sh | 2 +- master/tg_master.sh | 2 +- version.txt | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/install.sh b/core/install.sh index c3ae377b..08adba32 100755 --- a/core/install.sh +++ b/core/install.sh @@ -61,7 +61,7 @@ fi echo -e "======================================\n" sleep 1 -REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/feature/v4.2.0-dual-stack" +REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main" INSTALL_DIR="/opt/ip_sentinel" CONFIG_FILE="${INSTALL_DIR}/config.conf" diff --git a/master/install_master.sh b/master/install_master.sh index da9ed9c1..1397b2b0 100755 --- a/master/install_master.sh +++ b/master/install_master.sh @@ -60,7 +60,7 @@ fi echo -e "======================================\n" sleep 1 -REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/feature/v4.2.0-dual-stack" +REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main" # [链路容灾] 双栈冗余防抖抓取,确立本地态势版本号 TARGET_VERSION=$( (curl -fsSL --connect-timeout 5 --retry 2 "${REPO_RAW_URL}/version.txt" || curl -4 -fsSL --connect-timeout 5 --retry 2 "${REPO_RAW_URL}/version.txt") 2>/dev/null | grep "^MASTER_VERSION=" | cut -d'=' -f2 | tr -d '[:space:]') diff --git a/master/tg_master.sh b/master/tg_master.sh index f8c75894..3f8aab5a 100755 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -9,7 +9,7 @@ CONF="/opt/ip_sentinel_master/master.conf" [ ! -f "$CONF" ] && exit 1 source "$CONF" -REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/feature/v4.2.0-dual-stack" +REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main" MASTER_VERSION=${MASTER_VERSION:-"3.5.0"} OFFSET_FILE="${MASTER_DIR}/.tg_offset" diff --git a/version.txt b/version.txt index 9535865c..77f49cd4 100644 --- a/version.txt +++ b/version.txt @@ -1,2 +1,2 @@ -MASTER_VERSION=4.1.7 -AGENT_VERSION=4.1.6 +MASTER_VERSION=4.2.2 +AGENT_VERSION=4.2.2