Merge pull request #134 from Sagit-chu/fix-tunnel-ipv6-preference

fix(tunnel): respect IPv6 preference in tunnel creation and diagnostics
This commit is contained in:
sagit
2026-02-18 10:04:50 +08:00
committed by GitHub
3 changed files with 45 additions and 39 deletions
-9
View File
@@ -1,9 +0,0 @@
---
active: true
iteration: 1
max_iterations: 100
completion_promise: "DONE"
started_at: "2026-02-15T16:38:58.212Z"
session_id: "ses_39dd49703ffeveg711aA1D1YAk"
---
现状后端数据库兼容sqlite和postgresql,每一次新增功能需要维护两套数据库sql,需求是使用一个数据库驱动能同时兼容两个数据库,请仔细分析,列出计划,全量迁移,并且写好所有的测试,确保重构后所有的功能都能正常运行,由于工程量大,请写一个计划列表的markdown记录,每次完成一个就记录一下进度
@@ -383,7 +383,7 @@ func (h *Handler) diagnoseForwardRuntime(forward *forwardRecord) (map[string]int
"fromChainType": 1,
"toChainType": 2,
"toInx": firstNode.Inx,
})
}, "")
}
} else {
for _, outNode := range outNodes {
@@ -391,7 +391,7 @@ func (h *Handler) diagnoseForwardRuntime(forward *forwardRecord) (map[string]int
h.appendChainHopDiagnosis(&results, nodeCache, inNode.NodeID, outNode, description, map[string]interface{}{
"fromChainType": 1,
"toChainType": 3,
})
}, "")
}
}
}
@@ -406,7 +406,7 @@ func (h *Handler) diagnoseForwardRuntime(forward *forwardRecord) (map[string]int
"fromInx": currentNode.Inx,
"toChainType": 2,
"toInx": nextNode.Inx,
})
}, "")
}
} else {
for _, outNode := range outNodes {
@@ -415,7 +415,7 @@ func (h *Handler) diagnoseForwardRuntime(forward *forwardRecord) (map[string]int
"fromChainType": 2,
"fromInx": currentNode.Inx,
"toChainType": 3,
})
}, "")
}
}
}
@@ -470,6 +470,7 @@ func (h *Handler) diagnoseTunnelRuntime(tunnelID int64) (map[string]interface{},
return nil, errors.New("隧道配置不完整")
}
ipPreference := h.repo.GetTunnelIPPreference(tunnelID)
inNodes, chainHops, outNodes := splitChainNodeGroups(chainRows)
results := make([]map[string]interface{}, 0, len(chainRows)*2)
nodeCache := map[int64]*nodeRecord{}
@@ -491,7 +492,7 @@ func (h *Handler) diagnoseTunnelRuntime(tunnelID int64) (map[string]interface{},
"fromChainType": 1,
"toChainType": 2,
"toInx": firstNode.Inx,
})
}, ipPreference)
}
} else {
for _, outNode := range outNodes {
@@ -499,7 +500,7 @@ func (h *Handler) diagnoseTunnelRuntime(tunnelID int64) (map[string]interface{},
h.appendChainHopDiagnosis(&results, nodeCache, inNode.NodeID, outNode, description, map[string]interface{}{
"fromChainType": 1,
"toChainType": 3,
})
}, ipPreference)
}
}
}
@@ -514,7 +515,7 @@ func (h *Handler) diagnoseTunnelRuntime(tunnelID int64) (map[string]interface{},
"fromInx": currentNode.Inx,
"toChainType": 2,
"toInx": nextNode.Inx,
})
}, ipPreference)
}
} else {
for _, outNode := range outNodes {
@@ -523,7 +524,7 @@ func (h *Handler) diagnoseTunnelRuntime(tunnelID int64) (map[string]interface{},
"fromChainType": 2,
"fromInx": currentNode.Inx,
"toChainType": 3,
})
}, ipPreference)
}
}
}
@@ -693,13 +694,14 @@ func (h *Handler) appendPathDiagnosis(results *[]map[string]interface{}, nodeCac
*results = append(*results, item)
}
func (h *Handler) appendChainHopDiagnosis(results *[]map[string]interface{}, nodeCache map[int64]*nodeRecord, fromNodeID int64, toNode chainNodeRecord, description string, metadata map[string]interface{}) {
func (h *Handler) appendChainHopDiagnosis(results *[]map[string]interface{}, nodeCache map[int64]*nodeRecord, fromNodeID int64, toNode chainNodeRecord, description string, metadata map[string]interface{}, ipPreference string) {
fromNode, _ := h.cachedNode(nodeCache, fromNodeID)
targetNode, err := h.cachedNode(nodeCache, toNode.NodeID)
if err != nil {
h.appendFailedDiagnosis(results, nodeCache, fromNodeID, "", 0, description, metadata, err.Error())
return
}
targetIP, targetPort, err := resolveChainProbeTarget(targetNode, toNode.Port)
targetIP, targetPort, err := resolveChainProbeTarget(fromNode, targetNode, toNode.Port, ipPreference)
if err != nil {
h.appendFailedDiagnosis(results, nodeCache, fromNodeID, strings.Trim(strings.TrimSpace(targetNode.ServerIP), "[]"), toNode.Port, description, metadata, err.Error())
return
@@ -707,11 +709,14 @@ func (h *Handler) appendChainHopDiagnosis(results *[]map[string]interface{}, nod
h.appendPathDiagnosis(results, nodeCache, fromNodeID, targetIP, targetPort, description, metadata)
}
func resolveChainProbeTarget(targetNode *nodeRecord, preferredPort int) (string, int, error) {
func resolveChainProbeTarget(fromNode, targetNode *nodeRecord, preferredPort int, ipPreference string) (string, int, error) {
if targetNode == nil {
return "", 0, errors.New("目标节点不存在")
}
host := strings.Trim(strings.TrimSpace(targetNode.ServerIP), "[]")
host, err := selectTunnelDialHost(fromNode, targetNode, ipPreference)
if err != nil {
host = strings.Trim(strings.TrimSpace(targetNode.ServerIP), "[]")
}
if host == "" {
return "", 0, errors.New("目标节点地址为空")
}
+28 -18
View File
@@ -437,7 +437,7 @@ func (h *Handler) tunnelCreate(w http.ResponseWriter, r *http.Request) {
}
runtimeState.IPPreference = ipPreference
if strings.TrimSpace(inIP) == "" {
inIP = buildTunnelInIP(runtimeState.InNodes, runtimeState.Nodes)
inIP = buildTunnelInIP(runtimeState.InNodes, runtimeState.Nodes, ipPreference)
}
if len(runtimeState.InNodes) > 0 {
@@ -634,7 +634,7 @@ func (h *Handler) tunnelUpdate(w http.ResponseWriter, r *http.Request) {
runtimeState.TunnelID = id
runtimeState.IPPreference = ipPreference
inIp := buildTunnelInIP(runtimeState.InNodes, runtimeState.Nodes)
inIp := buildTunnelInIP(runtimeState.InNodes, runtimeState.Nodes, ipPreference)
var federationBindings []repo.FederationTunnelBinding
var federationReleaseRefs []federationRuntimeReleaseRef
@@ -1995,32 +1995,42 @@ func (h *Handler) prepareTunnelCreateState(tx *gorm.DB, req map[string]interface
return state, nil
}
func buildTunnelInIP(inNodes []tunnelRuntimeNode, nodes map[int64]*nodeRecord) string {
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
}
if v := strings.TrimSpace(node.ServerIPv4); v != "" {
if _, ok := set[v]; !ok {
set[v] = struct{}{}
ordered = append(ordered, v)
v4 := strings.TrimSpace(node.ServerIPv4)
v6 := strings.TrimSpace(node.ServerIPv6)
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 v := strings.TrimSpace(node.ServerIPv6); v != "" {
if _, ok := set[v]; !ok {
set[v] = struct{}{}
ordered = append(ordered, v)
}
}
if strings.TrimSpace(node.ServerIPv4) == "" && strings.TrimSpace(node.ServerIPv6) == "" {
if len(addrs) == 0 {
if v := strings.TrimSpace(node.ServerIP); v != "" {
if _, ok := set[v]; !ok {
set[v] = struct{}{}
ordered = append(ordered, v)
}
addrs = append(addrs, v)
}
}
for _, a := range addrs {
if _, ok := set[a]; !ok {
set[a] = struct{}{}
ordered = append(ordered, a)
}
}
}