mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2024-11-16 06:01:21 +08:00
92 lines
2.7 KiB
Go
92 lines
2.7 KiB
Go
|
package sing_shadowtls
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto/tls"
|
||
|
"net"
|
||
|
|
||
|
tlsC "github.com/Dreamacro/clash/component/tls"
|
||
|
"github.com/Dreamacro/clash/log"
|
||
|
|
||
|
"github.com/sagernet/sing-shadowtls"
|
||
|
sing_common "github.com/sagernet/sing/common"
|
||
|
utls "github.com/sagernet/utls"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
Mode string = "shadow-tls"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
DefaultALPN = []string{"h2", "http/1.1"}
|
||
|
)
|
||
|
|
||
|
type ShadowTLSOption struct {
|
||
|
Password string
|
||
|
Host string
|
||
|
Fingerprint string
|
||
|
ClientFingerprint string
|
||
|
SkipCertVerify bool
|
||
|
Version int
|
||
|
}
|
||
|
|
||
|
func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (net.Conn, error) {
|
||
|
tlsConfig := &tls.Config{
|
||
|
NextProtos: DefaultALPN,
|
||
|
MinVersion: tls.VersionTLS12,
|
||
|
InsecureSkipVerify: option.SkipCertVerify,
|
||
|
ServerName: option.Host,
|
||
|
}
|
||
|
|
||
|
var err error
|
||
|
if len(option.Fingerprint) == 0 {
|
||
|
tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig)
|
||
|
} else {
|
||
|
if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tlsHandshake := shadowtls.DefaultTLSHandshakeFunc(option.Password, tlsConfig)
|
||
|
if len(option.ClientFingerprint) != 0 {
|
||
|
if fingerprint, exists := tlsC.GetFingerprint(option.ClientFingerprint); exists {
|
||
|
tlsHandshake = uTLSHandshakeFunc(tlsConfig, *fingerprint.ClientHelloID)
|
||
|
}
|
||
|
}
|
||
|
client, err := shadowtls.NewClient(shadowtls.ClientConfig{
|
||
|
Version: option.Version,
|
||
|
Password: option.Password,
|
||
|
TLSHandshake: tlsHandshake,
|
||
|
Logger: log.SingLogger,
|
||
|
})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return client.DialContextConn(ctx, conn)
|
||
|
}
|
||
|
|
||
|
func uTLSHandshakeFunc(config *tls.Config, clientHelloID utls.ClientHelloID) shadowtls.TLSHandshakeFunc {
|
||
|
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
|
||
|
tlsConfig := &utls.Config{
|
||
|
Rand: config.Rand,
|
||
|
Time: config.Time,
|
||
|
VerifyPeerCertificate: config.VerifyPeerCertificate,
|
||
|
RootCAs: config.RootCAs,
|
||
|
NextProtos: config.NextProtos,
|
||
|
ServerName: config.ServerName,
|
||
|
InsecureSkipVerify: config.InsecureSkipVerify,
|
||
|
CipherSuites: config.CipherSuites,
|
||
|
MinVersion: config.MinVersion,
|
||
|
MaxVersion: config.MaxVersion,
|
||
|
CurvePreferences: sing_common.Map(config.CurvePreferences, func(it tls.CurveID) utls.CurveID {
|
||
|
return utls.CurveID(it)
|
||
|
}),
|
||
|
SessionTicketsDisabled: config.SessionTicketsDisabled,
|
||
|
Renegotiation: utls.RenegotiationSupport(config.Renegotiation),
|
||
|
SessionIDGenerator: sessionIDGenerator,
|
||
|
}
|
||
|
tlsConn := utls.UClient(conn, tlsConfig, clientHelloID)
|
||
|
return tlsConn.HandshakeContext(ctx)
|
||
|
}
|
||
|
}
|