Clash.Meta/transport/sing-shadowtls/shadowtls.go

87 lines
2.3 KiB
Go
Raw Normal View History

package sing_shadowtls
import (
"context"
"crypto/tls"
"net"
2023-11-03 21:01:45 +08:00
"github.com/metacubex/mihomo/component/ca"
tlsC "github.com/metacubex/mihomo/component/tls"
"github.com/metacubex/mihomo/log"
"github.com/metacubex/sing-shadowtls"
2025-04-22 23:44:55 +08:00
"golang.org/x/exp/slices"
)
const (
Mode string = "shadow-tls"
)
var (
DefaultALPN = []string{"h2", "http/1.1"}
2025-04-22 23:44:55 +08:00
WsALPN = []string{"http/1.1"}
)
type ShadowTLSOption struct {
Password string
Host string
Fingerprint string
ClientFingerprint string
SkipCertVerify bool
Version int
2025-04-22 20:49:54 +08:00
ALPN []string
}
func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (net.Conn, error) {
tlsConfig := &tls.Config{
2025-04-22 20:49:54 +08:00
NextProtos: option.ALPN,
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: option.SkipCertVerify,
ServerName: option.Host,
}
2025-04-22 20:09:24 +08:00
if option.Version == 1 {
tlsConfig.MaxVersion = tls.VersionTLS12 // ShadowTLS v1 only support TLS 1.2
}
var err error
2023-09-22 14:45:34 +08:00
tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint)
if err != nil {
return nil, err
}
tlsHandshake := uTLSHandshakeFunc(tlsConfig, option.ClientFingerprint)
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, clientFingerprint string) shadowtls.TLSHandshakeFunc {
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
2025-04-21 12:07:33 +08:00
tlsConfig := tlsC.UConfig(config)
tlsConfig.SessionIDGenerator = sessionIDGenerator
2025-04-22 23:44:55 +08:00
if config.MaxVersion == tls.VersionTLS12 { // for ShadowTLS v1
tlsConn := tlsC.Client(conn, tlsConfig)
return tlsConn.HandshakeContext(ctx)
2025-04-22 23:44:55 +08:00
}
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok {
tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint)
if slices.Equal(tlsConfig.NextProtos, WsALPN) {
err := tlsC.BuildWebsocketHandshakeState(tlsConn)
if err != nil {
return err
2025-04-22 23:44:55 +08:00
}
}
return tlsConn.HandshakeContext(ctx)
}
tlsConn := tlsC.Client(conn, tlsConfig)
return tlsConn.HandshakeContext(ctx)
}
}