ecan0/serpent-wrt
GitHub: ecan0/serpent-wrt
一个专为 OpenWRT 路由器设计的轻量级威胁情报检测与 nftables 阻断守护进程,通过读取 conntrack 表实现低资源占用的网络异常行为检测。
Stars: 0 | Forks: 0
# serpent-wrt
[](https://github.com/ecan0/serpent-wrt/actions/workflows/ci.yml)
[](https://golang.org/dl/)
[](LICENSE)
一个轻量级的威胁情报与执行守护进程,专为 OpenWRT 路由器设计。
serpent-wrt 使用 Linux conntrack 元数据监控网络连接,通过行为启发式检测可疑活动,并使用 nftables 执行拦截——无需数据包捕获,无需数据库,内存占用极低。专为内存低至 64 MB 的受限设备设计。
## 为什么选择 conntrack 而不是数据包捕获?
tcpdump 和 libpcap 会将每个数据包复制到用户空间。在配备 64 MB RAM 和 400 MHz MIPS CPU 的路由器上,这会产生持续的每数据包 CPU 开销、环形缓冲区带来的内存压力,以及任何 PCAP 存储带来的闪存磨损——而威胁信号并不需要有效载荷检查。
Linux 内核已经在 `nf_conntrack` 中维护了一个紧凑的每流状态表。无论流量如何,读取 `/proc/net/nf_conntrack` 每个轮询周期只需一次文件读取。
| | 数据包捕获 | conntrack |
|---|---|---|
| CPU 成本 | 每数据包 | 每轮询周期 |
| 内存 | 环形缓冲区 + 重组装 | 内核平面表 |
| 数据 | 每个字节 | 每流元数据 |
| 磁盘写入 | 可选的 PCAP 文件 | 无 |
| 执行 | 独立栈 | 复用现有 nftables |
## 架构
```
/proc/net/nf_conntrack
│
▼
collector ── poll interval ──▶ FlowRecord{proto, src, dst, ports, state}
│
▼
direction classifier
(skip: unroutable, broadcast, self)
│
├── LAN → WAN ──────────────────────────────────┐
│ ┌──────────────────────────────────────────┐ │
│ │ feed_match (threat feed hit) │ │
│ │ fanout (many distinct destinations) │ │
│ │ port_scan (many distinct ports) │ │
│ │ beacon (periodic C2 cadence) │ │
│ └──────────────────────────────────────────┘ │
│ │
└── WAN → LAN ──────────────────────────────────┘
┌──────────────────────────────────────────┐
│ ext_scan (external recon: many ports) │
│ brute_force (spray: same port, many hosts│
└──────────────────────────────────────────┘
│ Detection event
▼
dedup filter ──▶ suppress repeat alerts (sliding window)
│
▼
event logger ──▶ NDJSON to stdout
│ (+ optional remote syslog)
▼
nftables enforcer ──▶ inet blocked_ips set
```
## 功能
- 基于 conntrack 的流量采集——无需数据包捕获
- 本地 IP/CIDR 威胁源,支持通过 `SIGHUP` 热重载
- 六个行为检测器,涵盖出站和入站方向
- 方向感知路由:LAN→WAN 检测器(fanout、port_scan、beacon、feed_match)独立于 WAN→LAN 检测器(ext_scan、brute_force)运行
- 广播、回环、链路本地和路由器自身流量在任何检测器处理前自动过滤
- 去重抑制在可配置时间窗口内压缩同一来源的重复告警
- 通过命名集合的 nftables 执行,由内核管理超时
- 结构化 NDJSON 日志输出到 stdout
- 可选的远程 syslog 转发(UDP/TCP)用于 SIEM 集成——失败时自动重连
- 可选的仅本地主机 HTTP API
- 单一静态二进制文件——无数据库、无 systemd 依赖,兼容 procd
## 构建
```
# 本地二进制文件
make build # → bin/serpent-wrt
# 为 OpenWRT 目标交叉编译
make cross # → bin/serpent-wrt-linux-{mipsle,mips,armv7,arm64,amd64}
# x86/generic — 32位 OpenWRT 虚拟机 (uname -m = i686)
GOOS=linux GOARCH=386 go build -o bin/serpent-wrt-linux-386 ./cmd/serpent-wrt
# 运行测试
make test
```
**支持的目标平台:** `linux/mipsle`、`linux/mips`、`linux/arm`(v7)、`linux/arm64`、`linux/amd64`、`linux/386`
## 部署
### 首次设置
```
# 复制初始化脚本、配置和威胁情报到路由器
make deploy-setup DEPLOY_HOST=root@
# 构建并推送二进制文件 (x86/generic)
make deploy-x86 DEPLOY_HOST=root@
```
### 手动部署
许多 OpenWRT 构建版本省略了 `sftp-server`,因此 `scp` 和 `rsync` 会失败。改用 stdin 传输文件:
```
# 覆盖二进制文件前先停止服务(避免"Text file busy")
ssh root@router '/etc/init.d/serpent-wrt stop'
# 传输二进制文件
ssh root@router 'cat > /usr/sbin/serpent-wrt && chmod +x /usr/sbin/serpent-wrt' \
< bin/serpent-wrt-linux-386
# 传输配置和情报
ssh root@router 'cat > /etc/serpent-wrt/serpent-wrt.yaml' \
< configs/serpent-wrt.example.yaml
ssh root@router 'cat > /etc/serpent-wrt/threat-feed.txt' \
< testdata/threat-feed.txt
# 传输初始化脚本、启用并启动
ssh root@router 'cat > /etc/init.d/serpent-wrt && chmod +x /etc/init.d/serpent-wrt' \
< contrib/init.d/serpent-wrt
ssh root@router "/etc/init.d/serpent-wrt enable && /etc/init.d/serpent-wrt start"
```
### 热重载威胁源
```
# 无需重启重新加载 — 通过 procd reload 或直接触发:
kill -HUP $(pidof serpent-wrt)
```
## 配置
完整注解示例请参阅 [`configs/serpent-wrt.example.yaml`](configs/serpent-wrt.example.yaml)。
```
poll_interval: 5s
threat_feed_path: /etc/serpent-wrt/threat-feed.txt
enforcement_enabled: false # set true once nftables is verified working
block_duration: 1h
# LAN CIDR — 用于方向分类(LAN→WAN 与 WAN→LAN)
lan_cidrs:
- 192.168.1.0/24
# 路由器自身的 IP — 源自这些的流量在检测器运行前被过滤
# 添加每个接口 IP(LAN、WAN,回环自动)
self_ips:
- 192.168.1.1
nft_table: serpent_wrt
nft_set: blocked_ips
log_level: info
api_enabled: true
api_bind: 127.0.0.1:8080
# 可选:将 JSON 事件转发到远程 syslog 目标(如 Wazuh on port 514)
# syslog_target: "10.0.0.10:514"
# syslog_proto: "udp" # or "tcp"
detectors:
fanout:
distinct_dst_threshold: 50
window: 60s
scan:
distinct_port_threshold: 30
window: 60s
beacon:
min_hits: 5
tolerance: 3s
window: 5m
ext_scan:
distinct_port_threshold: 15
window: 60s
brute_force:
threshold: 5
window: 60s
```
## 威胁源格式
纯文本,每行一个 IPv4 地址或 CIDR。以 `#` 开头的行和空行将被忽略。
```
# 示例
1.2.3.4
185.220.101.0/24
```
## 检测器
所有检测器仅基于连接元数据运行——不检查有效载荷。
**出站(LAN → WAN)**
| 检测器 | 触发条件 | 关键配置 |
|---|---|---|
| `feed_match` | 源或目标 IP/CIDR 匹配威胁源 | `threat_feed_path` |
| `fanout` | 内部主机联系过多不同的外部目标 | `distinct_dst_threshold`、`window` |
| `port_scan` | 内部主机在单一目标上探测过多不同端口 | `distinct_port_threshold`、`window` |
| `beacon` | 内部主机以固定间隔联系同一目标 | `min_hits`、`tolerance`、`window` |
**入站(WAN → LAN)**
| 检测器 | 触发条件 | 关键配置 |
|---|---|---|
| `ext_scan` | 外部 IP 在单一内部主机上探测过多不同端口 | `distinct_port_threshold`、`window` |
| `brute_force` | 外部 IP 在多个内部主机上命中同一服务端口 | `threshold`、`window` |
ESTABLISHED TCP 流被排除在 beacon 检测器之外,以避免持久连接产生误报。`feed_match` 检测器同时检查源和目标,以捕获来自已知恶意 IP 的入站连接。
## API
当 `api_enabled: true` 时可用。仅绑定到本地主机。
| 端点 | 方法 | 描述 |
|---|---|---|
| `/healthz` | GET | `{"status":"ok"}` |
| `/stats` | GET | 运行时计数器(已见流量、按类型检测、应用拦截) |
| `/reload` | POST | 从磁盘热重载威胁源 |
| `/detections/recent` | GET | 最近 100 条检测记录 |
## 日志
NDJSON 输出到 stdout,每行一个事件:
```
{"time":"2025-01-01T00:00:00Z","level":"warn","type":"detection","detector":"feed_match","src_ip":"192.168.1.5","dst_ip":"1.2.3.4","dst_port":443,"message":"connection to threat feed entry 1.2.3.4"}
{"time":"2025-01-01T00:00:00Z","level":"warn","type":"enforcement","src_ip":"192.168.1.5","message":"blocked 192.168.1.5 triggered by feed_match"}
```
配置 `syslog_target` 后,每个事件还会作为 JSON 字符串转发到 syslog MSG 字段。兼容 Wazuh、Graylog 和任何 RFC 3164 syslog 接收器。发送方在写入失败时自动重连,因此 SIEM 的短暂重启不会永久破坏远程转发。
## 局限性
- **仅支持 IPv4** — IPv6 conntrack 条目被跳过
- **轮询而非事件驱动** — conntrack 按固定间隔读取;第 5 阶段将用 netlink 流式传输替换
- **无 DNS 关联** — 不解析或跟踪域名
- **不检查有效载荷** — 如上所述,这是设计意图
- **nft 子进程** — 执行调用 `nft` 子进程;在此规模下可接受
- **无持久状态** — 重启后检测历史和拦截状态丢失
- **仅本地威胁源** — MVP 中无远程源同步
## 路线图
| 阶段 | 状态 | 范围 |
|---|---|---|
| 1 | 已完成 | 配置、流量模型、事件、源、conntrack 采集器 |
| 2 | 已完成 | 源匹配、fanout、port_scan、有界滑动窗口状态存储 |
| 3 | 已完成 | nftables 执行器、运行时管道、统计、API |
| 4 | 已完成 | 信标检测器、procd 初始化脚本、测试、远程 syslog、自愈 UDP 写入器 |
| 5 | 已完成 | 入站 WAN 检测(ext_scan、brute_force)、方向分类器、去重抑制、广播/自身过滤 |
| 6 | 计划中 | Netlink conntrack 事件、dnsmasq 集成、IPv6、目标支持时的 eBPF/XDP、LuCI 插件 |
## 许可证
[MIT](LICENSE)
标签:CIDR扫描, conntrack, EVTX分析, Go语言, IoT安全, LangChain, Linux路由器, Netfilter, nftables, OpenWRT, 启发式检测, 威胁情报, 开发者工具, 恶意行为检测, 程序破解, 网关安全, 网络安全, 轻量级, 防火墙, 隐私保护