fix: use configured connectIp for tunnel chain diagnosis

- Pass connectIp through resolveChainProbeTarget in diagnosis stream start items
- Pass connectIp in appendChainHopDiagnosis for full chain probes
- Reconstruct tunnel state with connectIp field preserved
- Fix forward service config when bindIP already contains port
- Add contract tests for connectIp diagnosis scenarios
- Add unit test for bindIP with port in buildForwardServiceConfigs
- Update AGENTS.md with plan document rules

Entire-Checkpoint: 35a2e61c2431
This commit is contained in:
sagitchu
2026-03-03 14:17:36 +08:00
parent e38335973d
commit 1c10347357
7 changed files with 295 additions and 5 deletions
@@ -72,7 +72,7 @@ func (h *Handler) buildDiagnosisStreamStartItems(workItems []diagnosisWorkItem)
fromNode, _ := h.cachedNode(nodeCache, workItem.fromNodeID)
targetNode, err := h.cachedNode(nodeCache, workItem.toNode.NodeID)
if err == nil {
resolvedIP, resolvedPort, resolveErr := resolveChainProbeTarget(fromNode, targetNode, workItem.toNode.Port, workItem.ipPreference, "")
resolvedIP, resolvedPort, resolveErr := resolveChainProbeTarget(fromNode, targetNode, workItem.toNode.Port, workItem.ipPreference, workItem.toNode.ConnectIP)
if resolveErr == nil {
targetIP = resolvedIP
targetPort = resolvedPort
@@ -1099,7 +1099,7 @@ func (h *Handler) appendChainHopDiagnosis(results *[]map[string]interface{}, nod
h.appendFailedDiagnosis(results, nodeCache, fromNodeID, "", 0, description, metadata, err.Error())
return
}
targetIP, targetPort, err := resolveChainProbeTarget(fromNode, targetNode, toNode.Port, ipPreference, "")
targetIP, targetPort, err := resolveChainProbeTarget(fromNode, targetNode, toNode.Port, ipPreference, toNode.ConnectIP)
if err != nil {
h.appendFailedDiagnosis(results, nodeCache, fromNodeID, strings.Trim(strings.TrimSpace(targetNode.ServerIP), "[]"), toNode.Port, description, metadata, err.Error())
return
@@ -1317,12 +1317,19 @@ func buildForwardServiceConfigs(baseName string, forward *forwardRecord, tunnel
if protocol == "udp" {
listenerAddr = node.UDPListenAddr
}
var serviceAddr string
if bindIP != "" {
listenerAddr = bindIP
if strings.Contains(bindIP, ":") {
serviceAddr = processServerAddress(bindIP)
} else {
serviceAddr = processServerAddress(fmt.Sprintf("%s:%d", bindIP, port))
}
} else {
serviceAddr = processServerAddress(fmt.Sprintf("%s:%d", listenerAddr, port))
}
service := map[string]interface{}{
"name": fmt.Sprintf("%s_%s", baseName, protocol),
"addr": processServerAddress(fmt.Sprintf("%s:%d", listenerAddr, port)),
"addr": serviceAddr,
"handler": map[string]interface{}{
"type": protocol,
},