mirror of
https://github.com/MetaCubeX/Clash.Meta.git
synced 2025-04-19 08:40:57 +00:00
chore: better global-client-fingerprint handle
This commit is contained in:
parent
6236cb1cf0
commit
d5243adf89
10 changed files with 47 additions and 67 deletions
|
@ -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{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue