fix: REALITY with gRPC transport

This commit is contained in:
H1JK 2023-03-10 10:01:05 +08:00
parent c0fc5d142f
commit dca98b7aa1
4 changed files with 50 additions and 29 deletions

View File

@ -26,6 +26,8 @@ type Trojan struct {
gunTLSConfig *tls.Config gunTLSConfig *tls.Config
gunConfig *gun.Config gunConfig *gun.Config
transport *gun.TransportWrap transport *gun.TransportWrap
realityConfig *tlsC.RealityConfig
} }
type TrojanOption struct { type TrojanOption struct {
@ -84,7 +86,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
} }
if t.transport != nil { 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 { } else {
c, err = t.plainStream(c) c, err = t.plainStream(c)
} }
@ -245,12 +247,6 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
tOption.ServerName = option.SNI tOption.ServerName = option.SNI
} }
var err error
tOption.Reality, err = option.RealityOpts.Parse()
if err != nil {
return nil, err
}
t := &Trojan{ t := &Trojan{
Base: &Base{ Base: &Base{
name: option.Name, name: option.Name,
@ -266,6 +262,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
option: &option, 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" { if option.Network == "grpc" {
dialFn := func(network, addr string) (net.Conn, error) { dialFn := func(network, addr string) (net.Conn, error) {
c, err := dialer.DialContext(context.Background(), "tcp", t.addr, t.Base.DialOptions()...) 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.gunTLSConfig = tlsConfig
t.gunConfig = &gun.Config{ t.gunConfig = &gun.Config{

View File

@ -156,7 +156,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
c, err = vmess.StreamH2Conn(c, h2Opts) c, err = vmess.StreamH2Conn(c, h2Opts)
case "grpc": case "grpc":
c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig)
default: default:
// default tcp network // default tcp network
// handle TLS And XTLS // handle TLS And XTLS
@ -522,6 +522,11 @@ func NewVless(option VlessOption) (*Vless, error) {
option: &option, option: &option,
} }
v.realityConfig, err = v.option.RealityOpts.Parse()
if err != nil {
return nil, err
}
switch option.Network { switch option.Network {
case "h2": case "h2":
if len(option.HTTP2Opts.Host) == 0 { if len(option.HTTP2Opts.Host) == 0 {
@ -556,12 +561,7 @@ func NewVless(option VlessOption) (*Vless, error) {
v.gunTLSConfig = tlsConfig v.gunTLSConfig = tlsConfig
v.gunConfig = gunConfig 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()
if err != nil {
return nil, err
} }
return v, nil return v, nil

View File

@ -193,7 +193,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
c, err = clashVMess.StreamH2Conn(c, h2Opts) c, err = clashVMess.StreamH2Conn(c, h2Opts)
case "grpc": case "grpc":
c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig)
default: default:
// handle TLS // handle TLS
if v.option.TLS { if v.option.TLS {
@ -455,7 +455,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
v.gunTLSConfig = tlsConfig v.gunTLSConfig = tlsConfig
v.gunConfig = gunConfig 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() v.realityConfig, err = v.option.RealityOpts.Parse()

View File

@ -20,6 +20,7 @@ import (
"github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/buf"
"github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/pool"
tlsC "github.com/Dreamacro/clash/component/tls" tlsC "github.com/Dreamacro/clash/component/tls"
"go.uber.org/atomic" "go.uber.org/atomic"
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
@ -189,7 +190,7 @@ func (g *Conn) SetDeadline(t time.Time) error {
return nil 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{} wrap := 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) {
@ -201,20 +202,37 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *T
wrap.remoteAddr = pconn.RemoteAddr() wrap.remoteAddr = pconn.RemoteAddr()
if len(Fingerprint) != 0 { if len(Fingerprint) != 0 {
if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { if realityConfig == nil {
utlsConn := tlsC.UClient(pconn, cfg, fingerprint) if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists {
if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { 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() pconn.Close()
return nil, err return nil, err
} }
state := utlsConn.(*tlsC.UConn).ConnectionState() //state := realityConn.(*utls.UConn).ConnectionState()
if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { //if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
utlsConn.Close() // realityConn.Close()
return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) // return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS)
} //}
return utlsConn, nil 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) conn := tls.Client(pconn, cfg)
if err := conn.HandshakeContext(ctx); err != nil { if err := conn.HandshakeContext(ctx); err != nil {
@ -274,11 +292,11 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er
return conn, nil 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) { dialFn := func(network, addr string) (net.Conn, error) {
return conn, nil return conn, nil
} }
transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint) transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, realityConfig)
return StreamGunWithTransport(transport, cfg) return StreamGunWithTransport(transport, cfg)
} }