Flare 是一个基于 ShadowTLS 协议实现的内网穿透工具。通过将流量伪装成正常的 TLS 握手,实现隐蔽的通信通道,支持 TCP 端口转发和 SOCKS5 代理功能。
-
fls (Server):部署在公网服务器,负责:
- 监听 ShadowTLS 端口,接收 flc 连接
- 提供 Web 管理界面(客户端/隧道/代理管理)
- 监听远程端口(TCP 隧道/SOCKS5 代理)
- 通过控制通道下发任务指令给 flc
- 中继外部流量与 flc 之间的数据
-
flc (Client):部署在内网,负责:
- 主动连接 fls 建立控制长连接
- 接收 fls 下发的任务指令(隧道连接/代理连接)
- 按需建立数据连接,转发到内网目标服务
Flare 采用控制与数据分离的设计:
- 控制连接(长连接):flc 启动时建立,用于注册身份、维持心跳、接收任务指令。
- 数据连接(按需建立):收到任务指令后,flc 新建连接连向 fls,专门用于实际业务数据转发。转发完成后断开,不影响控制连接。
优势:解耦控制指令与大数据流量,避免大流量阻塞控制通道;flc 无需预先知道隧道配置,完全由 fls 动态调度。
flare/
├── bin/ # 编译后的可执行文件
│ ├── flc / flc.exe # Linux / Windows 客户端
│ └── fls / fls.exe # Linux / Windows 服务端
├── flc/
│ └── main.go # 客户端核心逻辑
├── fls/
│ ├── main.go # 服务端核心逻辑
│ └── web/ # Web 管理界面模板
│ ├── static/ # CSS/JS 静态资源
│ └── views/ # HTML 模板
├── protocol/
│ └── protocol.go # 通信协议定义(Frame/Message)
├── go.mod
└── go.sum
protocol/protocol.go:定义通信帧结构(FrameHeader + Payload)和消息类型。fls/main.go:Server结构体:管理客户端、隧道、代理、连接池、数据库等状态。runShadowTLS:启动 ShadowTLS 服务,接收 flc 连接。handleControlConnection:处理 flc 注册、心跳、任务响应。relayRemoteToClient:处理外部流量,下发任务给 flc,等待数据连接并中继。handleSocks5Connection:处理 SOCKS5 代理握手,解析目标地址,下发任务。loadDataFromDB:启动时从 SQLite 加载配置并恢复监听。
flc/main.go:Client结构体:管理控制连接状态。connectControl:建立并维持控制长连接。handleControlMessages:接收并处理 fls 下发的任务指令。handleTunnelConnect/handleProxyConnect:建立数据连接并转发到内网目标。
- flc 通过 ShadowTLS 协议连接 fls。
- 发送
MsgClientRegister携带 ClientID。 - fls 验证 ClientID 是否存在于数据库,返回
MsgClientRegisterAck。 - flc 进入心跳循环,等待任务指令。
- 外部用户连接 fls 的远程监听端口。
- fls 查找隧道配置,获取关联的 ClientID 和内网目标地址。
- fls 通过控制通道发送
MsgTunnelConnect(携带 TunnelID + LocalAddr)。 - flc 收到指令,新建 ShadowTLS 数据连接连向 fls,发送 Frame 头(TunnelID)。
- flc 连接内网目标服务(LocalAddr)。
- fls 将外部连接与 flc 数据连接加入连接池,开始双向中继。
- 外部代理客户端连接 fls 的代理监听端口。
- fls 完成 SOCKS5 握手(支持无认证/密码认证),解析目标地址。
- fls 通过控制通道发送
MsgProxyConnect(携带 ProxyID + TargetAddr)。 - flc 收到指令,新建 ShadowTLS 数据连接连向 fls,发送 Frame 头(ProxyID)。
- flc 连接目标地址(TargetAddr)。
- fls 将代理连接与 flc 数据连接加入连接池,开始双向中继。
- flc 断开重连时,fls 检测到旧连接存在。
- fls 主动关闭旧连接,清理其残留的数据连接池。
- 新连接接管,恢复服务。
- 断开清理时增加
client.Conn == conn判断,防止旧连接清理逻辑误杀新连接。
[ TunnelID (4 bytes) | DataLen (4 bytes) | Payload (DataLen bytes) ]
TunnelID = 0:控制通道消息。TunnelID > 0:数据通道连接,标识所属隧道/代理。
| 类型 | 方向 | 说明 |
|---|---|---|
MsgClientRegister |
flc -> fls | 客户端注册 |
MsgClientRegisterAck |
fls -> flc | 注册响应 |
MsgHeartbeat |
flc -> fls | 心跳 |
MsgHeartbeatAck |
fls -> flc | 心跳响应 |
MsgTunnelConnect |
fls -> flc | 隧道连接任务(携带 TunnelID + LocalAddr) |
MsgProxyConnect |
fls -> flc | 代理连接任务(携带 ProxyID + TargetAddr) |
# Linux
GOOS=linux GOARCH=amd64 go build -o bin/fls ./fls
GOOS=linux GOARCH=amd64 go build -o bin/flc ./flc
# Windows
GOOS=windows GOARCH=amd64 go build -o bin/fls.exe ./fls
GOOS=windows GOARCH=amd64 go build -o bin/flc.exe ./flcrm -rf dist && mkdir -p dist/bin
cp bin/* dist/bin/
cp -r fls/web dist/
tar -czvf flare.tar.gz -C dist .# fls (公网)
./bin/fls -listen :4436 -tls cloud.tencent.com -web :8080 -web-password admin123
# flc (内网)
./bin/flc -server <公网IP>:4436 -password <分配的密码> -sni cloud.tencent.com -id <分配的ID>- WaitGroup 安全:双向中继使用
sync.Once确保closeBoth只执行一次,防止重复关闭连接导致 panic。 - 连接池清理:flc 重连时必须清理旧连接池,但不删除 map 中的 key,确保监听端口继续正常工作。
- 数据库持久化:使用
gorm+sqlite(纯 Go 实现,无需 CGO)。结构体中Conn net.Conn必须加gorm:"-"标签。 - 日志标签:使用
[Main],[Control],[Relay],[Proxy],[Tunnel]等标签区分模块,便于排查问题。 - Web 模板:前端文件位于
fls/web/,修改后重启 fls 生效。