feat(webhook): 架构大跃迁!引入解耦型双轨独立监听器(Dual-Socket)彻底阻断内核态兼容冲突,并上线「前置安全遥测雷达」打破历史透明盲区

This commit is contained in:
hotyue
2026-06-08 07:49:17 +00:00
parent ed09ca5e58
commit c7b7b5ca84

View File

@@ -126,6 +126,18 @@ if os.path.exists('/opt/ip_sentinel/config.conf'):
class AgentHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
# ==========================================================
# 【核心加固】打破遥测盲区:请求一旦触达协议栈,在任何校验前强行审计
# ==========================================================
try:
log_dir = '/opt/ip_sentinel/logs'
os.makedirs(log_dir, exist_ok=True)
ts = time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())
with open(f'{log_dir}/agent.log', 'a', encoding='utf-8') as f:
f.write(f"[{ts}] [TELEMETRY] Connection received from {self.client_address} -> Path: {self.path}\n")
except Exception:
pass
# [权限校验] 路径解析与 HMAC-SHA256 动态签名核验
parsed = urllib.parse.urlparse(self.path)
req_path = parsed.path
@@ -484,55 +496,79 @@ fi
pass
import socket
import threading
# ----------------------------------------------------------
# [核心架构] 多线程非阻塞 Socket 模型 (抵抗 Slowloris 及阻塞攻击)
# [核心架构大跃迁: v4.3.2 双轨解耦监听防线]
# ----------------------------------------------------------
class DualStackServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
allow_reuse_address = True
class ThreadedServerV6(ThreadedServer):
"""专属 IPv6 隔离监听器,强行物理隔绝 IPv4 混杂空间,彻底阻断 EADDRINUSE 冲突"""
address_family = socket.AF_INET6
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
try:
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
except Exception:
pass
super().server_bind()
# [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
def main():
import ssl
cert_path = '/opt/ip_sentinel/core/cert.pem'
key_path = '/opt/ip_sentinel/core/key.pem'
context = None
if os.path.exists(cert_path) and os.path.exists(key_path):
try:
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile=cert_path, keyfile=key_path)
except Exception as e:
print(f"SSL Context creation failed: {e}")
DualStackServer.address_family = address_family
httpd = DualStackServer((bind_addr, PORT), AgentHandler)
servers = []
# ----------------------------------------------------------
# [加密通信] 强制全网挂载 TLS 加密隧道上下文
# ----------------------------------------------------------
import ssl
cert_path = '/opt/ip_sentinel/core/cert.pem'
key_path = '/opt/ip_sentinel/core/key.pem'
if os.path.exists(cert_path) and os.path.exists(key_path):
# 1. 尝试挂载 IPv4 独立对空雷达
try:
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile=cert_path, keyfile=key_path)
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
ThreadedServer.address_family = socket.AF_INET
srv_v4 = ThreadedServer(("0.0.0.0", PORT), AgentHandler)
if context:
srv_v4.socket = context.wrap_socket(srv_v4.socket, server_side=True)
servers.append(srv_v4)
print(f"📡 IPv4 Vector Socket binding established on 0.0.0.0:{PORT}")
except Exception as e:
print(f"SSL 隧道构建失败,退化为 HTTP: {e}")
print(f"⚠️ IPv4 Socket binding failed: {e}")
try:
httpd.serve_forever()
except Exception as e:
sys.exit(1)
# 2. 尝试挂载 IPv6 独立对空雷达 (强制隔离 IPv4)
try:
srv_v6 = ThreadedServerV6(("::", PORT), AgentHandler)
if context:
srv_v6.socket = context.wrap_socket(srv_v6.socket, server_side=True)
servers.append(srv_v6)
print(f"📡 IPv6 Vector Socket binding established on [::]:{PORT}")
except Exception as e:
print(f"⚠️ IPv6 Socket binding failed: {e}")
if not servers:
print("❌ [FATAL] Dual-Stack Network Radar completely localized binding failed!")
sys.exit(1)
# 3. 跨线程异步并发激活所有对空信道
for srv in servers:
t = threading.Thread(target=srv.serve_forever, daemon=True)
t.start()
# 4. 主守护线程,使用简单的时间挂起
try:
while True:
time.sleep(3600)
except KeyboardInterrupt:
sys.exit(0)
if __name__ == '__main__':
main()
EOF
echo "🚀 [Agent] 正在启动 Webhook 监听服务 (端口: $AGENT_PORT)..."
echo "🚀 [Agent] 正在启动双轨独立 Webhook 监听引擎 (端口: $AGENT_PORT)..."
exec python3 "${INSTALL_DIR}/core/webhook.py" "$AGENT_PORT"