mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 23:56:36 +08:00
5.3 KiB
5.3 KiB
Proxy Protocol 传输分析报告
日期: 2026-05-07
测试环境: 20.118.172.127 (Server 1) ↔ 108.181.90.137 (Server 2)
1. 代码流程分析
完整数据链路
前端 (proxyProtocol: 0|1|2)
→ 后端 handler mutations.go:1936
→ 数据库存储 forward.proxy_protocol (model.go:50)
→ 控制面 buildForwardServiceConfigs (control_plane.go:1791-1796)
→ handler metadata: {"proxyProtocol": 2}
→ Agent metadata 解析 (metadata.go:42)
→ handler.go:256 WrapClientConn()
→ conn.go:14 HeaderProxyFromAddrs(byte(ppv), src, dst)
→ conn.go:15 header.WriteTo(c)
→ 目标服务器收到 PROXY protocol header
关键代码
写入 PROXY header (go-gost/x/internal/net/proxyproto/conn.go):
func WrapClientConn(ppv int, src, dst net.Addr, c net.Conn) net.Conn {
if ppv <= 0 {
return c
}
header := proxyproto.HeaderProxyFromrs(byte(ppv), src, dst)
header.WriteTo(c)
return c
}
Handler 调用 (go-gost/x/handler/forward/local/handler.go:256):
cc = proxyproto.WrapClientConn(h.md.proxyProtocol, conn.RemoteAddr(), conn.LocalAddr(), cc)
src=conn.RemoteAddr()→ 客户端真实 IP ✅dst=conn.LocalAddr()→ agent 监听地址 ✅ppv= 1 或 2 → 版本号正确 ✅
2. 实际传输测试结果
测试方法
- 在 Server 2 启动 Python TCP 监听器,解析 PROXY protocol header
- 在 Server 1 用当前代码编译 gost,配置
proxyProtocol: 2转发到 Server 2 - 通过
nc发送测试数据,验证 Server 2 是否收到正确的 PROXY header
测试结果
| 版本 | 状态 | 接收到的 Header |
|---|---|---|
| PPv2 | ✅ 成功 | PP2 family=1 alen=12 SRC=127.0.0.1:45410 DST=127.0.0.1:20001 |
| PPv1 | ✅ 成功 | PROXY TCP4 127.0.0.1 127.0.0.1 43816 20001 |
测试详情
PPv2 原始数据:
Got 28 bytes
PP2 family=1 alen=12
SRC=127.0.0.1:45410 DST=127.0.0.1:20001
PPv1 原始数据 (hex):
50524f58592054435034203132372e302e302e31203132372e302e302e312034333831362032303030310d0a
解码: PROXY TCP4 127.0.0.1 127.0.0.1 43816 20001
3. 单元测试结果
go-gost/x/handler/forward/local/ → TestLocalForwardHandlerSendsProxyProtocolToTarget ✅
go-backend/internal/http/handler/ → TestBuildForwardServiceConfigsSendsProxyProtocolToForwardHandler ✅
go-backend/internal/store/repo/ → TestGetForwardRecordIncludesProxyProtocol ✅
全部通过 (3/3)。
4. 发现的问题
问题 1: WriteTo 错误未检查
位置: go-gost/x/internal/net/proxyproto/conn.go:15
header.WriteTo(c) // 返回 (int64, error) 被忽略
影响: 如果写入失败(连接已断开、网络错误等),后续数据传输会在没有 PROXY header 的情况下继续,目标服务器可能解析出错。
建议:
if _, err := header.WriteTo(c); err != nil {
return c // 或包装一个带错误的 conn
}
严重程度: 低(实际场景中,写入失败后 Transport 也会很快失败)
问题 2: 部署版本过旧
服务器状态:
| 服务器 | 组件 | 版本 | 状态 |
|---|---|---|---|
| 20.118.172.127 | flux_agent | UPX 压缩,无法读取版本 | ✅ 运行中 |
| 20.118.172.127 | paneld | /app/paneld |
✅ 运行中 |
| 20.118.172.127 | /usr/local/bin/gost | v3.0.0 (go1.23.4) | 旧版,不支持 handler metadata 中的 proxyProtocol |
| 108.181.90.137 | flux_agent | 8.8MB | ✅ 运行中 |
影响: 旧版 gost 二进制不识别 handler metadata 中的 proxyProtocol 字段,PROXY protocol 功能在生产环境不可用。
验证: 用旧版 gost 测试时,目标服务器收到的原始数据为空,无 PROXY header。
问题 3: 数据库 Schema 缺失
位置: 20.118.172.127 的 /app/data/gost.db
当前 forward 表 schema:
CREATE TABLE `forward` (
`id` integer PRIMARY KEY AUTOINCREMENT,
`user_id` integer NOT NULL,
`user_name` varchar(100) NOT NULL,
`name` varchar(100) NOT NULL,
`tunnel_id` integer NOT NULL,
`remote_addr` text NOT NULL,
`strategy` varchar(100) NOT NULL DEFAULT "fifo",
`in_flow` integer NOT NULL DEFAULT 0,
`out_flow` integer NOT NULL DEFAULT 0,
`created_time` integer NOT NULL,
`updated_time` integer NOT NULL,
`status` integer NOT NULL,
`inx` integer NOT NULL DEFAULT 0,
`speed_id` integer
);
缺失字段:
proxy_protocol— PROXY protocol 版本max_conn— 最大连接数ip_max_conn— 每 IP 最大连接数ip_speed_id— 每 IP 限速 ID
影响: 后端无法存储和读取 proxy_protocol 配置,前端设置不会生效。
5. 结论
| 维度 | 状态 | 说明 |
|---|---|---|
| 代码实现 | ✅ 正确 | 完整的写入链路,版本/地址正确 |
| 单元测试 | ✅ 通过 | 3/3 测试覆盖 handler、repo、控制面 |
| 实际传输 (新编译版) | ✅ 成功 | PPv1 和 PPv2 均正确传输 |
| 实际传输 (部署版) | ❌ 不工作 | 旧版不支持 handler metadata 中的 proxyProtocol |
| 数据库 Schema | ❌ 缺字段 | 需要迁移添加 proxy_protocol 等列 |
总结: 代码实现正确,PROXY protocol 传输逻辑无误。但生产服务器运行的是旧版本,需要升级 backend 和 agent 才能启用此功能。