现在我已经找到了完整的入口IP生成流程。让我整理并返回关键信息: --- ## 入口IP生成流程分析 ### 1. `buildTunnelInIP` 函数 (创建/更新隧道时) **位置**: `go-backend/internal/http/handler/mutations.go:2112-2152` ```go func buildTunnelInIP(inNodes []tunnelRuntimeNode, nodes map[int64]*nodeRecord, ipPreference string) string { set := make(map[string]struct{}) ordered := make([]string, 0) preferV6 := strings.TrimSpace(ipPreference) == "v6" for _, inNode := range inNodes { node := nodes[inNode.NodeID] if node == nil { continue } v4 := strings.TrimSpace(node.ServerIPv4) // 从节点获取 IPv4 v6 := strings.TrimSpace(node.ServerIPv6) // 从节点获取 IPv6 var addrs []string if preferV6 { if v6 != "" { addrs = append(addrs, v6) } if v4 != "" { addrs = append(addrs, v4) } } else { if v4 != "" { addrs = append(addrs, v4) } if v6 != "" { addrs = append(addrs, v6) } } if len(addrs) == 0 { if v := strings.TrimSpace(node.ServerIP); v != "" { // fallback 到 ServerIP addrs = append(addrs, v) } } // ... 去重后拼接 } return strings.Join(ordered, ",") } ``` **调用位置**: - 隧道创建: `mutations.go:496` - 隧道更新: `mutations.go:693` --- ### 2. `resolveForwardIngress` 函数 (查询转发时) **位置**: `go-backend/internal/store/repo/repository.go:2727-2796` ```go func resolveForwardIngress(db *gorm.DB, forwardID int64, tunnelID int64) (string, sql.NullInt64, error) { // 1. 首先从 tunnel 表获取 in_ip (由 buildTunnelInIP 生成) var tunnelInIP sql.NullString db.Model(&model.Tunnel{}).Select("in_ip").Where("id = ?", tunnelID).Limit(1).Scan(&tunnelInIP) // 2. 从 forward_port + node 表获取端口和节点IP type fpRow struct { Port sql.NullInt64 ServerIP sql.NullString } var fpRows []fpRow err := db.Model(&model.ForwardPort{}). Select("forward_port.port, node.server_ip"). Joins("LEFT JOIN node ON node.id = forward_port.node_id"). Where("forward_port.forward_id = ?", forwardID). Order("forward_port.id ASC"). Find(&fpRows).Error // 3. 组装入口地址 // - 如果 tunnel.in_ip 存在: "ip1:port,ip2:port..." // - 否则使用 forward_port 关联的 node.server_ip: "ip:port" // ... } ``` **调用位置**: - `repository.go:495` - 用户转发列表 - `repository.go:730` - 管理员转发列表 --- ### 3. `forward_port` 表与节点IP关联 **模型定义**: `go-backend/internal/store/model/model.go:50-57` ```go type ForwardPort struct { ID int64 `gorm:"primaryKey;autoIncrement"` ForwardID int64 `gorm:"column:forward_id;not null"` NodeID int64 `gorm:"column:node_id;not null"` // 关联到 node.id Port int `gorm:"not null"` } ``` **关联查询** (在 `resolveForwardIngress` 中): ```sql SELECT forward_port.port, node.server_ip FROM forward_port LEFT JOIN node ON node.id = forward_port.node_id WHERE forward_port.forward_id = ? ORDER BY forward_port.id ASC ``` --- ### 4. 转发创建API入口分配流程 **入口函数**: `go-backend/internal/http/handler/mutations.go:1108-1194` ```go func (h *Handler) forwardCreate(w http.ResponseWriter, r *http.Request) { // 1. 获取隧道入口节点IDs entryNodes, _ := h.tunnelEntryNodeIDs(tunnelID) // line 1162 // 2. 获取或选择入口端口 port := asInt(req["inPort"], 0) if port <= 0 { port = h.pickTunnelPort(tunnelID) // 自动分配端口 (line 1157) } // 3. 创建转发记录 + forward_port 记录 forwardID, err := h.repo.CreateForwardTx(..., entryNodes, port, ...) // line 1179 } ``` **`CreateForwardTx`**: `go-backend/internal/store/repo/repository_mutations.go:1171-1209` ```go func (r *Repository) CreateForwardTx(..., entryNodeIDs []int64, port int, ...) (int64, error) { // 创建 forward 记录 // 为每个入口节点创建 forward_port 记录 for _, nodeID := range entryNodeIDs { fp := model.ForwardPort{ ForwardID: forwardID, NodeID: nodeID, // 入口节点ID Port: port, // 入口端口 } tx.Create(&fp) } } ``` **入口节点获取**: `repository_mutations.go:535-548` ```go func (r *Repository) TunnelEntryNodeIDs(tunnelID int64) ([]int64, error) { // 从 chain_tunnel 表查询 chain_type = 1 (入口) 的节点 r.db.Model(&model.ChainTunnel{}). Where("tunnel_id = ? AND chain_type = ?", tunnelID, "1"). Order("inx ASC, id ASC"). Pluck("node_id", &ids) } ``` --- ## 关键修改位置 | 需求 | 修改文件 | 行号 | 说明 | |------|----------|------|------| | **修改隧道入口IP生成逻辑** | `mutations.go` | 2112-2152 | `buildTunnelInIP` 函数,控制IPv4/IPv6优先级和组合 | | **修改转发入口IP解析** | `repository.go` | 2727-2796 | `resolveForwardIngress`,控制入口地址格式 | | **修改端口自动分配** | `mutations.go` | 2901-2964 | `pickTunnelPort`,控制端口范围选择 | | **修改入口节点关联** | `repository_mutations.go` | 1196-1205 | `CreateForwardTx` 中的 forward_port 创建 | | **节点IP来源** | `model.go` | 516-531 | `NodeRecord` 结构体 | | **节点IP存储** | `model.go` | 59-65 | `Node` 模型: `ServerIP`, `ServerIPV4`, `ServerIPV6` | --- ## 入口IP数据流 ``` 1. 节点注册 → Node表存储 server_ip, server_ip_v4, server_ip_v6 2. 创建隧道: chain_tunnel (入口节点) → buildTunnelInIP() → tunnel.in_ip 字段 3. 创建转发: 隧道入口节点IDs → forward_port(forward_id, node_id, port) 4. 查询转发入口: forward_port JOIN node → resolveForwardIngress() ├─ 优先使用 tunnel.in_ip (多IP组合) └─ 否则用 forward_port 关联的 node.server_ip ```