From 8652380da1868b26bc56cfb0e0f804d910c9280f Mon Sep 17 00:00:00 2001 From: sagit Date: Fri, 13 Feb 2026 05:09:46 +0000 Subject: [PATCH 1/2] feat(backend): TLS tunnel relay nodelay injection Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- .../internal/http/handler/federation.go | 20 +++++++--- go-backend/internal/http/handler/mutations.go | 38 +++++++++++++------ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/go-backend/internal/http/handler/federation.go b/go-backend/internal/http/handler/federation.go index e3bea0d..be38834 100644 --- a/go-backend/internal/http/handler/federation.go +++ b/go-backend/internal/http/handler/federation.go @@ -916,14 +916,19 @@ func (h *Handler) federationRuntimeApplyRole(w http.ResponseWriter, r *http.Requ response.WriteJSON(w, response.ErrDefault("Invalid target")) return } + targetProtocol := defaultString(target.Protocol, protocol) + connector := map[string]interface{}{ + "type": "relay", + } + if isTLSTunnelProtocol(targetProtocol) { + connector["metadata"] = map[string]interface{}{"nodelay": true} + } nodeItems = append(nodeItems, map[string]interface{}{ - "name": fmt.Sprintf("node_%d", i+1), - "addr": processServerAddress(fmt.Sprintf("%s:%d", host, target.Port)), - "connector": map[string]interface{}{ - "type": "relay", - }, + "name": fmt.Sprintf("node_%d", i+1), + "addr": processServerAddress(fmt.Sprintf("%s:%d", host, target.Port)), + "connector": connector, "dialer": map[string]interface{}{ - "type": defaultString(target.Protocol, protocol), + "type": targetProtocol, }, }) } @@ -962,6 +967,9 @@ func (h *Handler) federationRuntimeApplyRole(w http.ResponseWriter, r *http.Requ "type": protocol, }, } + if isTLSTunnelProtocol(protocol) { + service["handler"].(map[string]interface{})["metadata"] = map[string]interface{}{"nodelay": true} + } if req.Role == "middle" { service["handler"].(map[string]interface{})["chain"] = chainName } diff --git a/go-backend/internal/http/handler/mutations.go b/go-backend/internal/http/handler/mutations.go index 9784d04..3e30f3f 100644 --- a/go-backend/internal/http/handler/mutations.go +++ b/go-backend/internal/http/handler/mutations.go @@ -2564,14 +2564,19 @@ func buildTunnelChainConfig(tunnelID int64, fromNodeID int64, targets []tunnelRu if port <= 0 { return nil, errors.New("节点端口不能为空") } + protocol := defaultString(target.Protocol, "tls") + connector := map[string]interface{}{ + "type": "relay", + } + if isTLSTunnelProtocol(protocol) { + connector["metadata"] = map[string]interface{}{"nodelay": true} + } nodeItems = append(nodeItems, map[string]interface{}{ - "name": fmt.Sprintf("node_%d", idx+1), - "addr": processServerAddress(fmt.Sprintf("%s:%d", host, port)), - "connector": map[string]interface{}{ - "type": "relay", - }, + "name": fmt.Sprintf("node_%d", idx+1), + "addr": processServerAddress(fmt.Sprintf("%s:%d", host, port)), + "connector": connector, "dialer": map[string]interface{}{ - "type": defaultString(target.Protocol, "tls"), + "type": protocol, }, }) } @@ -2600,14 +2605,19 @@ func buildTunnelChainServiceConfig(tunnelID int64, chainNode tunnelRuntimeNode, if node == nil { return nil } + protocol := defaultString(chainNode.Protocol, "tls") + handlerCfg := map[string]interface{}{ + "type": "relay", + } + if isTLSTunnelProtocol(protocol) { + handlerCfg["metadata"] = map[string]interface{}{"nodelay": true} + } service := map[string]interface{}{ - "name": fmt.Sprintf("%d_tls", tunnelID), - "addr": fmt.Sprintf("%s:%d", node.TCPListenAddr, chainNode.Port), - "handler": map[string]interface{}{ - "type": "relay", - }, + "name": fmt.Sprintf("%d_tls", tunnelID), + "addr": fmt.Sprintf("%s:%d", node.TCPListenAddr, chainNode.Port), + "handler": handlerCfg, "listener": map[string]interface{}{ - "type": defaultString(chainNode.Protocol, "tls"), + "type": protocol, }, } if chainNode.ChainType == 2 { @@ -2653,6 +2663,10 @@ func nodeDisplayName(node *nodeRecord) string { return fmt.Sprintf("node_%d", node.ID) } +func isTLSTunnelProtocol(protocol string) bool { + return strings.EqualFold(strings.TrimSpace(defaultString(protocol, "tls")), "tls") +} + func nodeSupportsV4(node *nodeRecord) bool { if node == nil { return false From acea5ea76c5a80ae23e779ad018e97dbbf16b3cc Mon Sep 17 00:00:00 2001 From: sagit Date: Fri, 13 Feb 2026 05:09:54 +0000 Subject: [PATCH 2/2] fix(gost): filter expected net.ErrClosed noise in service handler Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- go-gost/x/service/service.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/go-gost/x/service/service.go b/go-gost/x/service/service.go index 0ae6c00..1819c64 100644 --- a/go-gost/x/service/service.go +++ b/go-gost/x/service/service.go @@ -54,10 +54,10 @@ var needWrap = false // SetProtocolBlock sets protocol blocking switches and recomputes wrapper need func SetProtocolBlock(httpOn int, tlsOn int, socksOn int) { - isHttp = httpOn - isTls = tlsOn - isSocks = socksOn - needWrap = isTls+isSocks+isHttp > 0 + isHttp = httpOn + isTls = tlsOn + isSocks = socksOn + needWrap = isTls+isSocks+isHttp > 0 } type Option func(opts *options) @@ -292,7 +292,9 @@ func (s *defaultService) Serve() error { } if err := s.handler.Handle(ctx, conn); err != nil { - log.Error(err) + if !errors.Is(err, net.ErrClosed) { + log.Error(err) + } if v := xmetrics.GetCounter(xmetrics.MetricServiceHandlerErrorsCounter, metrics.Labels{"service": s.name, "client": clientIP}); v != nil { v.Inc() @@ -403,12 +405,12 @@ func (s *defaultService) observeStats(ctx context.Context) { TotalErrs: st.Get(stats.KindTotalErrs), }, } - + // 将流量累积到全局管理器,而不是立即上报 if outputBytes > 0 || inputBytes > 0 { globalManager := GetGlobalTrafficManager() globalManager.AddTraffic(s.name, int64(outputBytes), int64(inputBytes)) - + // 立即重置流量计数(因为已经记录到全局管理器中) if xstats, ok := st.(*xstats.Stats); ok { xstats.ResetTraffic(st.Get(stats.KindInputBytes)-inputBytes, st.Get(stats.KindOutputBytes)-outputBytes)