diff --git a/core/agent_daemon.sh b/core/agent_daemon.sh index 80f7b30..1da271a 100644 --- a/core/agent_daemon.sh +++ b/core/agent_daemon.sh @@ -1,12 +1,13 @@ #!/bin/bash # ========================================================== -# 脚本名称: agent_daemon.sh (受控节点 Webhook 守护进程) -# 核心功能: 向 Master 汇报公网 IP 注册、监听本地 HTTP 唤醒指令 +# 脚本名称: agent_daemon.sh (受控节点 Webhook 守护进程 V1.2) +# 核心功能: 智能防打扰注册、进程防冲突自检、后台静默监听 # ========================================================== INSTALL_DIR="/opt/ip_sentinel" CONFIG_FILE="${INSTALL_DIR}/config.conf" +IP_CACHE="${INSTALL_DIR}/core/.last_ip" # 【新增】本地 IP 状态缓存文件 [ ! -f "$CONFIG_FILE" ] && exit 1 source "$CONFIG_FILE" @@ -14,29 +15,43 @@ source "$CONFIG_FILE" # 如果没有配置 TG,说明未开启联控模式,直接退出 [ -z "$TG_TOKEN" ] || [ -z "$CHAT_ID" ] && exit 0 -# 默认 Webhook 监听端口,可在安装时动态写入配置 +# 默认 Webhook 监听端口 AGENT_PORT=${AGENT_PORT:-9527} -# 截取主机名作为节点唯一标识 (可限制长度防超长) NODE_NAME=$(hostname | cut -c 1-15) +# --- [重点升级 1: 守护进程防冲突自检] --- +# 检查是否已经有 webhook 进程在监听当前端口,如果有,直接安静退出 (Cron 友好) +if pgrep -f "webhook.py $AGENT_PORT" > /dev/null; then + # 保持静默,不输出多余日志,防止打扰系统的 syslog + exit 0 +fi + # 1. 获取本机原生公网 IPv4 AGENT_IP=$(curl -4 -s -m 5 api.ip.sb/ip) if [ -n "$AGENT_IP" ]; then - # 2. 向 Master 发送注册暗号 (借助 TG API) - # 【升级点】利用 TG API 机制,引导用户充当“安全网关”手动转发授权 - REG_MSG="👋 **[边缘节点接入申请]**%0A节点: \`${NODE_NAME}\`%0A地址: \`${AGENT_IP}:${AGENT_PORT}\`%0A%0A⚠️ **安全验证**: 为防止非法节点接入,请长按复制下方代码,并**发送给我**以完成最终授权录入:%0A%0A\`#REGISTER#|${NODE_NAME}|${AGENT_IP}|${AGENT_PORT}\`" - - curl -s -m 5 -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \ - -d "chat_id=${CHAT_ID}" \ - -d "text=${REG_MSG}" \ - -d "parse_mode=Markdown" > /dev/null - - echo "✅ [Agent] 已向司令部发送接入申请,请在 Telegram 手机端完成授权!" + # --- [重点升级 2: 智能防打扰注册机制] --- + LAST_IP="" + [ -f "$IP_CACHE" ] && LAST_IP=$(cat "$IP_CACHE") + + # 只有当这是第一次运行,或者公网 IP 发生变动时,才发送 Telegram 申请 + if [ "$AGENT_IP" != "$LAST_IP" ]; then + REG_MSG="👋 **[边缘节点接入申请]**%0A节点: \`${NODE_NAME}\`%0A地址: \`${AGENT_IP}:${AGENT_PORT}\`%0A%0A⚠️ **安全验证**: 为防止非法节点接入,请长按复制下方代码,并**发送给我**以完成最终授权录入:%0A%0A\`#REGISTER#|${NODE_NAME}|${AGENT_IP}|${AGENT_PORT}\`" + + curl -s -m 5 -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \ + -d "chat_id=${CHAT_ID}" \ + -d "text=${REG_MSG}" \ + -d "parse_mode=Markdown" > /dev/null + + echo "✅ [Agent] 已向司令部发送接入申请,请在 Telegram 手机端完成授权!" + # 记录当前 IP 到缓存文件 + echo "$AGENT_IP" > "$IP_CACHE" + else + echo "ℹ️ [Agent] IP 未变动 ($AGENT_IP),跳过重复注册申请。" + fi fi # 3. 启动轻量级 Python3 Webhook 监听服务 -# (相比纯 Bash 的 nc 命令,Python3 的 HTTP 库在各发行版间兼容性最完美,且支持并发) cat > "${INSTALL_DIR}/core/webhook.py" << 'EOF' import http.server import socketserver @@ -55,13 +70,10 @@ class AgentHandler(http.server.BaseHTTPRequestHandler): # 路由分发 if self.path == '/trigger_run': - # 另起后台进程执行深度伪装,不阻塞 Webhook 响应 subprocess.Popen(['bash', '/opt/ip_sentinel/core/mod_google.sh']) elif self.path == '/trigger_report': - # 另起后台进程执行战报生成 subprocess.Popen(['bash', '/opt/ip_sentinel/core/tg_report.sh']) elif self.path == '/trigger_log': - # 【新增升级】抓取最后15行日志并通过 TG 原路返回 (直接通过 bash -c 运行复合命令) bash_cmd = """ source /opt/ip_sentinel/config.conf LOG_DATA=$(tail -n 15 /opt/ip_sentinel/logs/sentinel.log) @@ -84,5 +96,12 @@ except Exception as e: sys.exit(1) EOF -# 保持前台运行 (被 Cron 的 nohup 放入后台守护) -python3 "${INSTALL_DIR}/core/webhook.py" "$AGENT_PORT" \ No newline at end of file +# --- [重点升级 3: 真正的静默后台启动] --- +echo "🚀 [Agent] 正在后台启动 Webhook 监听服务 (端口: $AGENT_PORT)..." +# 使用 nohup 和 & 将进程完全推入后台,不阻塞当前终端 +nohup python3 "${INSTALL_DIR}/core/webhook.py" "$AGENT_PORT" > /dev/null 2>&1 & + +# 尝试脱离终端会话控制 (忽略报错以兼容不同 shell 环境) +disown 2>/dev/null || true + +echo "✅ [Agent] 守护进程启动完毕,可安全关闭终端。" \ No newline at end of file diff --git a/core/install.sh b/core/install.sh index 5eae86e..7798f1d 100755 --- a/core/install.sh +++ b/core/install.sh @@ -1,8 +1,8 @@ #!/bin/bash # ========================================================== -# 脚本名称: install.sh (IP-Sentinel 分布式边缘节点部署脚本 V5.0) -# 核心功能: 区域选择、一键卸载、解析冷数据、配置高频调度与 Webhook 守护 +# 脚本名称: install.sh (IP-Sentinel 分布式边缘节点部署脚本 V5.1) +# 核心功能: 区域选择、一键卸载、解析冷数据、配置高频调度与双重 Webhook 守护 # ========================================================== # 你的专属 Forgejo 仓库 Raw 数据直链前缀 @@ -106,7 +106,6 @@ curl -sL "${REPO_RAW_URL}/core/runner.sh" -o "${INSTALL_DIR}/core/runner.sh" curl -sL "${REPO_RAW_URL}/core/mod_google.sh" -o "${INSTALL_DIR}/core/mod_google.sh" curl -sL "${REPO_RAW_URL}/core/updater.sh" -o "${INSTALL_DIR}/core/updater.sh" curl -sL "${REPO_RAW_URL}/core/tg_report.sh" -o "${INSTALL_DIR}/core/tg_report.sh" -# 【核心替换】下载边缘节点的 Webhook 守护进程 curl -sL "${REPO_RAW_URL}/core/agent_daemon.sh" -o "${INSTALL_DIR}/core/agent_daemon.sh" curl -sL "${REPO_RAW_URL}/core/uninstall.sh" -o "${INSTALL_DIR}/core/uninstall.sh" chmod +x ${INSTALL_DIR}/core/*.sh @@ -128,11 +127,14 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then # 每天早上 8 点发送昨天的统计战报 echo "0 8 * * * ${INSTALL_DIR}/core/tg_report.sh >/dev/null 2>&1" >> /tmp/cron_backup - # 边缘守护进程看门狗: 检查 agent_daemon.sh (或其拉起的 webhook.py) 是否存活 - echo "* * * * * pgrep -f webhook.py >/dev/null || nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup + # 【升级点】双保险守护进程看门狗: + # 1. 保证服务器重启后开机秒唤醒 + echo "@reboot nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup + # 2. 保证平时手滑杀掉进程后,1分钟内自动复活 (由于 daemon 脚本内自带 pgrep 防冲突,这里可以直接调用) + echo "* * * * * nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup # 安装时立刻启动一次边缘守护进程 (触发注册与 Webhook 监听) - pgrep -f webhook.py >/dev/null || nohup bash "${INSTALL_DIR}/core/agent_daemon.sh" >/dev/null 2>&1 & + nohup bash "${INSTALL_DIR}/core/agent_daemon.sh" >/dev/null 2>&1 & fi crontab /tmp/cron_backup diff --git a/master/tg_master.sh b/master/tg_master.sh index 48b01ae..7b48056 100644 --- a/master/tg_master.sh +++ b/master/tg_master.sh @@ -1,8 +1,8 @@ #!/bin/bash # ========================================================== -# 脚本名称: tg_master.sh (Master 端调度枢纽) -# 核心功能: 监听 TG、操作 SQLite、向 Agent 发送多维 Webhook 指令 +# 脚本名称: tg_master.sh (Master 端调度枢纽 V1.2) +# 核心功能: 监听 TG、操作 SQLite、Webhook 调度、僵尸节点清理 # ========================================================== CONF="/opt/ip_sentinel_master/master.conf" @@ -85,13 +85,32 @@ while true; do manage:*) TARGET_NODE=${TEXT#*:} - # 【升级点】补齐包含 run、log、report 的复合面板菜单 - BTNS="[[{\"text\":\"▶️ 执行深度伪装\",\"callback_data\":\"run:$TARGET_NODE\"}, {\"text\":\"📜 查看实时日志\",\"callback_data\":\"log:$TARGET_NODE\"}], [{\"text\":\"📊 索要统计战报\",\"callback_data\":\"report:$TARGET_NODE\"}, {\"text\":\"⬅️ 返回主列表\",\"callback_data\":\"list_nodes\"}]]" + # 【升级点 1】重构战术面板排版,新增 [剔除失联节点] 按钮,采用 3 行优雅布局 + BTNS="[[{\"text\":\"▶️ 执行深度伪装\",\"callback_data\":\"run:$TARGET_NODE\"}, {\"text\":\"📜 查看实时日志\",\"callback_data\":\"log:$TARGET_NODE\"}], [{\"text\":\"📊 索要统计战报\",\"callback_data\":\"report:$TARGET_NODE\"}, {\"text\":\"🗑️ 剔除失联节点\",\"callback_data\":\"del:$TARGET_NODE\"}], [{\"text\":\"⬅️ 返回主列表\",\"callback_data\":\"list_nodes\"}]]" send_ui "$CHAT_ID" "⚙️ **目标锁定**: \`$TARGET_NODE\`\n请选择战术动作:" "$BTNS" ;; + del:*) + # 【升级点 2】执行数据库硬删除,并自动刷新节点列表 + TARGET_NODE=${TEXT#*:} + db_exec "DELETE FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE';" + send_msg "$CHAT_ID" "🗑️ 节点 \`$TARGET_NODE\` 的档案已从司令部彻底销毁!" + + # 删除后自动重新渲染节点列表展示 + NODE_LIST=$(db_exec "SELECT node_name FROM nodes WHERE chat_id='$CHAT_ID';") + if [ -z "$NODE_LIST" ]; then + send_msg "$CHAT_ID" "⚠️ 当前司令部已无任何节点挂载。" + else + BTNS="[" + for N in $NODE_LIST; do + BTNS="$BTNS[{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"}]," + done + BTNS="${BTNS%,}]" + send_ui "$CHAT_ID" "🔍 刷新后的节点列表:" "$BTNS" + fi + ;; + run:*|report:*|log:*) - # 【升级点】合并 Webhook 触发逻辑,智能识别动作类型 ACTION_TYPE=$(echo "$TEXT" | cut -d':' -f1) TARGET_NODE=$(echo "$TEXT" | cut -d':' -f2) @@ -103,13 +122,12 @@ while true; do if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [$ACTION_TYPE] 指令,请稍候..." - # 向 Agent 的开放端口发送动态 Webhook 唤醒指令 (如 trigger_run, trigger_log) + # 向 Agent 的开放端口发送动态 Webhook 唤醒指令 RESPONSE=$(curl -s -m 5 "http://${AGENT_IP}:${AGENT_PORT}/trigger_${ACTION_TYPE}" || echo "FAILED") if [ "$RESPONSE" == "FAILED" ]; then send_msg "$CHAT_ID" "❌ 指令下发超时或失败!请检查节点公网 IP 或防火墙端口 ($AGENT_PORT) 是否放行。" else - # 只有 run 指令需要主控单独回复确认,log 和 report 会由 Agent 直接将内容发到你的 TG if [ "$ACTION_TYPE" == "run" ]; then send_msg "$CHAT_ID" "✅ 节点 \`$TARGET_NODE\` 回应: 指令已接收,伪装程序启动。" fi