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  }