From a28e215bf0e05bdba456aa1b96340a3f0f41218c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Tue, 24 Feb 2026 12:27:39 +0000 Subject: [PATCH] Hide ALPN in ECH --- go.mod | 2 ++ go.sum | 4 ++-- transport/internet/tls/tls.go | 13 ++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2da39f3b..927c4e3e 100644 --- a/go.mod +++ b/go.mod @@ -52,3 +52,5 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/refraction-networking/utls => github.com/fangliding/utls v0.0.0-20260223095720-1ba92b0f6acd diff --git a/go.sum b/go.sum index b386a3a5..b5ea7d14 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fangliding/utls v0.0.0-20260223095720-1ba92b0f6acd h1:gOZhm1IpArbRLXkLzT5m11HU/HLJmp1aI6/WQLZ85+Y= +github.com/fangliding/utls v0.0.0-20260223095720-1ba92b0f6acd/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= @@ -51,8 +53,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= -github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo= -github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y= diff --git a/transport/internet/tls/tls.go b/transport/internet/tls/tls.go index cbc80bf5..7bd64a7e 100644 --- a/transport/internet/tls/tls.go +++ b/transport/internet/tls/tls.go @@ -10,6 +10,7 @@ import ( utls "github.com/refraction-networking/utls" "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/net" + "github.com/xtls/xray-core/common/utils" ) type Interface interface { @@ -97,6 +98,12 @@ func (c *UConn) WebsocketHandshakeContext(ctx context.Context) error { if err := c.BuildHandshakeState(); err != nil { return err } + config := *utils.AccessField[*utls.Config](c, "config") + // Do not modify outer ALPN to http/1.1 if ECH is used + // Outer ALPN will be h2,http/1.1, and real ALPN in config will be hidden in ECH + if config.EncryptedClientHelloConfigList != nil { + return c.HandshakeContext(ctx) + } // Iterate over extensions and check for utls.ALPNExtension hasALPNExtension := false for _, extension := range c.Extensions { @@ -131,7 +138,7 @@ func GeneraticUClient(c net.Conn, config *tls.Config) *utls.UConn { } func copyConfig(c *tls.Config) *utls.Config { - return &utls.Config{ + config := &utls.Config{ Rand: c.Rand, RootCAs: c.RootCAs, ServerName: c.ServerName, @@ -140,6 +147,10 @@ func copyConfig(c *tls.Config) *utls.Config { KeyLogWriter: c.KeyLogWriter, EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList, } + if config.EncryptedClientHelloConfigList != nil { + config.NextProtos = c.NextProtos + } + return config } func init() {