Initial commit

This commit is contained in:
2026-06-30 15:14:37 +08:00
commit 15dab96872
311 changed files with 95639 additions and 0 deletions
+272
View File
@@ -0,0 +1,272 @@
# MeshRay-Core 架构规范
> Core 是通用的数据传输引擎,通过 ProtocolPlugin 接口适配不同协议。当前默认内置 WG 插件。
---
## 一、目录结构
```
core/
├── core.go # 进程入口
├── engine.go # 引擎实例
├── metrics.go # 监控指标
├── connect/ # 建连层
│ ├── strategy.go # 策略调度
│ ├── stun.go # STUN 协议
│ ├── direct.go # Layer 1
│ ├── fake_tcp.go # Layer 2
│ ├── real_tcp.go # Layer 3
│ ├── turn.go # Layer 4/6/7
│ ├── turn_quic.go # Layer 5
│ ├── ice.go # Layer 8
│ └── ws.go # Layer 9
├── transport/ # 传输层
│ ├── conn_manager.go # 连接索引
│ ├── relay.go # 转发循环
│ └── plugin.go # Plugin 接口
└── plugins/ # 协议插件
└── wg/
└── wgparse.go # WG 插件实现
```
---
## 二、各文件职责
### 2.1 根目录(4 个文件)
| 文件 | 职责 | 持有什么 | 不做什么 |
|------|------|---------|----------|
| `core.go` | 进程入口,管理多个 Engine | `map[engineID]*Engine` | 不做建连、不转发数据 |
| `engine.go` | 一个组网的引擎实例 | strategy、conn_manager、relay、plugin | 不直接调用 connect,由 relay 调用 |
| `metrics.go` | 监控指标采集 | 原子计数器(连接数、字节数、切换次数) | 不做业务逻辑 |
**关键关系**
- `core.go` 持有多个 `engine.go`
- `internal/ctr/ctr.go` 直接调用 `core.go``engine.go` (进程内函数调用)
- `engine.go` 持有 connect/、transport/、plugins/ 的实例
### 2.2 connect/9 个文件)— 建连层
**职责**:通过各种网络方式建立连接,最终返回 `net.Conn`
**对外暴露的唯一入口**`strategy.go``Connect()` 方法。其他 connect 文件只被 `strategy.go` 调用。
| 文件 | 对应层级 | 职责 | 返回什么 |
|------|---------|------|---------|
| `strategy.go` | 全部 | 按优先级尝试各层,不通自动切换,定期探测恢复 | `net.Conn` + 当前层级名 |
| `stun.go` | 被 direct/ice 调用 | STUN 协议:发送 Binding Request,获取本机公网地址 | `*net.UDPAddr`(地址,不是连接) |
| `direct.go` | Layer 1 | 调用 stun 获取候选地址,然后 UDP 打洞 | `net.Conn` |
| `fake_tcp.go` | Layer 2 | UDP 包外层封装 TCP 头部,欺骗防火墙 | `net.Conn` |
| `real_tcp.go` | Layer 3 | 真正的 TCP 直连打洞 | `net.Conn` |
| `turn.go` | Layer 4/6/7 | TURN 协议协商(Allocate/Permission/ChannelBind),参数区分 UDP/TCP/TLS | `net.Conn` |
| `turn_quic.go` | Layer 5 | TURN-QUIC 私有扩展(RFC 9000 | `net.Conn` |
| `ice.go` | Layer 8 | ICE 协商 + WebRTC DataChannel,内部调用 stun 收集候选 | `net.Conn` |
| `ws.go` | Layer 9 | WS/WSS 握手 + 帧收发 + 身份标识 | `net.Conn` |
**9 层完整编号**
| 层级 | 链路名称 | 文件 | 传输方式 | 穿透力 |
|------|---------|------|---------|--------|
| 1 | Direct-UDP | direct.go | P2P 直连 | 弱(性能最好) |
| 2 | Direct-FakeTCP | fake_tcp.go | P2P 直连 | 弱 |
| 3 | Direct-RealTCP | real_tcp.go | P2P 直连 | 中 |
| 4 | TURN-UDP | turn.go | 中继 | 中 |
| 5 | TURN-QUIC | turn_quic.go | 中继 | 中 |
| 6 | TURN-TCP | turn.go | 中继 | 强 |
| 7 | TURN-TLS | turn.go | 中继 | 强 |
| 8 | WebRTC | ice.go | ICE/TURN | 强 |
| 9 | WS/WSS | ws.go | 隧道 | 最强(兜底) |
**strategy.go 的自动切换逻辑**
- 单包超时 500ms → 切到下一层
- 10s 滑动窗口丢包率 > 10% → 切到下一层
- 当前在第 N 层时,每 30s 探测 Layer 1 → 连续 2 次成功直接切回 Layer 1(不逐层回退)
**stun.go 的特殊地位**:唯一被多处调用的 connect 文件(direct.go 和 ice.go 都需要它),所以独立存在。
### 2.3 transport/3 个文件)— 传输层
**职责**:用 `net.Conn` 转发数据。不感知具体协议,通过 ProtocolPlugin 接口适配。
| 文件 | 职责 | 不做什么 |
|------|------|---------|
| `conn_manager.go` | 连接索引:`peer_key → net.Conn` 的映射 | 不做建连、不转发数据 |
| `relay.go` | Read/Write 循环:从本地端口收包 → 查路由 → 通过 conn 发送;从 conn 收包 → 发到本地端口 | 不做建连 |
| `plugin.go` | 定义 ProtocolPlugin 接口 | 不实现任何协议 |
**relay.go 的工作流程**
```
本地端口收到 WG 密文包
→ 调用 plugin.IsControlPacket() 判断包类型
→ true:控制包,按已建链路透传
→ 调用 plugin.IsDataPacket() 判断
→ true:调用 plugin.ExtractRouteID() 提取路由标识
→ 查路由标识映射表 → 发往对应本地端口
→ 都不是:丢弃
```
**关键**relay.go 不知道 WireGuard,不知道 receiver index,只知道 route_id。
### 2.4 plugins/wg/1 个文件)— 协议插件
**职责**:实现 ProtocolPlugin 接口,处理 WG 协议特有的包解析。
| 文件 | 职责 | 不做什么 |
|------|------|---------|
| `wgparse.go` | 实现 `IsDataPacket`/`ExtractRouteID`/`IsControlPacket` | 不做建连、不转发数据 |
**WG 插件的具体实现**
| 方法 | 逻辑 |
|------|------|
| `IsControlPacket(packet)` | `packet[0]` ∈ {1, 2, 3} → true |
| `IsDataPacket(packet)` | `packet[0]` == 4 → true |
| `ExtractRouteID(packet)` | 读取 `packet[4:8]`,网络字节序解析为 uint32(即 WG receiver index |
### 2.5 plugins/wg/1 个文件)
| 文件 | 职责 |
|------|------|
| `wgparse.go` | WireGuard 数据包解析和封装 |
---
## 三、分层架构图
```
┌─────────────────────────────────────────────────────────┐
│ internal/ctr/ctr.go │
│ 直接调用 Core (进程内函数调用) │
└────────────────────────┬────────────────────────────────┘
│ 函数调用
┌────────────────────────▼────────────────────────────────┐
│ core.go │
│ 管理多个 Engine 实例 │
└───┬─────────────────────────────────────────────────────┘
│ 每个组网一个 Engine
┌─────────────────────────────────────────────────────────┐
│ engine.go │
│ 持有:strategy + conn_manager + relay + plugin │
│ 协调 connect/ 和 transport/ 工作 │
└───┬─────────────────────────────────────────────────────┘
├──────────────────────────────────────────┐
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ connect/ │ │ transport/ │
│ 建连层 │ │ 传输层 │
│ │ │ │
│ strategy.go │ 返回 │ relay.go │
│ ├─ direct.go (L1) │ net.Conn├─ plugin.go │
│ ├─ fake_tcp.go (L2) │────────►│ │ ProtocolPlugin │
│ ├─ real_tcp.go (L3) │ │ │ │
│ ├─ turn.go (L4/6/7) │ │ 插件调用 │
│ ├─ turn_quic.go(L5) │ │ ▼ │
│ ├─ ice.go (L8) │ │ plugins/wg/ │
│ └─ ws.go (L9) │ │ └─ wgparse.go │
│ │ │ │
│ stun.go (被 direct/ice 调用) │ conn_manager.go │
└───────────────────────┘ └───────────────────────┘
```
---
## 四、调用关系
### 4.1 Engine 创建时
```
engine.go
→ 创建 WGPluginplugins/wg/wgparse.go
→ 创建 Relay,传入 plugintransport/relay.go
→ 创建 Strategyconnect/strategy.go
→ 创建 ConnManagertransport/conn_manager.go
```
### 4.2 Bind 流程
```
ctr 直接调用:Bind()
→ engine.go 接收函数调用
→ engine.go 调用 strategy.Connect()
→ strategy 按优先级尝试各层
→ Layer 1: direct.go 调用 stun.go 获取候选,尝试 UDP 打洞
→ 不通?→ Layer 4: turn.go 调用 TURN 协商
→ 不通?→ Layer 9: ws.go 调用 WS 握手
→ 返回 net.Conn + 当前层级名
→ engine.go 把 net.Conn 注册到 conn_manager
→ engine.go 启动 relay 的 Read/Write 循环
```
### 4.3 数据转发流程
```
WG 发出密文包 → 本地端口
→ relay.go 收到
→ 调用 plugin.IsControlPacket()
→ true:按已建链路透传(conn_manager 查 conn
→ 调用 plugin.IsDataPacket()
→ true:调用 plugin.ExtractRouteID() 获取 route_id
→ 查路由标识映射表 → 找到本地端口 → 发送
→ 都不是:丢弃
```
---
## 五、通用层与插件层的边界
| 层 | 知道什么 | 不知道什么 |
|---|---------|-----------|
| **connect/** | 网络协议(STUN/TURN/WS/WebRTC | WireGuard、route_id |
| **transport/** | net.Conn、route_id、ProtocolPlugin 接口 | WireGuard、receiver index |
| **plugins/wg/** | WG 包格式、receiver index | 网络连接、net.Conn |
| **engine.go** | 协调 connect/ 和 transport/ | WG 包格式细节 |
**如果将来要支持其他协议**
- 新建 `plugins/xxx/xxxparse.go`
- 实现 `ProtocolPlugin` 接口的三个方法
- `engine.go` 里换成 `xxx.NewPlugin()`
- connect/、transport/、core.go 的代码完全不用改
---
## 六、Core 接口(直接被 ctr 调用)
| 方法 | 调用方 | 说明 |
|------|--------|------|
| `CreateEngine` | ctr | 创建一个 Engine 实例(直接函数调用) |
| `Bind` | ctr | 为每个 Peer 开启本地端口,开始建链 |
| `Unbind` | ctr | 停止指定 Peer 的端口监听 |
| `Start` | ctr | 启动转发主循环 |
| `Stop` | ctr | 停止 Engine |
| `GetStatus` | ctr | 查询 Engine 状态 |
| `NotifyPeerInfo` | ctr | 下发对端候选地址和 route_id |
**实现位置**
- 所有方法都在 `engine.go` 中实现
- `core.go` 提供 Engine 实例管理
- ctr通过`coreInst.CreateEngine(...)`直接调用
---
## 七、文件清单汇总
| 目录 | 文件数 | 文件 |
|------|--------|------|
| 根目录 | 3 | core.go, engine.go, metrics.go |
| connect/ | 9 | strategy.go, stun.go, direct.go, fake_tcp.go, real_tcp.go, turn.go, turn_quic.go, ice.go, ws.go |
| transport/ | 3 | conn_manager.go, relay.go, plugin.go |
| plugins/wg/ | 1 | wgparse.go |
| **总计** | **16** | |
**已删除的文件**
- ~~grpc_service.go~~ - 不再需要(改为直接函数调用)
- ~~pool/connpool.go~~ - 不再需要(无连接池)
- ~~proto/core.proto~~ - 不再需要 gRPC