github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/transport/internet/tls/utls/utls.go (about) 1 package utls 2 3 import ( 4 "context" 5 systls "crypto/tls" 6 7 utls "github.com/refraction-networking/utls" 8 9 "github.com/v2fly/v2ray-core/v5/common" 10 "github.com/v2fly/v2ray-core/v5/common/net" 11 "github.com/v2fly/v2ray-core/v5/transport/internet/security" 12 "github.com/v2fly/v2ray-core/v5/transport/internet/tls" 13 ) 14 15 //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen 16 17 func NewUTLSSecurityEngineFromConfig(config *Config) (security.Engine, error) { 18 if config.TlsConfig == nil { 19 return nil, newError("mandatory field tls_config is not specified") 20 } 21 return &Engine{config: config}, nil 22 } 23 24 type Engine struct { 25 config *Config 26 } 27 28 func (e Engine) Client(conn net.Conn, opts ...security.Option) (security.Conn, error) { 29 var options []tls.Option 30 for _, v := range opts { 31 switch s := v.(type) { 32 case security.OptionWithALPN: 33 if e.config.ForceAlpn == ForcedALPN_TRANSPORT_PREFERENCE_TAKE_PRIORITY { 34 options = append(options, tls.WithNextProto(s.ALPNs...)) 35 } 36 case security.OptionWithDestination: 37 options = append(options, tls.WithDestination(s.Dest)) 38 default: 39 return nil, newError("unknown option") 40 } 41 } 42 tlsConfig := e.config.TlsConfig.GetTLSConfig(options...) 43 utlsConfig, err := uTLSConfigFromTLSConfig(tlsConfig) 44 if err != nil { 45 return nil, newError("unable to generate utls config from tls config").Base(err) 46 } 47 48 preset, err := nameToUTLSPreset(e.config.Imitate) 49 if err != nil { 50 return nil, newError("unable to get utls preset from name").Base(err) 51 } 52 53 utlsClientConn := utls.UClient(conn, utlsConfig, *preset) 54 55 if e.config.NoSNI { 56 err = utlsClientConn.RemoveSNIExtension() 57 if err != nil { 58 return nil, newError("unable to remove server name indication from utls client hello").Base(err) 59 } 60 } 61 62 err = utlsClientConn.BuildHandshakeState() 63 if err != nil { 64 return nil, newError("unable to build utls handshake state").Base(err) 65 } 66 67 // ALPN is necessary for protocols like websocket to work. The uTLS setting may be overwritten on call into 68 // BuildHandshakeState, so we need to check the original tls settings. 69 if tlsConfig.NextProtos != nil { 70 for n, v := range utlsClientConn.Extensions { 71 if aplnExtension, ok := v.(*utls.ALPNExtension); ok { 72 if e.config.ForceAlpn == ForcedALPN_TRANSPORT_PREFERENCE_TAKE_PRIORITY { 73 aplnExtension.AlpnProtocols = tlsConfig.NextProtos 74 break 75 } 76 if e.config.ForceAlpn == ForcedALPN_NO_ALPN { 77 utlsClientConn.Extensions = append(utlsClientConn.Extensions[:n], utlsClientConn.Extensions[n+1:]...) 78 break 79 } 80 } 81 } 82 } 83 84 err = utlsClientConn.BuildHandshakeState() 85 if err != nil { 86 return nil, newError("unable to build utls handshake state after modification").Base(err) 87 } 88 89 err = utlsClientConn.Handshake() 90 if err != nil { 91 return nil, newError("unable to finish utls handshake").Base(err) 92 } 93 return uTLSClientConnection{utlsClientConn}, nil 94 } 95 96 type uTLSClientConnection struct { 97 *utls.UConn 98 } 99 100 func (u uTLSClientConnection) GetConnectionApplicationProtocol() (string, error) { 101 if err := u.Handshake(); err != nil { 102 return "", err 103 } 104 return u.ConnectionState().NegotiatedProtocol, nil 105 } 106 107 func uTLSConfigFromTLSConfig(config *systls.Config) (*utls.Config, error) { // nolint: unparam 108 uconfig := &utls.Config{ 109 Rand: config.Rand, 110 Time: config.Time, 111 RootCAs: config.RootCAs, 112 NextProtos: config.NextProtos, 113 ServerName: config.ServerName, 114 } 115 return uconfig, nil 116 } 117 118 func init() { 119 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 120 return NewUTLSSecurityEngineFromConfig(config.(*Config)) 121 })) 122 }