From dca98b7aa1b73b5b5c33b6db89266ce0dbd7b5ad Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 10 Mar 2023 10:01:05 +0800 Subject: [PATCH] fix: REALITY with gRPC transport --- adapter/outbound/trojan.go | 19 +++++++++-------- adapter/outbound/vless.go | 14 ++++++------- adapter/outbound/vmess.go | 4 ++-- transport/gun/gun.go | 42 +++++++++++++++++++++++++++----------- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index d36bd40ce..030e74a99 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -26,6 +26,8 @@ type Trojan struct { gunTLSConfig *tls.Config gunConfig *gun.Config transport *gun.TransportWrap + + realityConfig *tlsC.RealityConfig } type TrojanOption struct { @@ -84,7 +86,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) } if t.transport != nil { - c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig) + c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig, t.realityConfig) } else { c, err = t.plainStream(c) } @@ -245,12 +247,6 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { tOption.ServerName = option.SNI } - var err error - tOption.Reality, err = option.RealityOpts.Parse() - if err != nil { - return nil, err - } - t := &Trojan{ Base: &Base{ name: option.Name, @@ -266,6 +262,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { option: &option, } + var err error + t.realityConfig, err = option.RealityOpts.Parse() + if err != nil { + return nil, err + } + tOption.Reality = t.realityConfig + if option.Network == "grpc" { dialFn := func(network, addr string) (net.Conn, error) { c, err := dialer.DialContext(context.Background(), "tcp", t.addr, t.Base.DialOptions()...) @@ -292,7 +295,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { } } - t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint) + t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint, t.realityConfig) t.gunTLSConfig = tlsConfig t.gunConfig = &gun.Config{ diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 435beee95..5dc52571d 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -156,7 +156,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { c, err = vmess.StreamH2Conn(c, h2Opts) case "grpc": - c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) + c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // default tcp network // handle TLS And XTLS @@ -522,6 +522,11 @@ func NewVless(option VlessOption) (*Vless, error) { option: &option, } + v.realityConfig, err = v.option.RealityOpts.Parse() + if err != nil { + return nil, err + } + switch option.Network { case "h2": if len(option.HTTP2Opts.Host) == 0 { @@ -556,12 +561,7 @@ func NewVless(option VlessOption) (*Vless, error) { v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) - } - - v.realityConfig, err = v.option.RealityOpts.Parse() - if err != nil { - return nil, err + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.realityConfig) } return v, nil diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index f9e7205bc..5bb46dadc 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -193,7 +193,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { c, err = clashVMess.StreamH2Conn(c, h2Opts) case "grpc": - c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) + c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // handle TLS if v.option.TLS { @@ -455,7 +455,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.realityConfig) } v.realityConfig, err = v.option.RealityOpts.Parse() diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 920e7adc3..8eafdc50c 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -20,6 +20,7 @@ import ( "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/pool" tlsC "github.com/Dreamacro/clash/component/tls" + "go.uber.org/atomic" "golang.org/x/net/http2" ) @@ -189,7 +190,7 @@ func (g *Conn) SetDeadline(t time.Time) error { return nil } -func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *TransportWrap { +func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap { wrap := TransportWrap{} dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { @@ -201,20 +202,37 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *T wrap.remoteAddr = pconn.RemoteAddr() if len(Fingerprint) != 0 { - if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { - utlsConn := tlsC.UClient(pconn, cfg, fingerprint) - if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { + if realityConfig == nil { + if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { + utlsConn := tlsC.UClient(pconn, cfg, fingerprint) + if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { + pconn.Close() + return nil, err + } + state := utlsConn.(*tlsC.UConn).ConnectionState() + if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + utlsConn.Close() + return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + } + return utlsConn, nil + } + } else { + realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, tlsConfig, realityConfig) + if err != nil { pconn.Close() return nil, err } - state := utlsConn.(*tlsC.UConn).ConnectionState() - if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { - utlsConn.Close() - return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) - } - return utlsConn, nil + //state := realityConn.(*utls.UConn).ConnectionState() + //if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + // realityConn.Close() + // return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + //} + return realityConn, nil } } + if realityConfig != nil { + return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") + } conn := tls.Client(pconn, cfg) if err := conn.HandshakeContext(ctx); err != nil { @@ -274,11 +292,11 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er return conn, nil } -func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config) (net.Conn, error) { +func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) { dialFn := func(network, addr string) (net.Conn, error) { return conn, nil } - transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint) + transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, realityConfig) return StreamGunWithTransport(transport, cfg) }