mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-12 21:18:03 +08:00
chore: better global-client-fingerprint handle
This commit is contained in:
parent
6236cb1cf0
commit
d5243adf89
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/proxydialer"
|
"github.com/metacubex/mihomo/component/proxydialer"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
"github.com/metacubex/mihomo/component/resolver"
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/transport/anytls"
|
"github.com/metacubex/mihomo/transport/anytls"
|
||||||
"github.com/metacubex/mihomo/transport/vmess"
|
"github.com/metacubex/mihomo/transport/vmess"
|
||||||
@ -115,9 +114,6 @@ func NewAnyTLS(option AnyTLSOption) (*AnyTLS, error) {
|
|||||||
if tlsConfig.Host == "" {
|
if tlsConfig.Host == "" {
|
||||||
tlsConfig.Host = option.Server
|
tlsConfig.Host = option.Server
|
||||||
}
|
}
|
||||||
if tlsC.HaveGlobalFingerprint() && len(option.ClientFingerprint) == 0 {
|
|
||||||
tlsConfig.ClientFingerprint = tlsC.GetGlobalFingerprint()
|
|
||||||
}
|
|
||||||
tOption.TLSConfig = tlsConfig
|
tOption.TLSConfig = tlsConfig
|
||||||
|
|
||||||
outbound := &AnyTLS{
|
outbound := &AnyTLS{
|
||||||
|
@ -63,13 +63,7 @@ type TrojanSSOption struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StreamConnContext implements C.ProxyAdapter
|
// StreamConnContext implements C.ProxyAdapter
|
||||||
func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ net.Conn, err error) {
|
||||||
var err error
|
|
||||||
|
|
||||||
if tlsC.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 {
|
|
||||||
t.option.ClientFingerprint = tlsC.GetGlobalFingerprint()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t.option.Network {
|
switch t.option.Network {
|
||||||
case "ws":
|
case "ws":
|
||||||
host, port, _ := net.SplitHostPort(t.addr)
|
host, port, _ := net.SplitHostPort(t.addr)
|
||||||
|
@ -75,13 +75,7 @@ type VlessOption struct {
|
|||||||
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
|
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ net.Conn, err error) {
|
||||||
var err error
|
|
||||||
|
|
||||||
if tlsC.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 {
|
|
||||||
v.option.ClientFingerprint = tlsC.GetGlobalFingerprint()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v.option.Network {
|
switch v.option.Network {
|
||||||
case "ws":
|
case "ws":
|
||||||
host, port, _ := net.SplitHostPort(v.addr)
|
host, port, _ := net.SplitHostPort(v.addr)
|
||||||
|
@ -96,13 +96,7 @@ type WSOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StreamConnContext implements C.ProxyAdapter
|
// StreamConnContext implements C.ProxyAdapter
|
||||||
func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ net.Conn, err error) {
|
||||||
var err error
|
|
||||||
|
|
||||||
if tlsC.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) {
|
|
||||||
v.option.ClientFingerprint = tlsC.GetGlobalFingerprint()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v.option.Network {
|
switch v.option.Network {
|
||||||
case "ws":
|
case "ws":
|
||||||
host, port, _ := net.SplitHostPort(v.addr)
|
host, port, _ := net.SplitHostPort(v.addr)
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/metacubex/mihomo/adapter/outbound"
|
"github.com/metacubex/mihomo/adapter/outbound"
|
||||||
"github.com/metacubex/mihomo/common/structure"
|
"github.com/metacubex/mihomo/common/structure"
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,7 +21,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
|
|||||||
)
|
)
|
||||||
switch proxyType {
|
switch proxyType {
|
||||||
case "ss":
|
case "ss":
|
||||||
ssOption := &outbound.ShadowSocksOption{ClientFingerprint: tlsC.GetGlobalFingerprint()}
|
ssOption := &outbound.ShadowSocksOption{}
|
||||||
err = decoder.Decode(mapping, ssOption)
|
err = decoder.Decode(mapping, ssOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
@ -55,7 +54,6 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
|
|||||||
Method: "GET",
|
Method: "GET",
|
||||||
Path: []string{"/"},
|
Path: []string{"/"},
|
||||||
},
|
},
|
||||||
ClientFingerprint: tlsC.GetGlobalFingerprint(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = decoder.Decode(mapping, vmessOption)
|
err = decoder.Decode(mapping, vmessOption)
|
||||||
@ -64,7 +62,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
|
|||||||
}
|
}
|
||||||
proxy, err = outbound.NewVmess(*vmessOption)
|
proxy, err = outbound.NewVmess(*vmessOption)
|
||||||
case "vless":
|
case "vless":
|
||||||
vlessOption := &outbound.VlessOption{ClientFingerprint: tlsC.GetGlobalFingerprint()}
|
vlessOption := &outbound.VlessOption{}
|
||||||
err = decoder.Decode(mapping, vlessOption)
|
err = decoder.Decode(mapping, vlessOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
@ -78,7 +76,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
|
|||||||
}
|
}
|
||||||
proxy, err = outbound.NewSnell(*snellOption)
|
proxy, err = outbound.NewSnell(*snellOption)
|
||||||
case "trojan":
|
case "trojan":
|
||||||
trojanOption := &outbound.TrojanOption{ClientFingerprint: tlsC.GetGlobalFingerprint()}
|
trojanOption := &outbound.TrojanOption{}
|
||||||
err = decoder.Decode(mapping, trojanOption)
|
err = decoder.Decode(mapping, trojanOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
|
@ -37,9 +37,9 @@ 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, clientFingerprint string, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) {
|
||||||
retry := 0
|
retry := 0
|
||||||
for fingerprint, exists := GetFingerprint(ClientFingerprint); exists; retry++ {
|
for fingerprint, exists := GetFingerprint(clientFingerprint); exists; retry++ {
|
||||||
verifier := &realityVerifier{
|
verifier := &realityVerifier{
|
||||||
serverName: tlsConfig.ServerName,
|
serverName: tlsConfig.ServerName,
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ func (g *Conn) SetDeadline(t time.Time) error {
|
|||||||
return nil
|
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) {
|
dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout)
|
ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -237,9 +237,13 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re
|
|||||||
return pconn, nil
|
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 realityConfig == nil {
|
||||||
if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists {
|
if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists {
|
||||||
utlsConn := tlsC.UClient(pconn, cfg, fingerprint)
|
utlsConn := tlsC.UClient(pconn, cfg, fingerprint)
|
||||||
if err := utlsConn.HandshakeContext(ctx); err != nil {
|
if err := utlsConn.HandshakeContext(ctx); err != nil {
|
||||||
pconn.Close()
|
pconn.Close()
|
||||||
@ -253,7 +257,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re
|
|||||||
return utlsConn, nil
|
return utlsConn, nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, cfg, realityConfig)
|
realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg, realityConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pconn.Close()
|
pconn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -45,13 +45,7 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientHelloID utls.ClientHelloID
|
tlsHandshake := uTLSHandshakeFunc(tlsConfig, option.ClientFingerprint)
|
||||||
if len(option.ClientFingerprint) != 0 {
|
|
||||||
if fingerprint, exists := tlsC.GetFingerprint(option.ClientFingerprint); exists {
|
|
||||||
clientHelloID = *fingerprint.ClientHelloID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tlsHandshake := uTLSHandshakeFunc(tlsConfig, clientHelloID)
|
|
||||||
client, err := shadowtls.NewClient(shadowtls.ClientConfig{
|
client, err := shadowtls.NewClient(shadowtls.ClientConfig{
|
||||||
Version: option.Version,
|
Version: option.Version,
|
||||||
Password: option.Password,
|
Password: option.Password,
|
||||||
@ -64,7 +58,7 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (
|
|||||||
return client.DialContextConn(ctx, conn)
|
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 {
|
return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
|
||||||
tlsConfig := &utls.Config{
|
tlsConfig := &utls.Config{
|
||||||
Rand: config.Rand,
|
Rand: config.Rand,
|
||||||
@ -84,12 +78,18 @@ func uTLSHandshakeFunc(config *tls.Config, clientHelloID utls.ClientHelloID) sha
|
|||||||
Renegotiation: utls.RenegotiationSupport(config.Renegotiation),
|
Renegotiation: utls.RenegotiationSupport(config.Renegotiation),
|
||||||
SessionIDGenerator: sessionIDGenerator,
|
SessionIDGenerator: sessionIDGenerator,
|
||||||
}
|
}
|
||||||
var empty utls.ClientHelloID
|
clientFingerprint := clientFingerprint
|
||||||
if clientHelloID == empty {
|
if tlsC.HaveGlobalFingerprint() && len(clientFingerprint) == 0 {
|
||||||
tlsConn := utls.Client(conn, tlsConfig)
|
clientFingerprint = tlsC.GetGlobalFingerprint()
|
||||||
return tlsConn.Handshake()
|
|
||||||
}
|
}
|
||||||
|
if len(clientFingerprint) != 0 {
|
||||||
|
if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists {
|
||||||
|
clientHelloID := *fingerprint.ClientHelloID
|
||||||
tlsConn := utls.UClient(conn, tlsConfig, clientHelloID)
|
tlsConn := utls.UClient(conn, tlsConfig, clientHelloID)
|
||||||
return tlsConn.HandshakeContext(ctx)
|
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
|
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 {
|
if cfg.Reality == nil {
|
||||||
utlsConn, valid := GetUTLSConn(conn, cfg.ClientFingerprint, tlsConfig)
|
if fingerprint, exists := tlsC.GetFingerprint(clientFingerprint); exists {
|
||||||
if valid {
|
utlsConn := tlsC.UClient(conn, tlsConfig, fingerprint)
|
||||||
err = utlsConn.HandshakeContext(ctx)
|
err = utlsConn.HandshakeContext(ctx)
|
||||||
return utlsConn, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return utlsConn, nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return tlsC.GetRealityConn(ctx, conn, cfg.ClientFingerprint, tlsConfig, cfg.Reality)
|
return tlsC.GetRealityConn(ctx, conn, clientFingerprint, tlsConfig, cfg.Reality)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cfg.Reality != nil {
|
if cfg.Reality != nil {
|
||||||
@ -52,14 +59,3 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn
|
|||||||
err = tlsConn.HandshakeContext(ctx)
|
err = tlsConn.HandshakeContext(ctx)
|
||||||
return tlsConn, err
|
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
|
config.ServerName = uri.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.ClientFingerprint) != 0 {
|
clientFingerprint := c.ClientFingerprint
|
||||||
if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists {
|
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)
|
utlsConn := tlsC.UClient(conn, config, fingerprint)
|
||||||
if err = utlsConn.BuildWebsocketHandshakeState(); err != nil {
|
if err = utlsConn.BuildWebsocketHandshakeState(); 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user