From d5243adf8911563677d3bd190b82623c93e554b7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 19 Apr 2025 02:04:09 +0800 Subject: [PATCH] chore: better global-client-fingerprint handle --- adapter/outbound/anytls.go | 4 ---- adapter/outbound/trojan.go | 8 +------- adapter/outbound/vless.go | 8 +------- adapter/outbound/vmess.go | 8 +------- adapter/parser.go | 8 +++----- component/tls/reality.go | 4 ++-- transport/gun/gun.go | 12 ++++++++---- transport/sing-shadowtls/shadowtls.go | 26 ++++++++++++------------- transport/vmess/tls.go | 28 ++++++++++++--------------- transport/vmess/websocket.go | 8 ++++++-- 10 files changed, 47 insertions(+), 67 deletions(-) diff --git a/adapter/outbound/anytls.go b/adapter/outbound/anytls.go index 4727b188..7fb1d9c6 100644 --- a/adapter/outbound/anytls.go +++ b/adapter/outbound/anytls.go @@ -11,7 +11,6 @@ import ( "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/proxydialer" "github.com/metacubex/mihomo/component/resolver" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/anytls" "github.com/metacubex/mihomo/transport/vmess" @@ -115,9 +114,6 @@ func NewAnyTLS(option AnyTLSOption) (*AnyTLS, error) { if tlsConfig.Host == "" { tlsConfig.Host = option.Server } - if tlsC.HaveGlobalFingerprint() && len(option.ClientFingerprint) == 0 { - tlsConfig.ClientFingerprint = tlsC.GetGlobalFingerprint() - } tOption.TLSConfig = tlsConfig outbound := &AnyTLS{ diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 257b58d6..d6ca4379 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -63,13 +63,7 @@ type TrojanSSOption struct { } // StreamConnContext implements C.ProxyAdapter -func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { - var err error - - if tlsC.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 { - t.option.ClientFingerprint = tlsC.GetGlobalFingerprint() - } - +func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ net.Conn, err error) { switch t.option.Network { case "ws": host, port, _ := net.SplitHostPort(t.addr) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 9cdccef9..4d1a23b8 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -75,13 +75,7 @@ type VlessOption struct { ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } -func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { - var err error - - if tlsC.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 { - v.option.ClientFingerprint = tlsC.GetGlobalFingerprint() - } - +func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ net.Conn, err error) { switch v.option.Network { case "ws": host, port, _ := net.SplitHostPort(v.addr) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 42b8a434..fddef0e1 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -96,13 +96,7 @@ type WSOptions struct { } // StreamConnContext implements C.ProxyAdapter -func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { - var err error - - if tlsC.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) { - v.option.ClientFingerprint = tlsC.GetGlobalFingerprint() - } - +func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ net.Conn, err error) { switch v.option.Network { case "ws": host, port, _ := net.SplitHostPort(v.addr) diff --git a/adapter/parser.go b/adapter/parser.go index 48359f70..56febe28 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -5,7 +5,6 @@ import ( "github.com/metacubex/mihomo/adapter/outbound" "github.com/metacubex/mihomo/common/structure" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" ) @@ -22,7 +21,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { ) switch proxyType { case "ss": - ssOption := &outbound.ShadowSocksOption{ClientFingerprint: tlsC.GetGlobalFingerprint()} + ssOption := &outbound.ShadowSocksOption{} err = decoder.Decode(mapping, ssOption) if err != nil { break @@ -55,7 +54,6 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { Method: "GET", Path: []string{"/"}, }, - ClientFingerprint: tlsC.GetGlobalFingerprint(), } err = decoder.Decode(mapping, vmessOption) @@ -64,7 +62,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { } proxy, err = outbound.NewVmess(*vmessOption) case "vless": - vlessOption := &outbound.VlessOption{ClientFingerprint: tlsC.GetGlobalFingerprint()} + vlessOption := &outbound.VlessOption{} err = decoder.Decode(mapping, vlessOption) if err != nil { break @@ -78,7 +76,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { } proxy, err = outbound.NewSnell(*snellOption) case "trojan": - trojanOption := &outbound.TrojanOption{ClientFingerprint: tlsC.GetGlobalFingerprint()} + trojanOption := &outbound.TrojanOption{} err = decoder.Decode(mapping, trojanOption) if err != nil { break diff --git a/component/tls/reality.go b/component/tls/reality.go index 5beffb43..eee37384 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -37,9 +37,9 @@ type RealityConfig struct { 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, clientFingerprint string, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) { retry := 0 - for fingerprint, exists := GetFingerprint(ClientFingerprint); exists; retry++ { + for fingerprint, exists := GetFingerprint(clientFingerprint); exists; retry++ { verifier := &realityVerifier{ serverName: tlsConfig.ServerName, } diff --git a/transport/gun/gun.go b/transport/gun/gun.go index b9f03ce7..8889baa7 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -224,7 +224,7 @@ func (g *Conn) SetDeadline(t time.Time) error { return nil } -func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap { +func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap { dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout) defer cancel() @@ -237,9 +237,13 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re return pconn, nil } - if len(Fingerprint) != 0 { + clientFingerprint := clientFingerprint + if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 { + clientFingerprint = tlsC.GetGlobalFingerprint() + } + if len(clientFingerprint) != 0 { if realityConfig == nil { - if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { + if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists { utlsConn := tlsC.UClient(pconn, cfg, fingerprint) if err := utlsConn.HandshakeContext(ctx); err != nil { pconn.Close() @@ -253,7 +257,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re return utlsConn, nil } } else { - realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, cfg, realityConfig) + realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg, realityConfig) if err != nil { pconn.Close() return nil, err diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go index 7bfd4578..a628e7b1 100644 --- a/transport/sing-shadowtls/shadowtls.go +++ b/transport/sing-shadowtls/shadowtls.go @@ -45,13 +45,7 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) ( return nil, err } - var clientHelloID utls.ClientHelloID - if len(option.ClientFingerprint) != 0 { - if fingerprint, exists := tlsC.GetFingerprint(option.ClientFingerprint); exists { - clientHelloID = *fingerprint.ClientHelloID - } - } - tlsHandshake := uTLSHandshakeFunc(tlsConfig, clientHelloID) + tlsHandshake := uTLSHandshakeFunc(tlsConfig, option.ClientFingerprint) client, err := shadowtls.NewClient(shadowtls.ClientConfig{ Version: option.Version, Password: option.Password, @@ -64,7 +58,7 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) ( return client.DialContextConn(ctx, conn) } -func uTLSHandshakeFunc(config *tls.Config, clientHelloID utls.ClientHelloID) shadowtls.TLSHandshakeFunc { +func uTLSHandshakeFunc(config *tls.Config, clientFingerprint string) shadowtls.TLSHandshakeFunc { return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error { tlsConfig := &utls.Config{ Rand: config.Rand, @@ -84,12 +78,18 @@ func uTLSHandshakeFunc(config *tls.Config, clientHelloID utls.ClientHelloID) sha Renegotiation: utls.RenegotiationSupport(config.Renegotiation), SessionIDGenerator: sessionIDGenerator, } - var empty utls.ClientHelloID - if clientHelloID == empty { - tlsConn := utls.Client(conn, tlsConfig) - return tlsConn.Handshake() + clientFingerprint := clientFingerprint + if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 { + clientFingerprint = tlsC.GetGlobalFingerprint() } - tlsConn := utls.UClient(conn, tlsConfig, clientHelloID) + if len(clientFingerprint) != 0 { + if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists { + clientHelloID := *fingerprint.ClientHelloID + tlsConn := utls.UClient(conn, tlsConfig, clientHelloID) + return tlsConn.HandshakeContext(ctx) + } + } + tlsConn := utls.Client(conn, tlsConfig) return tlsConn.HandshakeContext(ctx) } } diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 82a484f1..ff622995 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -32,15 +32,22 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn return nil, err } - if len(cfg.ClientFingerprint) != 0 { + clientFingerprint := cfg.ClientFingerprint + if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 { + clientFingerprint = tlsC.GetGlobalFingerprint() + } + if len(clientFingerprint) != 0 { if cfg.Reality == nil { - utlsConn, valid := GetUTLSConn(conn, cfg.ClientFingerprint, tlsConfig) - if valid { + if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists { + utlsConn := tlsC.UClient(conn, tlsConfig, fingerprint) err = utlsConn.HandshakeContext(ctx) - return utlsConn, err + if err != nil { + return nil, err + } + return utlsConn, nil } } else { - return tlsC.GetRealityConn(ctx, conn, cfg.ClientFingerprint, tlsConfig, cfg.Reality) + return tlsC.GetRealityConn(ctx, conn, clientFingerprint, tlsConfig, cfg.Reality) } } if cfg.Reality != nil { @@ -52,14 +59,3 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn err = tlsConn.HandshakeContext(ctx) return tlsConn, err } - -func GetUTLSConn(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (*tlsC.UConn, bool) { - - if fingerprint, exists := tlsC.GetFingerprint(ClientFingerprint); exists { - utlsConn := tlsC.UClient(conn, tlsConfig, fingerprint) - - return utlsConn, true - } - - return nil, false -} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 8ada88ec..43b695ee 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -354,8 +354,12 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, config.ServerName = uri.Host } - if len(c.ClientFingerprint) != 0 { - if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { + clientFingerprint := c.ClientFingerprint + if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 { + clientFingerprint = tlsC.GetGlobalFingerprint() + } + if len(clientFingerprint) != 0 { + if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists { utlsConn := tlsC.UClient(conn, config, fingerprint) if err = utlsConn.BuildWebsocketHandshakeState(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err)