From e733148c0bf78f6298cf08045297e783568b80c9 Mon Sep 17 00:00:00 2001 From: mmmray <142015632+mmmray@users.noreply.github.com> Date: Wed, 30 Oct 2024 03:31:05 +0100 Subject: [PATCH] REALITY: Unblock SplitHTTP transport (#3816) https://github.com/XTLS/Xray-core/pull/3816#issuecomment-2445694775 --- infra/conf/transport_internet.go | 4 ++-- transport/internet/splithttp/dialer.go | 26 ++++++++++++++++++++++---- transport/internet/splithttp/hub.go | 6 ++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index 096e9ab8..dcb640aa 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -838,8 +838,8 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) { config.SecuritySettings = append(config.SecuritySettings, tm) config.SecurityType = tm.Type case "reality": - if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "grpc" { - return nil, errors.New("REALITY only supports TCP, H2 and gRPC for now.") + if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "grpc" && config.ProtocolName != "splithttp" { + return nil, errors.New("REALITY only supports TCP, H2, gRPC and SplitHTTP for now.") } if c.REALITYSettings == nil { return nil, errors.New(`REALITY: Empty "realitySettings".`) diff --git a/transport/internet/splithttp/dialer.go b/transport/internet/splithttp/dialer.go index 60f8c628..89f3b631 100644 --- a/transport/internet/splithttp/dialer.go +++ b/transport/internet/splithttp/dialer.go @@ -19,6 +19,7 @@ import ( "github.com/xtls/xray-core/common/uuid" "github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet/browser_dialer" + "github.com/xtls/xray-core/transport/internet/reality" "github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/pipe" @@ -46,7 +47,9 @@ var ( ) func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (DialerClient, *muxResource) { - if browser_dialer.HasBrowserDialer() { + realityConfig := reality.ConfigFromStreamSettings(streamSettings) + + if browser_dialer.HasBrowserDialer() && realityConfig != nil { return &BrowserDialerClient{}, nil } @@ -80,8 +83,18 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStreamConfig) DialerClient { tlsConfig := tls.ConfigFromStreamSettings(streamSettings) - isH2 := tlsConfig != nil && !(len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "http/1.1") - isH3 := tlsConfig != nil && (len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "h3") + realityConfig := reality.ConfigFromStreamSettings(streamSettings) + + isH2 := false + isH3 := false + + if tlsConfig != nil { + isH2 = !(len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "http/1.1") + isH3 = len(tlsConfig.NextProtocol) == 1 && tlsConfig.NextProtocol[0] == "h3" + } else if realityConfig != nil { + isH2 = true + isH3 = false + } if isH3 { dest.Network = net.Network_UDP @@ -101,6 +114,10 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea return nil, err } + if realityConfig != nil { + return reality.UClient(conn, realityConfig, ctxInner, dest) + } + if gotlsConfig != nil { if fingerprint := tls.GetFingerprint(tlsConfig.Fingerprint); fingerprint != nil { conn = tls.UClient(conn, gotlsConfig, fingerprint) @@ -215,12 +232,13 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me transportConfiguration := streamSettings.ProtocolSettings.(*Config) tlsConfig := tls.ConfigFromStreamSettings(streamSettings) + realityConfig := reality.ConfigFromStreamSettings(streamSettings) scMaxConcurrentPosts := transportConfiguration.GetNormalizedScMaxConcurrentPosts() scMaxEachPostBytes := transportConfiguration.GetNormalizedScMaxEachPostBytes() scMinPostsIntervalMs := transportConfiguration.GetNormalizedScMinPostsIntervalMs() - if tlsConfig != nil { + if tlsConfig != nil || realityConfig != nil { requestURL.Scheme = "https" } else { requestURL.Scheme = "http" diff --git a/transport/internet/splithttp/hub.go b/transport/internet/splithttp/hub.go index 4545db64..b7244f10 100644 --- a/transport/internet/splithttp/hub.go +++ b/transport/internet/splithttp/hub.go @@ -13,12 +13,14 @@ import ( "github.com/quic-go/quic-go" "github.com/quic-go/quic-go/http3" + goreality "github.com/xtls/reality" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" http_proto "github.com/xtls/xray-core/common/protocol/http" "github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/transport/internet" + "github.com/xtls/xray-core/transport/internet/reality" "github.com/xtls/xray-core/transport/internet/stat" v2tls "github.com/xtls/xray-core/transport/internet/tls" "golang.org/x/net/http2" @@ -344,6 +346,10 @@ func ListenSH(ctx context.Context, address net.Address, port net.Port, streamSet } } + if config := reality.ConfigFromStreamSettings(streamSettings); config != nil { + listener = goreality.NewListener(listener, config.GetREALITYConfig()) + } + // h2cHandler can handle both plaintext HTTP/1.1 and h2c h2cHandler := h2c.NewHandler(handler, &http2.Server{}) l.listener = listener