mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-24 10:58:15 +08:00
chore: cleanup tls clientFingerprint code
This commit is contained in:
parent
936df90ace
commit
ee5d77cfd1
102
common/once/oncefunc.go
Normal file
102
common/once/oncefunc.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package once
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
// OnceFunc returns a function that invokes f only once. The returned function
|
||||||
|
// may be called concurrently.
|
||||||
|
//
|
||||||
|
// If f panics, the returned function will panic with the same value on every call.
|
||||||
|
func OnceFunc(f func()) func() {
|
||||||
|
var (
|
||||||
|
once sync.Once
|
||||||
|
valid bool
|
||||||
|
p any
|
||||||
|
)
|
||||||
|
// Construct the inner closure just once to reduce costs on the fast path.
|
||||||
|
g := func() {
|
||||||
|
defer func() {
|
||||||
|
p = recover()
|
||||||
|
if !valid {
|
||||||
|
// Re-panic immediately so on the first call the user gets a
|
||||||
|
// complete stack trace into f.
|
||||||
|
panic(p)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
f()
|
||||||
|
f = nil // Do not keep f alive after invoking it.
|
||||||
|
valid = true // Set only if f does not panic.
|
||||||
|
}
|
||||||
|
return func() {
|
||||||
|
once.Do(g)
|
||||||
|
if !valid {
|
||||||
|
panic(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnceValue returns a function that invokes f only once and returns the value
|
||||||
|
// returned by f. The returned function may be called concurrently.
|
||||||
|
//
|
||||||
|
// If f panics, the returned function will panic with the same value on every call.
|
||||||
|
func OnceValue[T any](f func() T) func() T {
|
||||||
|
var (
|
||||||
|
once sync.Once
|
||||||
|
valid bool
|
||||||
|
p any
|
||||||
|
result T
|
||||||
|
)
|
||||||
|
g := func() {
|
||||||
|
defer func() {
|
||||||
|
p = recover()
|
||||||
|
if !valid {
|
||||||
|
panic(p)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
result = f()
|
||||||
|
f = nil
|
||||||
|
valid = true
|
||||||
|
}
|
||||||
|
return func() T {
|
||||||
|
once.Do(g)
|
||||||
|
if !valid {
|
||||||
|
panic(p)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnceValues returns a function that invokes f only once and returns the values
|
||||||
|
// returned by f. The returned function may be called concurrently.
|
||||||
|
//
|
||||||
|
// If f panics, the returned function will panic with the same value on every call.
|
||||||
|
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
|
||||||
|
var (
|
||||||
|
once sync.Once
|
||||||
|
valid bool
|
||||||
|
p any
|
||||||
|
r1 T1
|
||||||
|
r2 T2
|
||||||
|
)
|
||||||
|
g := func() {
|
||||||
|
defer func() {
|
||||||
|
p = recover()
|
||||||
|
if !valid {
|
||||||
|
panic(p)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
r1, r2 = f()
|
||||||
|
f = nil
|
||||||
|
valid = true
|
||||||
|
}
|
||||||
|
return func() (T1, T2) {
|
||||||
|
once.Do(g)
|
||||||
|
if !valid {
|
||||||
|
panic(p)
|
||||||
|
}
|
||||||
|
return r1, r2
|
||||||
|
}
|
||||||
|
}
|
@ -37,9 +37,8 @@ type RealityConfig struct {
|
|||||||
ShortID [RealityMaxShortIDLen]byte
|
ShortID [RealityMaxShortIDLen]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRealityConn(ctx context.Context, conn net.Conn, clientFingerprint string, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) {
|
func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHelloID, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) {
|
||||||
retry := 0
|
for retry := 0; ; retry++ {
|
||||||
for fingerprint, exists := GetFingerprint(clientFingerprint); exists; retry++ {
|
|
||||||
verifier := &realityVerifier{
|
verifier := &realityVerifier{
|
||||||
serverName: tlsConfig.ServerName,
|
serverName: tlsConfig.ServerName,
|
||||||
}
|
}
|
||||||
@ -151,7 +150,6 @@ func GetRealityConn(ctx context.Context, conn net.Conn, clientFingerprint string
|
|||||||
|
|
||||||
return uConn, nil
|
return uConn, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("unknown uTLS fingerprint")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) {
|
func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/metacubex/mihomo/common/once"
|
||||||
"github.com/metacubex/mihomo/common/utils"
|
"github.com/metacubex/mihomo/common/utils"
|
||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
|
|
||||||
@ -11,46 +12,44 @@ import (
|
|||||||
"github.com/mroth/weightedrand/v2"
|
"github.com/mroth/weightedrand/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Conn = utls.Conn
|
||||||
type UConn = utls.UConn
|
type UConn = utls.UConn
|
||||||
|
type UClientHelloID = utls.ClientHelloID
|
||||||
|
|
||||||
const VersionTLS13 = utls.VersionTLS13
|
const VersionTLS13 = utls.VersionTLS13
|
||||||
|
|
||||||
type UClientHelloID struct {
|
func Client(c net.Conn, config *utls.Config) *Conn {
|
||||||
*utls.ClientHelloID
|
return utls.Client(c, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
var initRandomFingerprint UClientHelloID
|
|
||||||
var initUtlsClient string
|
|
||||||
|
|
||||||
func UClient(c net.Conn, config *utls.Config, fingerprint UClientHelloID) *UConn {
|
func UClient(c net.Conn, config *utls.Config, fingerprint UClientHelloID) *UConn {
|
||||||
return utls.UClient(c, config, *fingerprint.ClientHelloID)
|
return utls.UClient(c, config, fingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFingerprint(ClientFingerprint string) (UClientHelloID, bool) {
|
func GetFingerprint(clientFingerprint string) (UClientHelloID, bool) {
|
||||||
if ClientFingerprint == "none" {
|
if len(clientFingerprint) == 0 {
|
||||||
|
clientFingerprint = globalFingerprint
|
||||||
|
}
|
||||||
|
if len(clientFingerprint) == 0 || clientFingerprint == "none" {
|
||||||
return UClientHelloID{}, false
|
return UClientHelloID{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if initRandomFingerprint.ClientHelloID == nil {
|
if clientFingerprint == "random" {
|
||||||
initRandomFingerprint, _ = RollFingerprint()
|
fingerprint := randomFingerprint()
|
||||||
|
log.Debugln("use initial random HelloID:%s", fingerprint.Client)
|
||||||
|
return fingerprint, true
|
||||||
}
|
}
|
||||||
|
|
||||||
if ClientFingerprint == "random" {
|
if fingerprint, ok := fingerprints[clientFingerprint]; ok {
|
||||||
log.Debugln("use initial random HelloID:%s", initRandomFingerprint.Client)
|
|
||||||
return initRandomFingerprint, true
|
|
||||||
}
|
|
||||||
|
|
||||||
fingerprint, ok := Fingerprints[ClientFingerprint]
|
|
||||||
if ok {
|
|
||||||
log.Debugln("use specified fingerprint:%s", fingerprint.Client)
|
log.Debugln("use specified fingerprint:%s", fingerprint.Client)
|
||||||
return fingerprint, ok
|
return fingerprint, true
|
||||||
} else {
|
} else {
|
||||||
log.Warnln("wrong ClientFingerprint:%s", ClientFingerprint)
|
log.Warnln("wrong clientFingerprint:%s", clientFingerprint)
|
||||||
return UClientHelloID{}, false
|
return UClientHelloID{}, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RollFingerprint() (UClientHelloID, bool) {
|
var randomFingerprint = once.OnceValue(func() UClientHelloID {
|
||||||
chooser, _ := weightedrand.NewChooser(
|
chooser, _ := weightedrand.NewChooser(
|
||||||
weightedrand.NewChoice("chrome", 6),
|
weightedrand.NewChoice("chrome", 6),
|
||||||
weightedrand.NewChoice("safari", 3),
|
weightedrand.NewChoice("safari", 3),
|
||||||
@ -59,26 +58,29 @@ func RollFingerprint() (UClientHelloID, bool) {
|
|||||||
)
|
)
|
||||||
initClient := chooser.Pick()
|
initClient := chooser.Pick()
|
||||||
log.Debugln("initial random HelloID:%s", initClient)
|
log.Debugln("initial random HelloID:%s", initClient)
|
||||||
fingerprint, ok := Fingerprints[initClient]
|
fingerprint, ok := fingerprints[initClient]
|
||||||
return fingerprint, ok
|
if !ok {
|
||||||
}
|
log.Warnln("error in initial random HelloID:%s", initClient)
|
||||||
|
}
|
||||||
|
return fingerprint
|
||||||
|
})
|
||||||
|
|
||||||
var Fingerprints = map[string]UClientHelloID{
|
var fingerprints = map[string]UClientHelloID{
|
||||||
"chrome": {&utls.HelloChrome_Auto},
|
"chrome": utls.HelloChrome_Auto,
|
||||||
"chrome_psk": {&utls.HelloChrome_100_PSK},
|
"chrome_psk": utls.HelloChrome_100_PSK,
|
||||||
"chrome_psk_shuffle": {&utls.HelloChrome_106_Shuffle},
|
"chrome_psk_shuffle": utls.HelloChrome_106_Shuffle,
|
||||||
"chrome_padding_psk_shuffle": {&utls.HelloChrome_114_Padding_PSK_Shuf},
|
"chrome_padding_psk_shuffle": utls.HelloChrome_114_Padding_PSK_Shuf,
|
||||||
"chrome_pq": {&utls.HelloChrome_115_PQ},
|
"chrome_pq": utls.HelloChrome_115_PQ,
|
||||||
"chrome_pq_psk": {&utls.HelloChrome_115_PQ_PSK},
|
"chrome_pq_psk": utls.HelloChrome_115_PQ_PSK,
|
||||||
"firefox": {&utls.HelloFirefox_Auto},
|
"firefox": utls.HelloFirefox_Auto,
|
||||||
"safari": {&utls.HelloSafari_Auto},
|
"safari": utls.HelloSafari_Auto,
|
||||||
"ios": {&utls.HelloIOS_Auto},
|
"ios": utls.HelloIOS_Auto,
|
||||||
"android": {&utls.HelloAndroid_11_OkHttp},
|
"android": utls.HelloAndroid_11_OkHttp,
|
||||||
"edge": {&utls.HelloEdge_Auto},
|
"edge": utls.HelloEdge_Auto,
|
||||||
"360": {&utls.Hello360_Auto},
|
"360": utls.Hello360_Auto,
|
||||||
"qq": {&utls.HelloQQ_Auto},
|
"qq": utls.HelloQQ_Auto,
|
||||||
"random": {nil},
|
"random": {},
|
||||||
"randomized": {nil},
|
"randomized": utls.HelloRandomized,
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -88,7 +90,7 @@ func init() {
|
|||||||
randomized := utls.HelloRandomized
|
randomized := utls.HelloRandomized
|
||||||
randomized.Seed, _ = utls.NewPRNGSeed()
|
randomized.Seed, _ = utls.NewPRNGSeed()
|
||||||
randomized.Weights = &weights
|
randomized.Weights = &weights
|
||||||
Fingerprints["randomized"] = UClientHelloID{&randomized}
|
fingerprints["randomized"] = randomized
|
||||||
}
|
}
|
||||||
|
|
||||||
func UCertificates(it tls.Certificate) utls.Certificate {
|
func UCertificates(it tls.Certificate) utls.Certificate {
|
||||||
@ -154,14 +156,12 @@ func BuildWebsocketHandshakeState(c *UConn) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetGlobalUtlsClient(Client string) {
|
var globalFingerprint string
|
||||||
initUtlsClient = Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func HaveGlobalFingerprint() bool {
|
func SetGlobalFingerprint(fingerprint string) {
|
||||||
return len(initUtlsClient) != 0 && initUtlsClient != "none"
|
globalFingerprint = fingerprint
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGlobalFingerprint() string {
|
func GetGlobalFingerprint() string {
|
||||||
return initUtlsClient
|
return globalFingerprint
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@ func updateGeneral(general *config.General, logging bool) {
|
|||||||
mihomoHttp.SetUA(general.GlobalUA)
|
mihomoHttp.SetUA(general.GlobalUA)
|
||||||
resource.SetETag(general.ETagSupport)
|
resource.SetETag(general.ETagSupport)
|
||||||
|
|
||||||
tlsC.SetGlobalUtlsClient(general.GlobalClientFingerprint)
|
tlsC.SetGlobalFingerprint(general.GlobalClientFingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUsers(users []auth.AuthUser) {
|
func updateUsers(users []auth.AuthUser) {
|
||||||
|
@ -237,25 +237,19 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri
|
|||||||
return pconn, nil
|
return pconn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
clientFingerprint := clientFingerprint
|
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
|
||||||
if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 {
|
|
||||||
clientFingerprint = tlsC.GetGlobalFingerprint()
|
|
||||||
}
|
|
||||||
if len(clientFingerprint) != 0 {
|
|
||||||
if realityConfig == nil {
|
if realityConfig == nil {
|
||||||
if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists {
|
tlsConn := tlsC.UClient(pconn, tlsC.UConfig(cfg), clientFingerprint)
|
||||||
utlsConn := tlsC.UClient(pconn, tlsC.UConfig(cfg), fingerprint)
|
if err := tlsConn.HandshakeContext(ctx); err != nil {
|
||||||
if err := utlsConn.HandshakeContext(ctx); err != nil {
|
|
||||||
pconn.Close()
|
pconn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
state := utlsConn.ConnectionState()
|
state := tlsConn.ConnectionState()
|
||||||
if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
|
if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
|
||||||
utlsConn.Close()
|
tlsConn.Close()
|
||||||
return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
|
return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
|
||||||
}
|
}
|
||||||
return utlsConn, nil
|
return tlsConn, nil
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg, realityConfig)
|
realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg, realityConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
|
|
||||||
"github.com/metacubex/sing-shadowtls"
|
"github.com/metacubex/sing-shadowtls"
|
||||||
utls "github.com/metacubex/utls"
|
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,16 +66,12 @@ func uTLSHandshakeFunc(config *tls.Config, clientFingerprint string) shadowtls.T
|
|||||||
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
|
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
|
||||||
tlsConfig := tlsC.UConfig(config)
|
tlsConfig := tlsC.UConfig(config)
|
||||||
tlsConfig.SessionIDGenerator = sessionIDGenerator
|
tlsConfig.SessionIDGenerator = sessionIDGenerator
|
||||||
clientFingerprint := clientFingerprint
|
|
||||||
if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 {
|
|
||||||
clientFingerprint = tlsC.GetGlobalFingerprint()
|
|
||||||
}
|
|
||||||
if config.MaxVersion == tls.VersionTLS12 { // for ShadowTLS v1
|
if config.MaxVersion == tls.VersionTLS12 { // for ShadowTLS v1
|
||||||
clientFingerprint = ""
|
tlsConn := tlsC.Client(conn, tlsConfig)
|
||||||
|
return tlsConn.HandshakeContext(ctx)
|
||||||
}
|
}
|
||||||
if len(clientFingerprint) != 0 {
|
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
|
||||||
if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists {
|
tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint)
|
||||||
tlsConn := tlsC.UClient(conn, tlsConfig, fingerprint)
|
|
||||||
if slices.Equal(tlsConfig.NextProtos, WsALPN) {
|
if slices.Equal(tlsConfig.NextProtos, WsALPN) {
|
||||||
err := tlsC.BuildWebsocketHandshakeState(tlsConn)
|
err := tlsC.BuildWebsocketHandshakeState(tlsConn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -85,8 +80,7 @@ func uTLSHandshakeFunc(config *tls.Config, clientFingerprint string) shadowtls.T
|
|||||||
}
|
}
|
||||||
return tlsConn.HandshakeContext(ctx)
|
return tlsConn.HandshakeContext(ctx)
|
||||||
}
|
}
|
||||||
}
|
tlsConn := tlsC.Client(conn, tlsConfig)
|
||||||
tlsConn := utls.Client(conn, tlsConfig)
|
|
||||||
return tlsConn.HandshakeContext(ctx)
|
return tlsConn.HandshakeContext(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,20 +32,14 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
clientFingerprint := cfg.ClientFingerprint
|
if clientFingerprint, ok := tlsC.GetFingerprint(cfg.ClientFingerprint); ok {
|
||||||
if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 {
|
|
||||||
clientFingerprint = tlsC.GetGlobalFingerprint()
|
|
||||||
}
|
|
||||||
if len(clientFingerprint) != 0 {
|
|
||||||
if cfg.Reality == nil {
|
if cfg.Reality == nil {
|
||||||
if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists {
|
tlsConn := tlsC.UClient(conn, tlsC.UConfig(tlsConfig), clientFingerprint)
|
||||||
utlsConn := tlsC.UClient(conn, tlsC.UConfig(tlsConfig), fingerprint)
|
err = tlsConn.HandshakeContext(ctx)
|
||||||
err = utlsConn.HandshakeContext(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return utlsConn, nil
|
return tlsConn, nil
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return tlsC.GetRealityConn(ctx, conn, clientFingerprint, tlsConfig, cfg.Reality)
|
return tlsC.GetRealityConn(ctx, conn, clientFingerprint, tlsConfig, cfg.Reality)
|
||||||
}
|
}
|
||||||
|
@ -351,31 +351,26 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
|
|||||||
}
|
}
|
||||||
if config.ServerName == "" && !config.InsecureSkipVerify { // users must set either ServerName or InsecureSkipVerify in the config.
|
if config.ServerName == "" && !config.InsecureSkipVerify { // users must set either ServerName or InsecureSkipVerify in the config.
|
||||||
config = config.Clone()
|
config = config.Clone()
|
||||||
config.ServerName = uri.Host
|
config.ServerName = c.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
clientFingerprint := c.ClientFingerprint
|
if clientFingerprint, ok := tlsC.GetFingerprint(c.ClientFingerprint); ok {
|
||||||
if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 {
|
tlsConn := tlsC.UClient(conn, tlsC.UConfig(config), clientFingerprint)
|
||||||
clientFingerprint = tlsC.GetGlobalFingerprint()
|
if err = tlsC.BuildWebsocketHandshakeState(tlsConn); err != nil {
|
||||||
}
|
|
||||||
if len(clientFingerprint) != 0 {
|
|
||||||
if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists {
|
|
||||||
utlsConn := tlsC.UClient(conn, tlsC.UConfig(config), fingerprint)
|
|
||||||
if err = tlsC.BuildWebsocketHandshakeState(utlsConn); err != nil {
|
|
||||||
return nil, fmt.Errorf("parse url %s error: %w", c.Path, err)
|
return nil, fmt.Errorf("parse url %s error: %w", c.Path, err)
|
||||||
}
|
}
|
||||||
conn = utlsConn
|
err = tlsConn.HandshakeContext(ctx)
|
||||||
}
|
if err != nil {
|
||||||
} else {
|
|
||||||
conn = tls.Client(conn, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tlsConn, ok := conn.(interface {
|
|
||||||
HandshakeContext(ctx context.Context) error
|
|
||||||
}); ok {
|
|
||||||
if err = tlsConn.HandshakeContext(ctx); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
conn = tlsConn
|
||||||
|
} else {
|
||||||
|
tlsConn := tls.Client(conn, config)
|
||||||
|
err = tlsConn.HandshakeContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn = tlsConn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user