mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 07:36:38 +08:00
173 lines
5.2 KiB
Plaintext
173 lines
5.2 KiB
Plaintext
根据我的分析,以下是隧道链路构建时下一跳连接地址选择流程的完整报告:
|
|
|
|
---
|
|
|
|
## 隧道链路构建流程分析报告
|
|
|
|
### 1. 隧道链路配置发送到节点的代码位置
|
|
|
|
**主函数**: `applyTunnelRuntime()`
|
|
- 文件: `go-backend/internal/http/handler/mutations.go`
|
|
- 行号: 2454-2521
|
|
|
|
**核心流程**:
|
|
|
|
```
|
|
applyTunnelRuntime (L2454)
|
|
├── 入口节点: 发送 AddChains 命令 (L2474)
|
|
├── 跳转节点: 发送 AddChains (L2496) + AddService (L2502) 命令
|
|
└── 出口节点: 发送 AddService 命令 (L2514)
|
|
```
|
|
|
|
**配置构建函数**:
|
|
| 函数 | 位置 | 作用 |
|
|
|------|------|------|
|
|
| `buildTunnelChainConfig()` | L2567-2624 | 构建转发链配置 |
|
|
| `buildTunnelChainServiceConfig()` | L2626-2652 | 构建服务配置 |
|
|
| `selectTunnelDialHost()` | L2654-2699 | **选择下一跳连接地址** |
|
|
|
|
---
|
|
|
|
### 2. 下一跳连接地址是如何确定的
|
|
|
|
**地址选择核心函数**: `selectTunnelDialHost()` (L2654-2699)
|
|
|
|
```go
|
|
// 关键逻辑 (简化版)
|
|
func selectTunnelDialHost(fromNode, toNode *nodeRecord, ipPreference string) (string, error) {
|
|
// 1. 检测源节点和目标节点的 IPv4/IPv6 支持
|
|
fromV4 := nodeSupportsV4(fromNode)
|
|
fromV6 := nodeSupportsV6(fromNode)
|
|
toV4 := nodeSupportsV4(toNode)
|
|
toV6 := nodeSupportsV6(toNode)
|
|
|
|
// 2. 根据偏好选择地址
|
|
switch ipPreference {
|
|
case "v6": // 优先 IPv6
|
|
if fromV6 && toV6 { return pickNodeAddressV6(toNode) }
|
|
if fromV4 && toV4 { return pickNodeAddressV4(toNode) }
|
|
case "v4": // 优先 IPv4
|
|
if fromV4 && toV4 { return pickNodeAddressV4(toNode) }
|
|
if fromV6 && toV6 { return pickNodeAddressV6(toNode) }
|
|
default: // 默认优先 IPv4
|
|
if fromV4 && toV4 { return pickNodeAddressV4(toNode) }
|
|
if fromV6 && toV6 { return pickNodeAddressV6(toNode) }
|
|
}
|
|
// 3. 不兼容时报错
|
|
return "", fmt.Errorf("节点链路不兼容")
|
|
}
|
|
```
|
|
|
|
**地址选择优先级** (在 `pickNodeAddressV4/V6` 中, L2755-2773):
|
|
- **IPv4**: `ServerIPv4` > `ServerIP` (旧字段)
|
|
- **IPv6**: `ServerIPv6` > `ServerIP` (旧字段)
|
|
|
|
**端口来源** (在 `buildTunnelChainConfig` 中, L2585-2588):
|
|
```go
|
|
port := target.Port // 来自 ChainTunnel.Port 字段
|
|
if port <= 0 {
|
|
return nil, errors.New("节点端口不能为空")
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 3. ChainTunnel.Port 字段的使用流程
|
|
|
|
**数据模型** (`model.go` L127-138):
|
|
```go
|
|
type ChainTunnel struct {
|
|
ID int64
|
|
TunnelID int64
|
|
ChainType string // "1"=入口, "2"=跳转, "3"=出口
|
|
NodeID int64
|
|
Port sql.NullInt64 // ★ 连接端口
|
|
Strategy sql.NullString
|
|
Inx sql.NullInt64 // 跳转序号
|
|
Protocol sql.NullString
|
|
}
|
|
```
|
|
|
|
**Port 字段流转**:
|
|
|
|
```
|
|
创建隧道时
|
|
│
|
|
▼
|
|
prepareTunnelCreateState (L1970)
|
|
├── 出口节点: 从请求读取 port,若为空则调用 PickNodePortTx 自动分配
|
|
├── 跳转节点: 从请求读取 port,若为空则调用 PickNodePortTx 自动分配
|
|
│
|
|
▼
|
|
replaceTunnelChainsTx (L2775)
|
|
└── CreateChainTunnelTx 写入数据库 (L2809, L2837)
|
|
│
|
|
▼
|
|
读取/重建状态时
|
|
│
|
|
▼
|
|
ListChainNodesForTunnel (repository_control.go L280)
|
|
└── 从 chain_tunnel 表读取 Port 字段 (L295)
|
|
│
|
|
▼
|
|
reconstructTunnelState (L845)
|
|
└── 将 Port 复制到 tunnelRuntimeNode.Port (L887, L901)
|
|
│
|
|
▼
|
|
buildTunnelChainConfig (L2567)
|
|
└── 使用 target.Port 构建连接地址 (L2585)
|
|
```
|
|
|
|
---
|
|
|
|
### 4. 修改连接地址需要改动的关键位置
|
|
|
|
如果要修改下一跳连接地址的选择逻辑,需要关注以下位置:
|
|
|
|
| 修改目标 | 文件 | 行号 | 函数 |
|
|
|---------|------|------|------|
|
|
| **IP地址选择策略** | `mutations.go` | L2654-2699 | `selectTunnelDialHost()` |
|
|
| **IPv4地址提取** | `mutations.go` | L2755-2763 | `pickNodeAddressV4()` |
|
|
| **IPv6地址提取** | `mutations.go` | L2765-2773 | `pickNodeAddressV6()` |
|
|
| **端口获取** | `mutations.go` | L2585-2588 | `buildTunnelChainConfig()` |
|
|
| **端口分配逻辑** | `repository_mutations.go` | ~L459 | `PickNodePortTx()` |
|
|
| **端口写入数据库** | `repository_mutations.go` | L398-406 | `CreateChainTunnelTx()` |
|
|
| **端口从数据库读取** | `repository_control.go` | L280-343 | `ListChainNodesForTunnel()` |
|
|
|
|
**关键配置结构**:
|
|
```go
|
|
// mutations.go L1950-1957
|
|
type tunnelRuntimeNode struct {
|
|
NodeID int64
|
|
Protocol string // 连接协议
|
|
Strategy string // 选择策略
|
|
Inx int // 跳转序号
|
|
ChainType int // 1=入口, 2=跳转, 3=出口
|
|
Port int // ★ 连接端口
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 5. 调用链总结
|
|
|
|
```
|
|
用户创建隧道请求
|
|
│
|
|
▼
|
|
tunnelAdd (mutations.go L450)
|
|
│
|
|
├── prepareTunnelCreateState() ──► 分配端口,构建 state
|
|
│
|
|
├── replaceTunnelChainsTx() ──► 写入 chain_tunnel 表
|
|
│
|
|
└── applyTunnelRuntime()
|
|
│
|
|
├── buildTunnelChainConfig()
|
|
│ │
|
|
│ ├── selectTunnelDialHost() ──► 选择 IP 地址
|
|
│ │
|
|
│ └── 使用 target.Port ──► 端口
|
|
│
|
|
└── sendNodeCommand("AddChains/AddService") ──► 发送到节点
|
|
``` |