mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
TLS for WSS/HUS: Allow outer "alpn": ["h2", "http/1.1"] for camouflage (#6034)
https://github.com/XTLS/Xray-core/pull/6034#issuecomment-4363639160 Closes https://github.com/XTLS/Xray-core/issues/6024#issuecomment-4328306231
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
utls "github.com/refraction-networking/utls"
|
utls "github.com/refraction-networking/utls"
|
||||||
@@ -90,18 +91,24 @@ func (c *UConn) HandshakeContextServerName(ctx context.Context) string {
|
|||||||
return c.ConnectionState().ServerName
|
return c.ConnectionState().ServerName
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebsocketHandshake basically calls UConn.Handshake inside it but it will only send
|
// WebsocketHandshakeContext basically calls UConn.Handshake inside it but it will try
|
||||||
// http/1.1 in its ALPN.
|
// to build outer ALPN to `http/1.1` or `h2 http/1.1` (if manually specified for camouflage)
|
||||||
func (c *UConn) WebsocketHandshakeContext(ctx context.Context) error {
|
func (c *UConn) WebsocketHandshakeContext(ctx context.Context) error {
|
||||||
|
config := *utils.AccessField[*utls.Config](c, "config")
|
||||||
|
ALPN := slices.Clone(config.NextProtos)
|
||||||
|
// set other kinds of ALPN to http/1.1
|
||||||
|
if !slices.Equal(ALPN, []string{"h2", "http/1.1"}) {
|
||||||
|
ALPN = []string{"http/1.1"}
|
||||||
|
}
|
||||||
// Build the handshake state. This will apply every variable of the TLS of the
|
// Build the handshake state. This will apply every variable of the TLS of the
|
||||||
// fingerprint in the UConn
|
// fingerprint in the UConn
|
||||||
if err := c.BuildHandshakeState(); err != nil {
|
if err := c.BuildHandshakeState(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
config := *utils.AccessField[*utls.Config](c, "config")
|
// Do not modify outer ALPN if ECH is used
|
||||||
// Do not modify outer ALPN to http/1.1 if ECH is used
|
// Outer ALPN will be h2,http/1.1, and real http/1.1 in config will be hidden in ECH
|
||||||
// Outer ALPN will be h2,http/1.1, and real ALPN in config will be hidden in ECH
|
|
||||||
if config.EncryptedClientHelloConfigList != nil {
|
if config.EncryptedClientHelloConfigList != nil {
|
||||||
|
config.NextProtos = []string{"http/1.1"}
|
||||||
return c.HandshakeContext(ctx)
|
return c.HandshakeContext(ctx)
|
||||||
}
|
}
|
||||||
// Iterate over extensions and check for utls.ALPNExtension
|
// Iterate over extensions and check for utls.ALPNExtension
|
||||||
@@ -109,12 +116,12 @@ func (c *UConn) WebsocketHandshakeContext(ctx context.Context) error {
|
|||||||
for _, extension := range c.Extensions {
|
for _, extension := range c.Extensions {
|
||||||
if alpn, ok := extension.(*utls.ALPNExtension); ok {
|
if alpn, ok := extension.(*utls.ALPNExtension); ok {
|
||||||
hasALPNExtension = true
|
hasALPNExtension = true
|
||||||
alpn.AlpnProtocols = []string{"http/1.1"}
|
alpn.AlpnProtocols = ALPN
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !hasALPNExtension { // Append extension if doesn't exists
|
if !hasALPNExtension { // Append extension if doesn't exists
|
||||||
c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}})
|
c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: ALPN})
|
||||||
}
|
}
|
||||||
// Rebuild the client hello and do the handshake
|
// Rebuild the client hello and do the handshake
|
||||||
if err := c.BuildHandshakeState(); err != nil {
|
if err := c.BuildHandshakeState(); err != nil {
|
||||||
@@ -146,9 +153,7 @@ func copyConfig(c *tls.Config) *utls.Config {
|
|||||||
VerifyPeerCertificate: c.VerifyPeerCertificate,
|
VerifyPeerCertificate: c.VerifyPeerCertificate,
|
||||||
KeyLogWriter: c.KeyLogWriter,
|
KeyLogWriter: c.KeyLogWriter,
|
||||||
EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
|
EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
|
||||||
}
|
NextProtos: c.NextProtos,
|
||||||
if config.EncryptedClientHelloConfigList != nil {
|
|
||||||
config.NextProtos = c.NextProtos
|
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user