diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index b868eb8d..93ef7d96 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -27,7 +27,7 @@ type Trojan struct { hexPassword [trojan.KeyLength]byte // for gun mux - gunTLSConfig *tls.Config + gunTLSConfig *vmess.TLSConfig gunConfig *gun.Config transport *gun.TransportWrap @@ -118,7 +118,7 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C. c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts) case "grpc": - c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig, t.echConfig, t.realityConfig) + c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig) default: // default tcp network // handle TLS @@ -336,29 +336,25 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { return c, nil } - tlsConfig, err := ca.GetTLSConfig(ca.Option{ - TLSConfig: &tls.Config{ - NextProtos: option.ALPN, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: option.SkipCertVerify, - ServerName: option.SNI, - }, - Fingerprint: option.Fingerprint, - Certificate: option.Certificate, - PrivateKey: option.PrivateKey, - }) - if err != nil { - return nil, err + tlsConfig := &vmess.TLSConfig{ + Host: option.SNI, + SkipCertVerify: option.SkipCertVerify, + FingerPrint: option.Fingerprint, + Certificate: option.Certificate, + PrivateKey: option.PrivateKey, + ClientFingerprint: option.ClientFingerprint, + NextProtos: []string{"h2"}, + ECH: t.echConfig, + Reality: t.realityConfig, } - t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, option.ClientFingerprint, t.echConfig, t.realityConfig) + t.transport = gun.NewHTTP2Client(dialFn, tlsConfig) t.gunTLSConfig = tlsConfig t.gunConfig = &gun.Config{ - ServiceName: option.GrpcOpts.GrpcServiceName, - UserAgent: option.GrpcOpts.GrpcUserAgent, - Host: option.SNI, - ClientFingerprint: option.ClientFingerprint, + ServiceName: option.GrpcOpts.GrpcServiceName, + UserAgent: option.GrpcOpts.GrpcUserAgent, + Host: option.SNI, } } diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 603d433e..db316482 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -33,7 +33,7 @@ type Vless struct { encryption *encryption.ClientInstance // for gun mux - gunTLSConfig *tls.Config + gunTLSConfig *vmess.TLSConfig gunConfig *gun.Config transport *gun.TransportWrap @@ -151,7 +151,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c, err = vmess.StreamH2Conn(ctx, c, h2Opts) case "grpc": - c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.echConfig, v.realityConfig) + c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) default: // default tcp network // handle TLS @@ -461,38 +461,36 @@ func NewVless(option VlessOption) (*Vless, error) { } gunConfig := &gun.Config{ - ServiceName: v.option.GrpcOpts.GrpcServiceName, - UserAgent: v.option.GrpcOpts.GrpcUserAgent, - Host: v.option.ServerName, - ClientFingerprint: v.option.ClientFingerprint, + ServiceName: option.GrpcOpts.GrpcServiceName, + UserAgent: option.GrpcOpts.GrpcUserAgent, + Host: option.ServerName, } if option.ServerName == "" { gunConfig.Host = v.addr } - var tlsConfig *tls.Config + var tlsConfig *vmess.TLSConfig if option.TLS { - tlsConfig, err = ca.GetTLSConfig(ca.Option{ - TLSConfig: &tls.Config{ - InsecureSkipVerify: v.option.SkipCertVerify, - ServerName: v.option.ServerName, - }, - Fingerprint: v.option.Fingerprint, - Certificate: v.option.Certificate, - PrivateKey: v.option.PrivateKey, - }) - if err != nil { - return nil, err + tlsConfig = &vmess.TLSConfig{ + Host: option.ServerName, + SkipCertVerify: option.SkipCertVerify, + FingerPrint: option.Fingerprint, + Certificate: option.Certificate, + PrivateKey: option.PrivateKey, + ClientFingerprint: option.ClientFingerprint, + NextProtos: []string{"h2"}, + ECH: v.echConfig, + Reality: v.realityConfig, } if option.ServerName == "" { host, _, _ := net.SplitHostPort(v.addr) - tlsConfig.ServerName = host + tlsConfig.Host = host } } v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.echConfig, v.realityConfig) + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig) } return v, nil diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index c9656bd9..5093752e 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -34,7 +34,7 @@ type Vmess struct { option *VmessOption // for gun mux - gunTLSConfig *tls.Config + gunTLSConfig *mihomoVMess.TLSConfig gunConfig *gun.Config transport *gun.TransportWrap @@ -205,7 +205,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c, err = mihomoVMess.StreamH2Conn(ctx, c, h2Opts) case "grpc": - c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.echConfig, v.realityConfig) + c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) default: // handle TLS if v.option.TLS { @@ -467,38 +467,36 @@ func NewVmess(option VmessOption) (*Vmess, error) { } gunConfig := &gun.Config{ - ServiceName: v.option.GrpcOpts.GrpcServiceName, - UserAgent: v.option.GrpcOpts.GrpcUserAgent, - Host: v.option.ServerName, - ClientFingerprint: v.option.ClientFingerprint, + ServiceName: option.GrpcOpts.GrpcServiceName, + UserAgent: option.GrpcOpts.GrpcUserAgent, + Host: option.ServerName, } if option.ServerName == "" { gunConfig.Host = v.addr } - var tlsConfig *tls.Config + var tlsConfig *mihomoVMess.TLSConfig if option.TLS { - tlsConfig, err = ca.GetTLSConfig(ca.Option{ - TLSConfig: &tls.Config{ - InsecureSkipVerify: v.option.SkipCertVerify, - ServerName: v.option.ServerName, - }, - Fingerprint: v.option.Fingerprint, - Certificate: v.option.Certificate, - PrivateKey: v.option.PrivateKey, - }) - if err != nil { - return nil, err + tlsConfig = &mihomoVMess.TLSConfig{ + Host: option.ServerName, + SkipCertVerify: option.SkipCertVerify, + FingerPrint: option.Fingerprint, + Certificate: option.Certificate, + PrivateKey: option.PrivateKey, + ClientFingerprint: option.ClientFingerprint, + NextProtos: []string{"h2"}, + ECH: v.echConfig, + Reality: v.realityConfig, } if option.ServerName == "" { host, _, _ := net.SplitHostPort(v.addr) - tlsConfig.ServerName = host + tlsConfig.Host = host } } v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.echConfig, v.realityConfig) + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig) } return v, nil diff --git a/component/tls/utls.go b/component/tls/utls.go index 7262cb8b..62c8b7e2 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -135,6 +135,8 @@ func UEncryptedClientHelloKey(it tls.EncryptedClientHelloKey) utls.EncryptedClie } } +type ConnectionState = utls.ConnectionState + type Config = utls.Config var tlsCertificateRequestInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.CertificateRequestInfo)(nil)).Elem().FieldByName("ctx")).Offset diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 4d924530..aeddab2d 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -18,9 +18,9 @@ import ( "github.com/metacubex/mihomo/common/buf" "github.com/metacubex/mihomo/common/pool" - "github.com/metacubex/mihomo/component/ech" tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/vmess" "github.com/metacubex/http" "github.com/metacubex/http/httptrace" @@ -59,10 +59,9 @@ type Conn struct { } type Config struct { - ServiceName string - UserAgent string - Host string - ClientFingerprint string + ServiceName string + UserAgent string + Host string } func (g *Conn) initReader() { @@ -247,7 +246,7 @@ func (g *Conn) SetDeadline(t time.Time) error { return nil } -func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint string, echConfig *ech.Config, realityConfig *tlsC.RealityConfig) *TransportWrap { +func NewHTTP2Client(dialFn DialFn, tlsConfig *vmess.TLSConfig) *TransportWrap { dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout) defer cancel() @@ -260,65 +259,33 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri return pconn, nil } - if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok { - if realityConfig == nil { - tlsConfig := tlsC.UConfig(cfg) - err := echConfig.ClientHandleUTLS(ctx, tlsConfig) - if err != nil { - pconn.Close() - return nil, err - } - tlsConn := tlsC.UClient(pconn, tlsConfig, clientFingerprint) - if err := tlsConn.HandshakeContext(ctx); err != nil { - pconn.Close() - return nil, err - } + conn, err := vmess.StreamTLSConn(ctx, pconn, tlsConfig) + if err != nil { + _ = pconn.Close() + return nil, err + } + + if tlsConfig.Reality == nil { // reality doesn't return the negotiated ALPN + switch tlsConn := conn.(type) { + case interface{ ConnectionState() tls.ConnectionState }: state := tlsConn.ConnectionState() if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { - tlsConn.Close() + _ = conn.Close() return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS) } - return tlsConn, nil - } else { - realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg.ServerName, realityConfig) - if err != nil { - pconn.Close() - return nil, err + case interface{ ConnectionState() tlsC.ConnectionState }: + state := tlsConn.ConnectionState() + if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { + _ = conn.Close() + return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS) } - //state := realityConn.(*utls.UConn).ConnectionState() - //if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { - // realityConn.Close() - // return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS) - //} - return realityConn, nil } } - if realityConfig != nil { - return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") - } - - err = echConfig.ClientHandle(ctx, cfg) - if err != nil { - pconn.Close() - return nil, err - } - - conn := tls.Client(pconn, cfg) - if err := conn.HandshakeContext(ctx); err != nil { - pconn.Close() - return nil, err - } - state := conn.ConnectionState() - if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { - conn.Close() - return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS) - } return conn, nil } transport := &http.Http2Transport{ DialTLSContext: dialFunc, - TLSClientConfig: tlsConfig, AllowHTTP: false, DisableCompression: true, PingTimeout: 0, @@ -394,12 +361,12 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er return conn, nil } -func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, echConfig *ech.Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) { +func StreamGunWithConn(conn net.Conn, tlsConfig *vmess.TLSConfig, cfg *Config) (net.Conn, error) { dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) { return conn, nil } - transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, echConfig, realityConfig) + transport := NewHTTP2Client(dialFn, tlsConfig) c, err := StreamGunWithTransport(transport, cfg) if err != nil { return nil, err diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 9523910f..ff915b37 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -24,10 +24,6 @@ type TLSConfig struct { Reality *tlsC.RealityConfig } -type ECHConfig struct { - Enable bool -} - func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) { tlsConfig, err := ca.GetTLSConfig(ca.Option{ TLSConfig: &tls.Config{