跳转到内容

Go 版实现概览

pcdn-detector 是 Go 版参考实现:纯 Go、CGO_ENABLED=0,交叉编译出静态二进制,安装后即可在 OpenWrt 上运行。本页说明它的内部结构,供二次开发、排查问题或对照 C 版阅读源码时使用。

通用配置与功能见配置总览;Go / C 选型见选择后端实现。

单进程,若干 goroutine 各司其职:

组件 职责
抓包循环 从 AF_PACKET 环形缓冲取帧,解析后交给检测器
扫描定时器 每 interval 扫描一次滑动窗口,产生告警事件
blocker 消费告警事件,串行下发防火墙命令(命令在后台执行,不阻塞抓包)
HTTP 服务 每个连接一个 goroutine,读写运行时状态
信号处理 SIGHUP 触发重载,SIGINT / SIGTERM 兜底解封并退出

重载期间 blocker 对象不换绑,只替换其内部后端,因此检测层的 sink 与 HTTP 持有的指针始终有效, 迁移期间到达的事件排队而非丢弃。

  • AF_PACKET + TPACKET_V3 环形缓冲,不依赖 libpcap、不需要 CGO,可交叉编译为静态文件。
  • socket 上挂内核经典 BPF 过滤器,只放行可能承载所选协议的 IPv4 / IPv6 报文(兼容 VLAN / QinQ)。ARP、STP、ICMP、ICMPv6、NDP 等在进入用户态前即被丢弃。
  • snaplen 截断:BPF 返回值决定内核每包复制多少字节(默认 256B),负载不进入用户态; 流量统计用内核记录的线路长度 tp_len,不受截断影响。
  • TPACKET_V3 的一个 frame 可容纳多个小包,所以容量由 snaplen × 帧数 决定,frame_size 只影响块的切分粒度(详见内存与性能细节)。
目录 职责 常见排查切入点
cmd/pcdn-detect/ 命令行解析、组件装配、启动流程 参数优先级、启动失败的第一现场
internal/config/ 配置结构、默认值、校验、模板 template.go 里的 defaultConfigTemplate 是配置项权威说明
internal/capture/ 抓包、报文解析、BPF 生成 BPF 与 snaplen 的测试都在这里
internal/detector/ 滑动窗口、对端集合、端口淘汰、告警 阈值/续期/淘汰逻辑
internal/filter/ MAC + 端口黑白名单 名单匹配与端口表达式
internal/firewall/ hook / iptables / nftables 后端 封禁规则拼装、残留清理
internal/blocker/ 告警事件到封禁动作的协调 引用计数、全端口封禁、UPnP
internal/httpapi/ API 路由、鉴权、CORS、分页 各端点的筛选与统计口径
internal/minihttp/ 极简 HTTP/1.1 服务端 传输层限制、与 net/http 的差分测试
internal/state/ 重启继承用的二进制状态(PCST v1) 兜底重启、状态文件兼容性
internal/netutil/ MAC、协议号、公网地址判定 地址归属判断
internal/util/、internal/logx/、internal/tz/ 展示格式化、分级日志、时区解析 日志掩码与时间显示

不引入 net/http 与 TLS。internal/minihttp 自己实现 HTTP/1.1,因此不会带入 crypto/tls / crypto/x509,可执行文件更小;代价是不支持 HTTPS 与 chunked 请求体,需要加密时 在前置反向代理终结 TLS。行为边界(状态码、keep-alive、流水线、连接关闭语义)有与 net/http 的差分测试保证。

默认只放行 UDP。PCDN 以 UDP 为主,内核层过滤能大幅降低内核→用户态的处理量与内存带宽; 需要 TCP 时显式改 [capture] protocol,此时防火墙封禁协议也会跟着变。

内存优先于信息完整度。对端键用紧凑地址、单对端端口内联、告警标记复用对端记录、map 峰值 收缩等多处优化,换来单端口约 174 字节的常驻开销;具体数字与复现命令见 内存与性能细节。

状态只在兜底重启时落盘。正常运行不写状态文件;只有组件原地重建失败、需要 exec 自重启时, 才把告警会话与封禁状态写入 pcdn-detect.state(PCST v1,权限 0600)供下次启动继承。

终端窗口
make build # 本机架构 → bin/pcdn-detect
make all # mipsle / mips / armv7 / arm64 / amd64
  • 构建参数固定 CGO_ENABLED=0、-trimpath、-ldflags "-s -w -buildid="。
  • 版本通过 -X main.baseVersion=... -X main.gitHash=... 注入,-v 输出形如 0.0.1-beta.2+<git 短哈希>;未注入时显示 +unknown。
  • 交叉编译细节与架构对照见编译与交叉编译。
  • 配置、命令行、HTTP API、状态文件格式与 C 版 保持一致,两者可互换。
  • LuCI 面板通过 -T 校验、SIGHUP 重载、HTTP API 读状态与之交互;面板不解析 TOML。