github.com/kelleygo/clashcore@v1.0.2/transport/sing-shadowtls/shadowtls.go (about) 1 package sing_shadowtls 2 3 import ( 4 "context" 5 "crypto/tls" 6 "net" 7 8 "github.com/kelleygo/clashcore/component/ca" 9 tlsC "github.com/kelleygo/clashcore/component/tls" 10 "github.com/kelleygo/clashcore/log" 11 12 "github.com/sagernet/sing-shadowtls" 13 sing_common "github.com/sagernet/sing/common" 14 utls "github.com/sagernet/utls" 15 ) 16 17 const ( 18 Mode string = "shadow-tls" 19 ) 20 21 var ( 22 DefaultALPN = []string{"h2", "http/1.1"} 23 ) 24 25 type ShadowTLSOption struct { 26 Password string 27 Host string 28 Fingerprint string 29 ClientFingerprint string 30 SkipCertVerify bool 31 Version int 32 } 33 34 func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (net.Conn, error) { 35 tlsConfig := &tls.Config{ 36 NextProtos: DefaultALPN, 37 MinVersion: tls.VersionTLS12, 38 InsecureSkipVerify: option.SkipCertVerify, 39 ServerName: option.Host, 40 } 41 42 var err error 43 tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) 44 if err != nil { 45 return nil, err 46 } 47 48 tlsHandshake := shadowtls.DefaultTLSHandshakeFunc(option.Password, tlsConfig) 49 if len(option.ClientFingerprint) != 0 { 50 if fingerprint, exists := tlsC.GetFingerprint(option.ClientFingerprint); exists { 51 tlsHandshake = uTLSHandshakeFunc(tlsConfig, *fingerprint.ClientHelloID) 52 } 53 } 54 client, err := shadowtls.NewClient(shadowtls.ClientConfig{ 55 Version: option.Version, 56 Password: option.Password, 57 TLSHandshake: tlsHandshake, 58 Logger: log.SingLogger, 59 }) 60 if err != nil { 61 return nil, err 62 } 63 return client.DialContextConn(ctx, conn) 64 } 65 66 func uTLSHandshakeFunc(config *tls.Config, clientHelloID utls.ClientHelloID) shadowtls.TLSHandshakeFunc { 67 return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error { 68 tlsConfig := &utls.Config{ 69 Rand: config.Rand, 70 Time: config.Time, 71 VerifyPeerCertificate: config.VerifyPeerCertificate, 72 RootCAs: config.RootCAs, 73 NextProtos: config.NextProtos, 74 ServerName: config.ServerName, 75 InsecureSkipVerify: config.InsecureSkipVerify, 76 CipherSuites: config.CipherSuites, 77 MinVersion: config.MinVersion, 78 MaxVersion: config.MaxVersion, 79 CurvePreferences: sing_common.Map(config.CurvePreferences, func(it tls.CurveID) utls.CurveID { 80 return utls.CurveID(it) 81 }), 82 SessionTicketsDisabled: config.SessionTicketsDisabled, 83 Renegotiation: utls.RenegotiationSupport(config.Renegotiation), 84 SessionIDGenerator: sessionIDGenerator, 85 } 86 tlsConn := utls.UClient(conn, tlsConfig, clientHelloID) 87 return tlsConn.HandshakeContext(ctx) 88 } 89 }