Compare commits

...

28 Commits

Author SHA1 Message Date
hotyue
16b6c3f20a feat(core/daemon): 适配 V3.1.3 协议,IP变动或重连时自动上报大区坐标 2026-04-11 11:51:24 +00:00
hotyue
e3750f4565 feat(core/install): 适配 V3.1.3 协议,新节点注册暗号自动注入国家大区 (REGION_CODE) 2026-04-11 11:51:19 +00:00
hotyue
d3face9621 feat(master): V3.1.3 面板重构,新增大区多级折叠目录与双列排版,平滑升级 DB 协议 2026-04-11 11:51:14 +00:00
hotyue
aeeb9e1a43 docs: 完善 README 文档,新增玻璃房透明遥测、丝滑交互特性说明及完整拓扑架构 2026-04-11 11:27:40 +00:00
hotyue
09c6bab04a fix(master): 收敛 offset 记录文件至私有目录,修复 /tmp 侧信道劫持隐患 2026-04-11 11:24:13 +00:00
hotyue
2e73aa8833 feat(data): 新增美西核心节点 - 加州圣何塞 (San Jose) LBS 与专属配置 2026-04-11 11:21:57 +00:00
hotyue
03d88f4856 feat(master): 优化 TG 交互体验,哨兵节点注册成功后自动呼出最新活跃节点面板 2026-04-11 08:15:16 +00:00
hotyue
3cab2b2379 chore(core): 将官方公共机器人安全网关 API 从测试环境切换为正式生产环境 2026-04-11 07:55:30 +00:00
hotyue
87faeae8f7 fix(core): 修复首次安装时 agent_daemon 抢跑导致的重复注册推送问题 2026-04-11 07:33:44 +00:00
hotyue
19f0bb7c36 docs: 全面刷新 README 文档,点亮 v3.1.2 透明装机量徽章并重写核心极客特性 2026-04-11 07:12:48 +00:00
hotyue
01305f98b5 feat(master): Master 脚本接入透明统计,并新增部署前旧进程自洁功能 2026-04-11 07:08:21 +00:00
hotyue
a3ae3b29f9 feat(core): Agent 安装脚本接入透明统计,安装尾声展示全球哨兵编号 2026-04-11 07:08:13 +00:00
hotyue
053c9805d4 feat(telemetry): 开源玻璃房计划 (Glasshouse) Cloudflare Worker 计数器源码 2026-04-11 07:08:05 +00:00
hotyue
be51aab0e0 feat(core): 升级全球节点拓扑图接入香港阵地,正式发布 v3.1.1 2026-04-11 05:32:03 +00:00
hotyue
426fa74ff1 feat(data): 新增亚太核心枢纽 中国香港(HK) 节点配置文件与本土化搜索词库 2026-04-11 05:31:56 +00:00
hotyue
9904246e45 feat(core): 优化 Agent 安装逻辑,新增部署前环境自洁功能 (自动清理僵尸进程与冗余定时任务) 2026-04-11 05:31:52 +00:00
hotyue
06f52cbe1d feat(core): 升级全球节点拓扑图,正式跃升至 v3.1.0 2026-04-11 02:38:27 +00:00
hotyue
33d75925a6 feat(data): 新增亚太枢纽 新加坡 节点配置文件与本土化搜索词库 2026-04-11 02:38:25 +00:00
hotyue
52fe92efe5 feat(data): 新增欧洲枢纽 法国(巴黎) 节点配置文件与本土化搜索词库 2026-04-11 02:38:25 +00:00
hotyue
7fec21280f feat(data): 新增欧洲枢纽 德国(法兰克福) 节点配置文件与本土化搜索词库 2026-04-11 02:38:25 +00:00
hotyue
84b5fef640 feat(data): 新增欧洲枢纽 英国(伦敦) 节点配置文件与本土化搜索词库 2026-04-11 02:38:25 +00:00
hotyue
9d2aa9fcd5 fix(agent): 提拔 urllib 依赖至全局作用域,修复局部变量遮蔽导致的 Webhook 空回复崩溃 bug (v3.0.4-hotfix) 2026-04-11 02:23:52 +00:00
hotyue
ca2608756d security(core): 引入时间戳与动态 HMAC-SHA256 签名,彻底斩断明文 PSK 泄露与重放攻击隐患 (v3.0.4) 2026-04-11 01:51:03 +00:00
hotyue
27ebcfd418 security(agent): Webhook 引入 ThreadingMixIn 升级为多线程并发模型,彻底免疫 Slowloris 慢速网络耗尽攻击 (v3.0.3-part4) 2026-04-11 00:34:53 +00:00
hotyue
62deadda1e security(master): 部署脚本新增配置文件与数据库权限收敛 (chmod 600),防止 Bot Token 与节点网络拓扑泄露 (v3.0.3-part3) 2026-04-11 00:30:58 +00:00
hotyue
990d60f63a security(agent): 部署脚本新增配置文件权限收敛 (chmod 600),防止敏感 Token 发生本地提权泄露 (v3.0.3-part2) 2026-04-11 00:28:22 +00:00
hotyue
0571fcfd32 feat(install): 引入随机高位端口探测与占用校验,配合本地防火墙智能放行指引,提升防扫描隐蔽性 (v3.0.3-part1) 2026-04-11 00:12:12 +00:00
hotyue
4a77cb66d4 fix(agent): 引入 HTML 转义与 UA 伪装,修复日志回传中的 Markdown 解析冲突 (v3.0.2-final) 2026-04-10 16:25:04 +00:00
19 changed files with 688 additions and 96 deletions

View File

@@ -1,5 +1,9 @@
# 🛡️ IP-Sentinel (分布式 IP 哨兵集群)
![Agent Installs](https://img.shields.io/endpoint?url=https://ip-sentinel-count.samanthaestime296.workers.dev/stats/agent)
![Master Commands](https://img.shields.io/endpoint?url=https://ip-sentinel-count.samanthaestime296.workers.dev/stats/master)
![License](https://img.shields.io/github/license/hotyue/IP-Sentinel)
> **一个极度轻量、零感知、支持中枢遥控的 VPS IP 自动化养护与区域纠偏引擎。**
📢 官方战术交流频道: 🛰️ [IP-Sentinel Matrix](https://t.me/IP_Sentinel_Matrix)
@@ -8,13 +12,15 @@
## ✨ 核心极客特性
* 🗺️ **全球拓扑矩阵 (Global Nexus)****v3.0.0 新特性**。引入动态 `map.json` 索引中心与多级地理架构 (国家-省州-城市)。安装脚本全自动解析云端地图,支持无限扩展全球节点,真正实现“按图索骥”。
* ☁️ **云端中枢 (Public Master)**:引入官方公共机器人 [@OmniBeacon_bot](https://t.me/OmniBeacon_bot),新手无需部署 Master 司令部,一键回车即可接入全球养护矩阵,极大降低入伍门槛。
* 🗺️ **全球拓扑矩阵 (Global Nexus)****v3.1 跨洲际跃升**。守护版图现已横跨亚、欧、美三大洲(**美、日、英、德、法、新、港**)。为每个国家注入极其硬核的“原生本地化”搜索词库与本土高权重站点(如政府、权威媒体、高铁网),真正实现“拟真融入”。
* ☁️ **云端中枢 (Public Master)**:引入官方公共机器人 [@OmniBeacon_bot](https://t.me/OmniBeacon_bot),新手无需部署 Master 司令部,部署 Agent 时一键回车即可调用官方加密网关30 秒极速入伍!
* 🧠 **分布式中枢 (Master-Agent)**:对于硬核极客,支持私有化部署。一台 Master 主控集成 SQLite 数据库,统管无数台 Agent 边缘节点,确保数据绝对私有。
* 🎮 **TG 战术面板 (Command Center)**:无需记忆繁琐命令,原生 Inline Keyboard 按钮驱动。支持一键调出节点列表、一键下发伪装指令、一键索要精准战报、**毫秒级抓取实时运行日志**
* 🛡️ **NAT 穿透与安全网关 (NAT-Friendly)**:边缘节点采用 Python3 极轻量 Webhook 监听,**完全自定义通信端口**,完美支持受限 NAT 小鸡。独创 TG 转发授权机制,杜绝野生节点恶意接入
* 🔒 **叹息之墙 (Zero-Trust HMAC)****v3.1 核心重构**。全面废弃明文 Token底层通讯引入 `时间戳 + HMAC-SHA256` 军用级动态签名。指令有效期仅 60 秒(阅后即焚),彻底免疫中间人抓包、重放攻击与端口爆破
* 🛡️ **工业级并发与自净引擎**:底层 Webhook 采用多线程模型彻底免疫慢速耗尽攻击;独创“智能清道夫”逻辑,覆盖安装/升级时自动绞杀僵尸进程与冗余定时任务,绝对纯净,告别玄学冲突
* 🎮 **TG 战术面板 (Command Center)**:无需记忆繁琐命令,全 Inline Keyboard 交互。支持一键下发伪装指令、一键索要精准战报、**毫秒级抓取边缘节点实时运行日志**。
* 👻 **高仿真人类行为 (Human-Like)**:摒弃死板的 Ping/Curl引入单次会话指纹锁定、10 米级 GPS 坐标微抖动、以及 60~150 秒的真实阅读停顿拉伸,完美避开 AI 封控。
* 📡 **OTA 静默进化 (Smart Updates)**:系统每周日凌晨自动从云端拉取最新的“热搜词汇”和“真实设备指纹池”,确保养护行为与时俱进、永不过时
* 👁️‍🗨️ **玻璃房透明遥测 (Glasshouse Telemetry)****v3.1.2 全新上线**。引入基于 Cloudflare Workers 的全透明计数中枢,首页动态徽章实时展示全球真实装机与调用量。**绝对零隐私收集**,仅作原子累加,底层网关源码全开源,接受全网极客审计
***丝滑战术交互 (Seamless UI)**:司令部交互面板像素级打磨。新节点发送暗号入伍成功后,司令部将**无缝零延迟自动呼出**最新的活跃节点阵列面板,彻底免除重复输入命令的繁琐,掌控感拉满。
## 📂 项目架构 (Monorepo)
@@ -24,16 +30,17 @@
📦 IP-Sentinel
┣ 📂 master/ # 🧠 司令部SQLite 存储、TG 监听与 Webhook 调度中心
┣ 📂 core/ # 🛡️ 边缘哨兵Webhook 被动监听、高拟真养护引擎
📂 data/ # 🗂️ 全球数据规则库 (v3.0 全新拓扑)
┣ 📜 map.json # 🌐 全球区域索引大脑 (Master Index)
┣ 📂 regions/ # 🧊 冷数据:按 [国家/省州/城市] 深度细分的 LBS 锚点
┣ 📂 keywords/ # 🔥 热数据:按国家归类的动态搜索词库 (OTA 自动更新)
┗ 📜 user_agents.txt # 🔥 热数据:全局真实设备指纹池
📂 data/ # 🗂️ 全球数据规则库 (动态拓扑)
┣ 📜 map.json # 🌐 全球区域索引大脑 (Master Index)
┣ 📂 regions/ # 🧊 冷数据:按 [国家/省州/城市] 深度细分的 LBS 锚点
┣ 📂 keywords/ # 🔥 热数据:按国家归类的动态搜索词库 (OTA 自动更新)
┗ 📜 user_agents.txt # 🔥 热数据:全局真实设备指纹池
┗ 📂 telemetry/ # 👁️‍🗨️ 玻璃房计划Cloudflare Workers 透明计数器网关源码
```
## 🚀 极速部署 (Quick Start)
v3.0.0 提供了两种接入模式,请根据您的战术需求选择:
v3.1.x 提供了两种接入模式,请根据您的战术需求选择:
### 🔹 模式 A官方公共模式 (最简、推荐)
**适合不想折腾、只想快速养护 IP 的新兵。**
@@ -64,7 +71,7 @@ bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/core/i
🗑️ 一键无痕卸载
如果你需要清理某个边缘节点,只需重新运行 core/install.sh 并选择 [3],或直接在节点终端执行:
如果你需要清理某个边缘节点,只需重新运行 `core/install.sh` 并选择 **[2]**,或直接在节点终端执行:
```Bash
bash /opt/ip_sentinel/core/uninstall.sh

View File

@@ -1,7 +1,7 @@
#!/bin/bash
# ==========================================================
# 脚本名称: agent_daemon.sh (受控节点 Webhook 守护进程 V2.0)
# 脚本名称: agent_daemon.sh (受控节点 Webhook 守护进程 V3.0.3)
# 核心功能: 智能防打扰注册、进程自检、模块级路由分发(403拦截)
# ==========================================================
@@ -41,7 +41,8 @@ if [ -n "$AGENT_IP" ]; then
# 只有当这是第一次运行,或者公网 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}\`"
# V3.1.3 协议升级: 在底部暗号中精准嵌入 ${REGION_CODE} 大区标识
REG_MSG="👋 **[边缘节点接入申请]**%0A大区: \`${REGION_CODE}\`%0A节点: \`${NODE_NAME}\`%0A地址: \`${AGENT_IP}:${AGENT_PORT}\`%0A%0A⚠ **安全验证**: 为防止非法节点接入,请长按复制下方代码,并**发送给我**以完成最终授权录入:%0A%0A\`#REGISTER#|${REGION_CODE}|${NODE_NAME}|${AGENT_IP}|${AGENT_PORT}\`"
curl -s -m 5 -X POST "${TG_API_URL}" \
-d "chat_id=${CHAT_ID}" \
@@ -55,17 +56,25 @@ if [ -n "$AGENT_IP" ]; then
fi
fi
# 3. 启动轻量级 Python3 Webhook 监听服务 (带 403 权限校验路由)
# 3. 启动轻量级 Python3 Webhook 监听服务 (v3.0.4 动态 HMAC 签名防重放)
cat > "${INSTALL_DIR}/core/webhook.py" << 'EOF'
import http.server
import socketserver
import subprocess
import sys
import os
import html
# ================== [v3.0.4 新增密码学与解析依赖] ==================
import urllib.parse
import urllib.request # [修复] 提升至全局作用域,防止局部变量遮蔽
import hmac
import hashlib
import time
# ====================================================================
PORT = int(sys.argv[1])
# 🛡️ [v3.0.2 紧急加固] 提取全局鉴权 Token (利用 CHAT_ID 作为 PSK 预共享密钥)
# 🛡️ 提取全局鉴权 Token (利用 CHAT_ID 作为 PSK 预共享密钥)
AUTH_TOKEN = ""
if os.path.exists('/opt/ip_sentinel/config.conf'):
with open('/opt/ip_sentinel/config.conf', 'r') as f:
@@ -77,16 +86,49 @@ if os.path.exists('/opt/ip_sentinel/config.conf'):
class AgentHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
# 🛡️ 鉴权拦截器:防非法扫描与 DDoS 资源耗尽
if AUTH_TOKEN and f"auth={AUTH_TOKEN}" not in self.path:
self.send_response(401)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"401 Unauthorized: Access Denied\n")
return
# 🛡️ [v3.0.4 核心] URL 解析与动态 HMAC-SHA256 签名校验
parsed = urllib.parse.urlparse(self.path)
req_path = parsed.path
if AUTH_TOKEN:
query = urllib.parse.parse_qs(parsed.query)
req_t = query.get('t', [''])[0]
req_sign = query.get('sign', [''])[0]
# 校验 1参数是否齐全
if not req_t or not req_sign:
self.send_response(401)
self.end_headers()
self.wfile.write(b"401 Unauthorized: Missing Signature\n")
return
try:
# 校验 2时间戳防重放 (误差 ±60秒 内有效,拒绝隔夜抓包重放)
if abs(int(time.time()) - int(req_t)) > 60:
self.send_response(401)
self.end_headers()
self.wfile.write(b"401 Unauthorized: Request Expired\n")
return
except ValueError:
self.send_response(401)
self.end_headers()
return
# 校验 3HMAC 数据完整性与身份合法性校验
msg = f"{req_path}:{req_t}".encode('utf-8')
expected_sign = hmac.new(AUTH_TOKEN.encode('utf-8'), msg, hashlib.sha256).hexdigest()
# 使用 compare_digest 防御时序攻击
if not hmac.compare_digest(expected_sign, req_sign):
self.send_response(401)
self.end_headers()
self.wfile.write(b"401 Unauthorized: Signature Mismatch\n")
return
# 路由 1: Google 区域纠偏 (由于 URL 带有 auth 参数,必须由 == 改为 startswith)
if self.path.startswith('/trigger_google') or self.path.startswith('/trigger_run'):
# ================== 路由分发 (恢复为安全的精确匹配) ==================
# 路由 1: Google 区域纠偏
if req_path == '/trigger_google' or req_path == '/trigger_run':
if os.path.exists('/opt/ip_sentinel/core/mod_google.sh'):
self.send_response(200)
self.send_header("Content-type", "text/plain")
@@ -100,7 +142,7 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
self.wfile.write(b"403 Forbidden: Google Module Disabled\n")
# 路由 2: IP 信用净化
elif self.path.startswith('/trigger_trust'):
elif req_path == '/trigger_trust':
if os.path.exists('/opt/ip_sentinel/core/mod_trust.sh'):
self.send_response(200)
self.send_header("Content-type", "text/plain")
@@ -114,26 +156,21 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
self.wfile.write(b"403 Forbidden: Trust Module Disabled\n")
# 路由 3: 触发战报推送
elif self.path.startswith('/trigger_report'):
elif req_path == '/trigger_report':
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Action Accepted: tg_report\n")
subprocess.Popen(['bash', '/opt/ip_sentinel/core/tg_report.sh'])
# 路由 4: 抓取并回传实时日志 (v3.0.2 RCE 防御重构)
elif self.path.startswith('/trigger_log'):
# 路由 4: 抓取并回传实时日志
elif req_path == '/trigger_log':
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Action Accepted: fetch_log\n")
# 🛡️ 弃用高危 Bash 拼接,改用纯 Python 安全实现
import urllib.request
import urllib.parse
try:
# 1. 安全读取配置项 (不执行 source)
config = {}
if os.path.exists('/opt/ip_sentinel/config.conf'):
with open('/opt/ip_sentinel/config.conf', 'r') as f:
@@ -143,32 +180,32 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
key, val = line.split('=', 1)
config[key] = val.strip('"\'')
# 2. 安全截取日志最后15行
log_data = "日志文件不存在或为空"
log_path = '/opt/ip_sentinel/logs/sentinel.log'
if os.path.exists(log_path):
with open(log_path, 'r', errors='ignore') as f:
lines = f.readlines()
if lines:
log_data = "".join(lines[-15:])
log_data = html.escape("".join(lines[-15:]))
# 3. 安全获取主机名
node_name = subprocess.check_output(['hostname']).decode('utf-8').strip()[:15]
text_msg = f"📄 <b>[{node_name}] 实时运行日志:</b>\n<pre><code>{log_data}</code></pre>"
# 4. 构建并发送请求
text_msg = f"📄 **[{node_name}] 实时运行日志:**\n```log\n{log_data}\n```"
data = urllib.parse.urlencode({
'chat_id': config.get('CHAT_ID', ''),
'text': text_msg,
'parse_mode': 'Markdown'
'parse_mode': 'HTML'
}).encode('utf-8')
req = urllib.request.Request(config.get('TG_API_URL', ''), data=data)
req = urllib.request.Request(
config.get('TG_API_URL', ''),
data=data,
headers={'User-Agent': 'IP-Sentinel-Agent/3.0.4'}
)
urllib.request.urlopen(req, timeout=10)
except Exception as e:
# 仅在本地静默打印异常,防止信息泄露
print(f"Log fetch error: {e}")
print(f"Log transmission failed: {e}")
else:
self.send_response(404)
@@ -178,16 +215,18 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
pass
import socket
# [v3.0.1修复] 自定义支持双栈/IPv6的 Server 类
class DualStackServer(socketserver.TCPServer):
# ================== [v3.0.3 变更: 引入多线程模型抵抗 Slowloris 攻击] ==================
class ThreadedDualStackServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
allow_reuse_address = True # 开启端口复用,防止热重启时端口冲突
address_family = socket.AF_INET6 if socket.has_ipv6 else socket.AF_INET
try:
bind_addr = "::" if socket.has_ipv6 else ""
with DualStackServer((bind_addr, PORT), AgentHandler) as httpd:
with ThreadedDualStackServer((bind_addr, PORT), AgentHandler) as httpd:
httpd.serve_forever()
except Exception as e:
sys.exit(1)
# ====================================================================================
EOF
# --- [重点升级 3: 真正的静默后台启动] ---

View File

@@ -1,7 +1,7 @@
#!/bin/bash
# ==========================================================
# 脚本名称: install.sh (IP-Sentinel 分布式边缘节点部署脚本 v3.0.0 - Global Nexus)
# 脚本名称: install.sh (IP-Sentinel 分布式边缘节点部署脚本 v3.0.3 - Global Nexus)
# 核心功能: 区域选择、模块按需开启、官方机器人一键配置
# ==========================================================
@@ -51,6 +51,27 @@ if [ "$ACTION_CHOICE" == "2" ]; then
exit 0
fi
# ================== [v3.1.1 新增: 安装前环境纯净度清理 (严格保留日志)] ==================
echo -e "\n⏳ 正在清理旧版守护进程与冗余任务 (保留历史日志)..."
# 1. 强制超度可能存活的 Webhook 及各类看门狗进程,释放端口
pkill -9 -f "webhook.py" >/dev/null 2>&1 || true
pkill -9 -f "agent_daemon.sh" >/dev/null 2>&1 || true
pkill -9 -f "runner.sh" >/dev/null 2>&1 || true
# 2. 清除系统定时任务 (Cron) 中的旧版条目
if crontab -l >/dev/null 2>&1; then
crontab -l | grep -v "ip_sentinel" > /tmp/cron_clean
crontab /tmp/cron_clean
rm -f /tmp/cron_clean
fi
# 3. 抹除旧版核心代码与配置文件,杜绝代码冲突 (精准避开 logs 目录)
if [ -d "$INSTALL_DIR" ]; then
rm -rf "${INSTALL_DIR}/core" "${INSTALL_DIR}/data" "${INSTALL_DIR}/config.conf" "${INSTALL_DIR}/.last_ip" 2>/dev/null
fi
echo -e "\033[32m✅ 环境清理完毕,幽灵进程已肃清!\033[0m"
# ========================================================================================
# 📍 动态一级菜单:国家选择
echo -e "\n\033[36m📍 【第一级】请选择目标国家/地区:\033[0m"
jq -r '.countries[] | "\(.id)|\(.name)|\(.keyword_file)"' /tmp/map.json > /tmp/countries.txt
@@ -146,7 +167,7 @@ if [[ "$TG_CHOICE" =~ ^[Yy]$ ]]; then
if [ -z "$USER_TOKEN" ]; then
TG_TOKEN="OFFICIAL_GATEWAY_MODE"
TG_API_URL="https://omni-gateway.yuezhongjun.workers.dev"
TG_API_URL="https://omni-gateway.samanthaestime296.workers.dev"
echo -e "\033[32m✅ 已自动连接官方安全网关 (@OmniBeacon_bot)。\033[0m"
echo -e "\033[33m👉 请确保您已关注官方机器人并发送过 /start否则将无法接收消息。\033[0m"
else
@@ -157,8 +178,45 @@ if [[ "$TG_CHOICE" =~ ^[Yy]$ ]]; then
echo -e "\033[33m💡 提示:如果您不知道自己的 Chat ID可以关注 @userinfobot 获取。\033[0m"
read -p "请输入你的 Chat ID (与主控一致): " CHAT_ID
read -p "请输入本机用于接收指令的 Webhook 端口 (默认 9527): " INPUT_PORT
[ -n "$INPUT_PORT" ] && AGENT_PORT="$INPUT_PORT"
# ================== [v3.0.3 变更: 智能随机高位端口生成系统] ==================
echo -e "\n\033[36m[4.2/7] 正在构建 Webhook 安全通信隧道...\033[0m"
echo -n "🎲 正在探测可用随机端口..."
while true; do
RANDOM_PORT=$((RANDOM % 55536 + 10000))
# 同时兼容 ss (新) 和 netstat (旧) 检查端口占用
if ! (ss -tuln 2>/dev/null | grep -q ":$RANDOM_PORT " || netstat -tuln 2>/dev/null | grep -q ":$RANDOM_PORT "); then
break
fi
echo -n "."
done
echo -e " 完成!"
echo -e "💡 系统为您生成的推荐随机高位端口为: \033[32m$RANDOM_PORT\033[0m"
echo -e "\033[33m(该端口已通过本地占用校验,可直接使用)\033[0m"
while true; do
read -p "请输入 Webhook 监听端口 (回车采用推荐, 或手动输入): " INPUT_PORT
if [ -z "$INPUT_PORT" ]; then
AGENT_PORT="$RANDOM_PORT"
break
else
# 校验手动输入的合法性与可用性
if [[ "$INPUT_PORT" =~ ^[0-9]+$ ]] && [ "$INPUT_PORT" -ge 1 ] && [ "$INPUT_PORT" -le 65535 ]; then
if (ss -tuln 2>/dev/null | grep -q ":$INPUT_PORT " || netstat -tuln 2>/dev/null | grep -q ":$INPUT_PORT "); then
echo -e "\033[31m❌ 端口 $INPUT_PORT 已被占用,请重新输入或使用推荐端口。\033[0m"
else
AGENT_PORT="$INPUT_PORT"
break
fi
else
echo -e "\033[31m❌ 输入非法!端口范围应为 1-65535。\033[0m"
fi
fi
done
echo -e "✅ 已锁定 Webhook 通讯端口: \033[32m$AGENT_PORT\033[0m"
# ====================================================================
fi
# ================== [v3.0.1新增修改 1: 冗余网络栈探测与锚点锁定] ==================
@@ -261,6 +319,10 @@ IP_PREF="$IP_PREF"
BIND_IP="$BIND_IP"
EOF
# ================== [v3.0.3 变更: 敏感配置文件权限收敛] ==================
chmod 600 "$CONFIG_FILE"
# ====================================================================
# 6. 拉取全套组件 (按需下载,绝不浪费空间)
echo -e "\n[6/7] 正在根据模块开关部署核心引擎与热数据..."
# 基础公共组件
@@ -298,6 +360,11 @@ 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
# [v3.0.1新增修改 3: 删除原来的 curl 取 IP直接使用我们上方锁定的 BIND_IP]
# 并提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的重复推送
# [修复竞态]: 提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的抢跑推送
echo "$BIND_IP" > "${INSTALL_DIR}/core/.last_ip"
# 双保险守护进程看门狗
echo "@reboot nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup
echo "* * * * * nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup
@@ -311,14 +378,10 @@ rm -f /tmp/cron_backup
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
echo -e "\n📡 正在向指挥部发送注册暗号..."
# [v3.0.1新增修改 3: 删除原来的 curl 取 IP直接使用我们上方锁定的 BIND_IP]
# 并提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的重复推送
echo "$BIND_IP" > "${INSTALL_DIR}/core/.last_ip"
# 构造注册暗号 (使用带 [] 装甲的 BIND_IP防止 Master 端解析错误)
# 构造注册暗号 (V3.1.3 协议升级: 携带 REGION_CODE 大区标识)
NODE_NAME=$(hostname | cut -c 1-15)
REG_MSG="#REGISTER#|${NODE_NAME}|${BIND_IP}|${AGENT_PORT}"
REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${BIND_IP}|${AGENT_PORT}"
# 执行主动推送
PUSH_RESULT=$(curl -s -X POST "${TG_API_URL}" \
@@ -345,7 +408,34 @@ echo "📍 你的本地守护区域已锁定为: $REGION_NAME"
echo "⚙️ 哨兵现已开启 [每30分钟] 的高频高拟真养护循环。"
if [[ -n "$TG_TOKEN" ]]; then
echo "📡 Webhook 监听已启动 (端口: $AGENT_PORT) 并向中枢发送了注册请求。"
echo "⚠️ 请务必确保本机的防火墙放行了 TCP $AGENT_PORT 端口!"
# ================== [v3.0.3 变更: 智能防火墙检测与放行指引] ==================
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
FW_MSG="iptables -I INPUT -p tcp --dport $AGENT_PORT -j ACCEPT"
fi
echo -e "\033[33m⚠ 警告:请务必确保本机及云服务商安全组放行了 TCP $AGENT_PORT 端口!\033[0m"
if [ -n "$FW_MSG" ]; then
echo "💡 检测到本地防火墙开启,您可以尝试执行以下命令放行:"
echo -e "\033[36m $FW_MSG\033[0m"
fi
# ====================================================================
fi
echo "🗑️ 若未来需卸载,可重新运行本脚本选择[3]或执行: bash ${INSTALL_DIR}/core/uninstall.sh"
echo "========================================================"
echo "🗑️ 若未来需卸载,可重新运行本脚本选择[2]或执行: bash ${INSTALL_DIR}/core/uninstall.sh"
echo "========================================================"
# ================== [v3.1.2 新增: 玻璃房透明装机统计] ==================
echo -e "\n📡 正在向开源社区汇报装机量 (完全匿名不收集IP)..."
AGENT_COUNT=$(curl -s -m 3 "https://ip-sentinel-count.samanthaestime296.workers.dev/ping/agent" || echo "")
if [ -n "$AGENT_COUNT" ] && [[ "$AGENT_COUNT" =~ ^[0-9]+$ ]]; then
echo -e "\033[32m✅ 感谢您成为全球第 ${AGENT_COUNT} 名 IP-Sentinel 哨兵!\033[0m"
else
echo -e "\033[32m✅ 感谢您加入 IP-Sentinel 哨兵阵列!\033[0m"
fi
echo -e "\n"

10
data/keywords/kw_DE.txt Normal file
View File

@@ -0,0 +1,10 @@
wetter frankfurt heute
bundesliga ergebnisse
aktuelle nachrichten deutschland
restaurant in der nähe
deutsche bahn fahrplan
urlaub buchen
rezept für kartoffelsalat
dax aktueller stand
apotheke notdienst frankfurt
günstige flüge

10
data/keywords/kw_FR.txt Normal file
View File

@@ -0,0 +1,10 @@
meteo paris
actualités en direct
résultats ligue 1
pharmacie de garde
horaires sncf
recette crêpes
cac 40 en direct
acheter billet louvre
boulangerie autour de moi
carte vitale ameli

10
data/keywords/kw_HK.txt Normal file
View File

@@ -0,0 +1,10 @@
香港天文台天氣預報
MTR 港鐵路線圖
OpenRice 附近美食
LIHKG 討論區
恆生指數今日行情
SCMP breaking news
HKEX 港交所股價
國泰航空航班狀態
香港迪士尼樂園門票
百佳超級市場網購

10
data/keywords/kw_SG.txt Normal file
View File

@@ -0,0 +1,10 @@
singapore weather forecast
mrt map singapore
straitstimes breaking news
cpf board login
hdb bto launch updates
best chicken rice near me
public holidays sg
singpass login portal
changi airport flight status
iras tax filing

10
data/keywords/kw_UK.txt Normal file
View File

@@ -0,0 +1,10 @@
london weather today
bbc news latest
premier league fixtures
tesco near me
tube map london
uk bank holidays
royal family news
how to make english tea
nhs symptom checker
property for sale in london

View File

@@ -3,4 +3,7 @@ S&P 500 stock chart
local coffee shops near me
latest tech news
California traffic updates
AI startups in Silicon Valley
AI startups in Silicon ValleySan Jose weather this weekend
Silicon Valley tech news
best tacos in San Jose
Apple park visitor center hours

View File

@@ -1,6 +1,6 @@
{
"version": "3.0.0",
"updated_at": "2026-04-09",
"version": "3.1.0",
"updated_at": "2026-04-11",
"countries": [
{
"id": "US",
@@ -11,7 +11,8 @@
"id": "CA",
"name": "California (加州)",
"cities": [
{ "id": "Los_Angeles", "name": "Los Angeles (洛杉矶)" }
{ "id": "Los_Angeles", "name": "Los Angeles (洛杉矶)" },
{ "id": "San_Jose", "name": "San Jose (圣何塞)" }
]
}
]
@@ -29,6 +30,76 @@
]
}
]
},
{
"id": "UK",
"name": "United Kingdom (英国)",
"keyword_file": "kw_UK.txt",
"states": [
{
"id": "Default",
"name": "Default State",
"cities": [
{ "id": "London", "name": "London (伦敦)" }
]
}
]
},
{
"id": "DE",
"name": "Germany (德国)",
"keyword_file": "kw_DE.txt",
"states": [
{
"id": "Default",
"name": "Default State",
"cities": [
{ "id": "Frankfurt", "name": "Frankfurt (法兰克福)" }
]
}
]
},
{
"id": "FR",
"name": "France (法国)",
"keyword_file": "kw_FR.txt",
"states": [
{
"id": "Default",
"name": "Default State",
"cities": [
{ "id": "Paris", "name": "Paris (巴黎)" }
]
}
]
},
{
"id": "SG",
"name": "Singapore (新加坡)",
"keyword_file": "kw_SG.txt",
"states": [
{
"id": "Default",
"name": "Default State",
"cities": [
{ "id": "Singapore", "name": "Singapore (新加坡)" }
]
}
]
},
{
"id": "HK",
"name": "Hong Kong (香港)",
"keyword_file": "kw_HK.txt",
"states": [
{
"id": "Default",
"name": "Default State",
"cities": [
{ "id": "HongKong", "name": "Hong Kong (香港)" }
]
}
]
}
]
}

View File

@@ -0,0 +1,20 @@
{
"region_name": "Germany - Frankfurt",
"google_module": {
"base_lat": 50.1109,
"base_lon": 8.6821,
"lang_params": "hl=de&gl=DE",
"valid_url_suffix": "de"
},
"trust_module": {
"white_urls": [
"https://www.amazon.de/",
"https://www.spiegel.de/",
"https://www.tagesschau.de/",
"https://de.wikipedia.org/wiki/Spezial:Zuf%C3%A4llige_Seite",
"https://www.ebay.de/",
"https://www.bild.de/",
"https://www.kicker.de/"
]
}
}

View File

@@ -0,0 +1,20 @@
{
"region_name": "France - Paris",
"google_module": {
"base_lat": 48.8566,
"base_lon": 2.3522,
"lang_params": "hl=fr&gl=FR",
"valid_url_suffix": "fr"
},
"trust_module": {
"white_urls": [
"https://www.lemonde.fr/",
"https://www.lefigaro.fr/",
"https://www.amazon.fr/",
"https://www.service-public.fr/",
"https://fr.wikipedia.org/wiki/Sp%C3%A9cial:Page_au_hasard",
"https://www.cdiscount.com/",
"https://www.fnac.com/"
]
}
}

View File

@@ -0,0 +1,20 @@
{
"region_name": "Hong Kong",
"google_module": {
"base_lat": 22.2847,
"base_lon": 114.1582,
"lang_params": "hl=zh-HK&gl=HK",
"valid_url_suffix": "com.hk"
},
"trust_module": {
"white_urls": [
"https://www.gov.hk/",
"https://www.hko.gov.hk/",
"https://www.scmp.com/",
"https://www.hk01.com/",
"https://zh.wikipedia.org/wiki/Special:Random",
"https://www.hktvmall.com/",
"https://www.mtr.com.hk/"
]
}
}

View File

@@ -0,0 +1,20 @@
{
"region_name": "Singapore - Singapore",
"google_module": {
"base_lat": 1.3521,
"base_lon": 103.8198,
"lang_params": "hl=en-SG&gl=SG",
"valid_url_suffix": "com.sg"
},
"trust_module": {
"white_urls": [
"https://www.straitstimes.com/",
"https://www.channelnewsasia.com/",
"https://www.gov.sg/",
"https://shopee.sg/",
"https://en.wikipedia.org/wiki/Special:Random",
"https://www.fairprice.com.sg/",
"https://www.dbs.com.sg/"
]
}
}

View File

@@ -0,0 +1,20 @@
{
"region_name": "United Kingdom - London",
"google_module": {
"base_lat": 51.5074,
"base_lon": -0.1278,
"lang_params": "hl=en&gl=GB",
"valid_url_suffix": "co.uk"
},
"trust_module": {
"white_urls": [
"https://www.bbc.co.uk/",
"https://www.gov.uk/",
"https://www.amazon.co.uk/",
"https://www.theguardian.com/uk",
"https://www.nhs.uk/",
"https://en.wikipedia.org/wiki/Special:Random",
"https://www.ebay.co.uk/"
]
}
}

View File

@@ -0,0 +1,21 @@
{
"region_name": "United States - San Jose",
"google_module": {
"base_lat": 37.3382,
"base_lon": -121.8863,
"lang_params": "hl=en&gl=US",
"valid_url_suffix": "com"
},
"trust_module": {
"white_urls": [
"https://en.wikipedia.org/wiki/Special:Random",
"https://www.yahoo.com/",
"https://www.target.com/",
"https://www.npr.org/",
"https://www.weather.com/",
"https://www.amazon.com/",
"https://www.cdc.gov/",
"https://www.mercurynews.com/"
]
}
}

View File

@@ -29,6 +29,11 @@ if [ "$ACTION_CHOICE" == "2" ]; then
exit 0
fi
# ================== [v3.1.1 延续: 安装前环境纯净度清理] ==================
echo -e "\n⏳ 正在清理旧版 Master 守护进程 (绝对安全保留 SQLite 数据库)..."
pkill -9 -f "tg_master.sh" >/dev/null 2>&1 || true
# =======================================================================
# 1. 环境依赖安装
echo "[1/4] 安装核心依赖 (curl, jq, sqlite3)..."
if [ -f /etc/debian_version ]; then
@@ -64,6 +69,11 @@ CREATE TABLE IF NOT EXISTS nodes (
EOF
echo "✅ 数据库创建成功: $DB_FILE"
# ================== [v3.0.3 变更: 敏感文件权限收敛] ==================
chmod 600 "${MASTER_DIR}/master.conf"
chmod 600 "$DB_FILE"
# ====================================================================
# 4. 拉取核心调度代码并运行
echo -e "\n[4/4] 部署 TG 调度守护进程..."
# [修改] 剥离了写死的网址,改用顶部的 ${REPO_RAW_URL} 变量,确保与卸载脚本的数据源同源
@@ -82,4 +92,15 @@ pgrep -f tg_master.sh >/dev/null || nohup bash "${MASTER_DIR}/tg_master.sh" >/de
echo "========================================================"
echo "🎉 Master 控制中枢部署完成!"
echo "🤖 机器人现已开始全局接客,等待边缘节点注册。"
echo "========================================================"
echo "========================================================"
# ================== [v3.1.2 新增: 玻璃房透明装机统计] ==================
echo -e "\n📡 正在向开源社区汇报装机量 (完全匿名不收集IP)..."
MASTER_COUNT=$(curl -s -m 3 "https://ip-sentinel-count.samanthaestime296.workers.dev/ping/master" || echo "")
if [ -n "$MASTER_COUNT" ] && [[ "$MASTER_COUNT" =~ ^[0-9]+$ ]]; then
echo -e "\033[32m✅ 感谢您成为全球第 ${MASTER_COUNT} 名 IP-Sentinel 指挥官!\033[0m"
else
echo -e "\033[32m✅ 感谢您建立 IP-Sentinel 司令部!\033[0m"
fi
echo -e "\n"

View File

@@ -1,7 +1,7 @@
#!/bin/bash
# ==========================================================
# 脚本名称: tg_master.sh (Master 端调度枢纽 V2.0 模块化适配版)
# 脚本名称: tg_master.sh (Master 端调度枢纽 V3.0.4 动态签名版)
# 核心功能: 监听 TG、操作 SQLite、Webhook 精准调度、403权限拦截、僵尸节点清理
# ==========================================================
@@ -9,7 +9,7 @@ CONF="/opt/ip_sentinel_master/master.conf"
[ ! -f "$CONF" ] && exit 1
source "$CONF"
OFFSET_FILE="/tmp/tg_master_offset"
OFFSET_FILE="${MASTER_DIR}/.tg_offset"
[[ -f $OFFSET_FILE ]] || echo "0" > $OFFSET_FILE
# --- 工具函数 ---
@@ -35,6 +35,30 @@ db_exec() {
sqlite3 "$DB_FILE" "$1"
}
# ================== [v3.0.4 核心: 动态 HMAC 签名生成器] ==================
# 用法: generate_signed_url <IP> <PORT> <PATH>
generate_signed_url() {
local target_ip=$1
local target_port=$2
local action_path=$3
local current_t=$(date +%s)
# 构建加密载荷: "路径:时间戳"
local payload="${action_path}:${current_t}"
# 使用 CHAT_ID 作为密钥,生成 SHA256 HMAC 签名
local signature=$(echo -n "$payload" | openssl dgst -sha256 -hmac "$CHAT_ID" | awk '{print $NF}')
# 返回最终带签名的 URL
echo "http://${target_ip}:${target_port}${action_path}?t=${current_t}&sign=${signature}"
}
# ========================================================================
# ================== [v3.1.3 核心: 数据库结构无损热升级] ==================
# 自动探测并增加 region 字段,屏蔽已存在的报错,保护老节点数据
db_exec "ALTER TABLE nodes ADD COLUMN region TEXT DEFAULT 'UNKNOWN';" 2>/dev/null
# ========================================================================
# --- 核心轮询循环 ---
while true; do
OFFSET=$(cat $OFFSET_FILE)
@@ -60,33 +84,59 @@ while true; do
fi
# ==========================================
# 1. 节点注册通道 (v3.0.1 终极防注入补丁)
# 1. 节点注册通道 (V3.1.3 大区拓扑升级版)
# ==========================================
if [[ "$TEXT" == *"#REGISTER#"* ]]; then
REG_LINE=$(echo "$TEXT" | grep "#REGISTER#" | head -n 1 | tr -d '\` ')
IFS='|' read -r MAGIC RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
# 🛡️ 强制字符白名单过滤:物理抹杀所有 SQL 注入特殊字符
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-') # ChatID 只能是数字和负号
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) # IP 格式限制
AGENT_PORT=$(echo "$RAW_PORT" | tr -cd '0-9' | cut -c 1-5) # 端口只能是数字
# V3.1.3 兼容性拆包: 判断是新版协议 (5个字段) 还是老版协议 (4个字段)
FIELD_COUNT=$(echo "$REG_LINE" | awk -F'|' '{print NF}')
if [ "$FIELD_COUNT" -ge 5 ]; then
IFS='|' read -r MAGIC RAW_REGION RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
else
IFS='|' read -r MAGIC RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
RAW_REGION="UNKNOWN"
fi
# 🛡️ 强制字符白名单过滤:保留历史特征不变
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_PORT=$(echo "$RAW_PORT" | tr -cd '0-9' | cut -c 1-5)
# ================== [v3.0.2 紧急加固: SSRF 内网隔离墙] ==================
# 拒绝 127.x, 10.x, 192.168.x, 172.16~31.x 以及 IPv6 回环地址的注册
if [[ "$AGENT_IP" =~ ^127\.|^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^::1$|^localhost$ ]]; then
send_msg "$CHAT_ID" "⛔ **安全拦截**:禁止注册内网或回环 IP防止 SSRF 攻击渗透。"
continue
fi
# 异常拦截:如果核心字段被过滤成了空值,说明是恶意请求,直接抛弃
if [ -z "$NODE_NAME" ] || [ -z "$AGENT_IP" ] || [ -z "$AGENT_PORT" ] || [ -z "$CHAT_ID" ]; then
send_msg "$CHAT_ID" "⛔ **安全拦截**:检测到非法注册载荷,请求已拒绝。"
continue
fi
db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP) ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP;"
# 入库时追加 region 字段
db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen, region) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP, '$AGENT_REGION') ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP, region='$AGENT_REGION';"
send_msg "$CHAT_ID" "✅ 司令部已确认!节点接入成功: \`$NODE_NAME\` ($AGENT_IP:$AGENT_PORT)"
# ================== [v3.1.3 丝滑连招: 直接呼出全球大区雷达] ==================
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
if [ -n "$REGION_DATA" ]; then
BTNS="["
while IFS='|' read -r REGION_NAME NODE_COUNT; do
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
FLAG="🌐"
case "$REGION_NAME" in
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
esac
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
done <<< "$REGION_DATA"
BTNS="${BTNS%,}]"
send_ui "$CHAT_ID" "🌍 **全视界战略雷达**\n请选择要检阅的战区" "$BTNS"
fi
# ========================================================================
continue
fi
@@ -106,23 +156,80 @@ while true; do
else
send_msg "$CHAT_ID" "📢 **司令部指令下达:正在召唤所有哨兵回传简报...**"
echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do
# [v3.0.2 紧急加固] 批量下发战报时,必须同步追加 ?auth 鉴权令牌,防止被 Agent 拒绝
curl -s -m 5 "http://${AIP}:${APORT}/trigger_report?auth=${CHAT_ID}" > /dev/null &
# 🛡️ [v3.0.4] 动态签名防重放批量下发
TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_report")
curl -s -m 5 "$TARGET_URL" > /dev/null &
done
fi
;;
# ================== [补充缺失的全节点一键维护功能] ==================
"all_run")
NODE_DATA=$(db_exec "SELECT node_name, agent_ip, agent_port FROM nodes WHERE chat_id='$CHAT_ID';")
if [ -z "$NODE_DATA" ]; then
send_msg "$CHAT_ID" "⚠️ 您名下暂无在线节点。"
else
send_msg "$CHAT_ID" "📢 **司令部指令下达:正在唤醒所有哨兵执行系统维护...**"
echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do
# 🛡️ [v3.0.4] 动态签名防重放批量下发 (维护模块)
TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_run")
curl -s -m 5 "$TARGET_URL" > /dev/null &
done
fi
;;
# ====================================================================
"list_nodes")
NODE_LIST=$(db_exec "SELECT node_name FROM nodes WHERE chat_id='$CHAT_ID';")
if [ -z "$NODE_LIST" ]; then
# 【V3.1.3】一级菜单:大区聚合并列出数量
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
if [ -z "$REGION_DATA" ]; then
send_msg "$CHAT_ID" "⚠️ 您名下暂无在线节点,请先在边缘机执行部署。"
else
BTNS="["
for N in $NODE_LIST; do
BTNS="$BTNS[{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"}],"
done
while IFS='|' read -r REGION_NAME NODE_COUNT; do
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
FLAG="🌐"
case "$REGION_NAME" in
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
esac
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
done <<< "$REGION_DATA"
BTNS="${BTNS%,}]"
send_ui "$CHAT_ID" "🔍 您名下的活跃节点" "$BTNS"
send_ui "$CHAT_ID" "🌍 **全视界战略雷达**\n请选择要检阅的战区" "$BTNS"
fi
;;
region:*)
# 【V3.1.3】二级菜单:目标大区下的节点双列排版
TARGET_REGION=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9')
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
NODE_LIST=$(db_exec "SELECT node_name FROM nodes WHERE chat_id='$CHAT_ID' AND region='$TARGET_REGION';")
if [ -z "$NODE_LIST" ]; then
send_msg "$CHAT_ID" "⚠️ 该战区下暂无可用节点。"
else
BTNS="["
COL=0
ROW_STR="["
for N in $NODE_LIST; do
ROW_STR="$ROW_STR{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"},"
COL=$((COL+1))
if [ $COL -eq 2 ]; then
ROW_STR="${ROW_STR%,}]"
BTNS="$BTNS$ROW_STR,"
COL=0
ROW_STR="["
fi
done
# 如果是奇数,补齐最后的尾巴
if [ $COL -eq 1 ]; then
ROW_STR="${ROW_STR%,}]"
BTNS="$BTNS$ROW_STR,"
fi
# 添加返回上级大区雷达的按钮
BTNS="$BTNS[{\"text\":\"⬅️ 返回全球战区分布\",\"callback_data\":\"list_nodes\"}]]"
send_ui "$CHAT_ID" "📍 **[$TARGET_REGION] 战区哨兵矩阵**\n请下达控制指令" "$BTNS"
fi
;;
@@ -130,7 +237,7 @@ while true; do
# 🛡️ 强制过滤节点名,防止面板渲染时发生 XSS 或注入
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
# 【核心升级】拆分下发按钮,精准对应 Google 与 Trust 两个模块,并排版为 3 行 2 列
BTNS="[[{\"text\":\"📍 Google 纠偏\",\"callback_data\":\"google:$TARGET_NODE\"}, {\"text\":\"🛡️ 信用净化\",\"callback_data\":\"trust:$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\"}]]"
BTNS="[[{\"text\":\"📍 Google 纠偏\",\"callback_data\":\"google:$TARGET_NODE\"}, {\"text\":\"🛡️ 信用净化\",\"callback_data\":\"trust:$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"
;;
@@ -142,16 +249,23 @@ while true; do
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
# 剔除后直接返回上级一级雷达菜单
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
if [ -z "$REGION_DATA" ]; then
send_msg "$CHAT_ID" "⚠️ 当前司令部已无任何节点挂载。"
else
BTNS="["
for N in $NODE_LIST; do
BTNS="$BTNS[{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"}],"
done
while IFS='|' read -r REGION_NAME NODE_COUNT; do
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
FLAG="🌐"
case "$REGION_NAME" in
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
esac
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
done <<< "$REGION_DATA"
BTNS="${BTNS%,}]"
send_ui "$CHAT_ID" "🔍 刷新后的节点列表" "$BTNS"
send_ui "$CHAT_ID" "🌍 刷新后的全视界雷达" "$BTNS"
fi
;;
@@ -174,8 +288,9 @@ while true; do
send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [$ACTION_TYPE] 指令,请稍候..."
fi
# 触发 Webhook(v3.0.2 避免DDoS攻击加固)
RESPONSE=$(curl -s -m 5 "http://${AGENT_IP}:${AGENT_PORT}/trigger_${ACTION_TYPE}?auth=${CHAT_ID}" || echo "FAILED")
# 🛡️ [v3.0.4] 动态签名生成与触发 (防重放与防篡改)
TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_${ACTION_TYPE}")
RESPONSE=$(curl -s -m 5 "$TARGET_URL" || echo "FAILED")
# 结果判定
if [ "$RESPONSE" == "FAILED" ]; then

75
telemetry/worker.js Normal file
View File

@@ -0,0 +1,75 @@
// IP-Sentinel Glasshouse Telemetry (全透明装机量统计中枢)
// 部署环境: Cloudflare Workers + KV
// 隐私声明: 绝对不采集、不存储用户的 IP 地址、Header、Token 及任何系统特征参数。仅做纯粹的原子累加。
export default {
async fetch(request, env) {
const url = new URL(request.url);
const path = url.pathname;
// 全局跨域头,确保 GitHub README 的 Shields.io 徽章能正常读取
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET",
};
// 核心原子操作:无情的 +1 机器
async function incrementCounter(key) {
let count = await env.SENTINEL_KV.get(key);
count = count ? parseInt(count) + 1 : 1;
await env.SENTINEL_KV.put(key, count.toString());
return count;
}
async function getCounter(key) {
let count = await env.SENTINEL_KV.get(key);
return count ? parseInt(count) : 0;
}
try {
// 1. Agent (哨兵) 部署触发接口
if (path === '/ping/agent') {
const count = await incrementCounter('agent_count');
return new Response(count.toString(), { headers: corsHeaders });
}
// 2. Master (指挥部) 部署触发接口
if (path === '/ping/master') {
const count = await incrementCounter('master_count');
return new Response(count.toString(), { headers: corsHeaders });
}
// 3. GitHub README Agent 徽章接口 (输出给 Shields.io)
if (path === '/stats/agent') {
const count = await getCounter('agent_count');
const shield = {
schemaVersion: 1,
label: "Agent Nodes",
message: count.toString(),
color: "blue"
};
return new Response(JSON.stringify(shield), {
headers: { ...corsHeaders, "Content-Type": "application/json" }
});
}
// 4. GitHub README Master 徽章接口 (输出给 Shields.io)
if (path === '/stats/master') {
const count = await getCounter('master_count');
const shield = {
schemaVersion: 1,
label: "Master Commands",
message: count.toString(),
color: "orange"
};
return new Response(JSON.stringify(shield), {
headers: { ...corsHeaders, "Content-Type": "application/json" }
});
}
return new Response("IP-Sentinel Glasshouse Telemetry API (No IP Logged, 100% Transparent)", { status: 200 });
} catch (err) {
return new Response("Error", { status: 500 });
}
}
};