chore: simplify gun code

This commit is contained in:
wwqgtxx
2026-02-23 19:54:25 +08:00
parent 3752cb044f
commit 43509da1a9
6 changed files with 76 additions and 119 deletions

View File

@@ -27,7 +27,7 @@ type Trojan struct {
hexPassword [trojan.KeyLength]byte hexPassword [trojan.KeyLength]byte
// for gun mux // for gun mux
gunTLSConfig *tls.Config gunTLSConfig *vmess.TLSConfig
gunConfig *gun.Config gunConfig *gun.Config
transport *gun.TransportWrap 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) c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts)
case "grpc": 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:
// default tcp network // default tcp network
// handle TLS // handle TLS
@@ -336,29 +336,25 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
return c, nil return c, nil
} }
tlsConfig, err := ca.GetTLSConfig(ca.Option{ tlsConfig := &vmess.TLSConfig{
TLSConfig: &tls.Config{ Host: option.SNI,
NextProtos: option.ALPN, SkipCertVerify: option.SkipCertVerify,
MinVersion: tls.VersionTLS12, FingerPrint: option.Fingerprint,
InsecureSkipVerify: option.SkipCertVerify, Certificate: option.Certificate,
ServerName: option.SNI, PrivateKey: option.PrivateKey,
}, ClientFingerprint: option.ClientFingerprint,
Fingerprint: option.Fingerprint, NextProtos: []string{"h2"},
Certificate: option.Certificate, ECH: t.echConfig,
PrivateKey: option.PrivateKey, Reality: t.realityConfig,
})
if err != nil {
return nil, err
} }
t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, option.ClientFingerprint, t.echConfig, t.realityConfig) t.transport = gun.NewHTTP2Client(dialFn, tlsConfig)
t.gunTLSConfig = tlsConfig t.gunTLSConfig = tlsConfig
t.gunConfig = &gun.Config{ t.gunConfig = &gun.Config{
ServiceName: option.GrpcOpts.GrpcServiceName, ServiceName: option.GrpcOpts.GrpcServiceName,
UserAgent: option.GrpcOpts.GrpcUserAgent, UserAgent: option.GrpcOpts.GrpcUserAgent,
Host: option.SNI, Host: option.SNI,
ClientFingerprint: option.ClientFingerprint,
} }
} }

View File

@@ -33,7 +33,7 @@ type Vless struct {
encryption *encryption.ClientInstance encryption *encryption.ClientInstance
// for gun mux // for gun mux
gunTLSConfig *tls.Config gunTLSConfig *vmess.TLSConfig
gunConfig *gun.Config gunConfig *gun.Config
transport *gun.TransportWrap 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) c, err = vmess.StreamH2Conn(ctx, c, h2Opts)
case "grpc": 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:
// default tcp network // default tcp network
// handle TLS // handle TLS
@@ -461,38 +461,36 @@ func NewVless(option VlessOption) (*Vless, error) {
} }
gunConfig := &gun.Config{ gunConfig := &gun.Config{
ServiceName: v.option.GrpcOpts.GrpcServiceName, ServiceName: option.GrpcOpts.GrpcServiceName,
UserAgent: v.option.GrpcOpts.GrpcUserAgent, UserAgent: option.GrpcOpts.GrpcUserAgent,
Host: v.option.ServerName, Host: option.ServerName,
ClientFingerprint: v.option.ClientFingerprint,
} }
if option.ServerName == "" { if option.ServerName == "" {
gunConfig.Host = v.addr gunConfig.Host = v.addr
} }
var tlsConfig *tls.Config var tlsConfig *vmess.TLSConfig
if option.TLS { if option.TLS {
tlsConfig, err = ca.GetTLSConfig(ca.Option{ tlsConfig = &vmess.TLSConfig{
TLSConfig: &tls.Config{ Host: option.ServerName,
InsecureSkipVerify: v.option.SkipCertVerify, SkipCertVerify: option.SkipCertVerify,
ServerName: v.option.ServerName, FingerPrint: option.Fingerprint,
}, Certificate: option.Certificate,
Fingerprint: v.option.Fingerprint, PrivateKey: option.PrivateKey,
Certificate: v.option.Certificate, ClientFingerprint: option.ClientFingerprint,
PrivateKey: v.option.PrivateKey, NextProtos: []string{"h2"},
}) ECH: v.echConfig,
if err != nil { Reality: v.realityConfig,
return nil, err
} }
if option.ServerName == "" { if option.ServerName == "" {
host, _, _ := net.SplitHostPort(v.addr) host, _, _ := net.SplitHostPort(v.addr)
tlsConfig.ServerName = host tlsConfig.Host = host
} }
} }
v.gunTLSConfig = tlsConfig v.gunTLSConfig = tlsConfig
v.gunConfig = gunConfig 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 return v, nil

View File

@@ -34,7 +34,7 @@ type Vmess struct {
option *VmessOption option *VmessOption
// for gun mux // for gun mux
gunTLSConfig *tls.Config gunTLSConfig *mihomoVMess.TLSConfig
gunConfig *gun.Config gunConfig *gun.Config
transport *gun.TransportWrap 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) c, err = mihomoVMess.StreamH2Conn(ctx, c, h2Opts)
case "grpc": 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:
// handle TLS // handle TLS
if v.option.TLS { if v.option.TLS {
@@ -467,38 +467,36 @@ func NewVmess(option VmessOption) (*Vmess, error) {
} }
gunConfig := &gun.Config{ gunConfig := &gun.Config{
ServiceName: v.option.GrpcOpts.GrpcServiceName, ServiceName: option.GrpcOpts.GrpcServiceName,
UserAgent: v.option.GrpcOpts.GrpcUserAgent, UserAgent: option.GrpcOpts.GrpcUserAgent,
Host: v.option.ServerName, Host: option.ServerName,
ClientFingerprint: v.option.ClientFingerprint,
} }
if option.ServerName == "" { if option.ServerName == "" {
gunConfig.Host = v.addr gunConfig.Host = v.addr
} }
var tlsConfig *tls.Config var tlsConfig *mihomoVMess.TLSConfig
if option.TLS { if option.TLS {
tlsConfig, err = ca.GetTLSConfig(ca.Option{ tlsConfig = &mihomoVMess.TLSConfig{
TLSConfig: &tls.Config{ Host: option.ServerName,
InsecureSkipVerify: v.option.SkipCertVerify, SkipCertVerify: option.SkipCertVerify,
ServerName: v.option.ServerName, FingerPrint: option.Fingerprint,
}, Certificate: option.Certificate,
Fingerprint: v.option.Fingerprint, PrivateKey: option.PrivateKey,
Certificate: v.option.Certificate, ClientFingerprint: option.ClientFingerprint,
PrivateKey: v.option.PrivateKey, NextProtos: []string{"h2"},
}) ECH: v.echConfig,
if err != nil { Reality: v.realityConfig,
return nil, err
} }
if option.ServerName == "" { if option.ServerName == "" {
host, _, _ := net.SplitHostPort(v.addr) host, _, _ := net.SplitHostPort(v.addr)
tlsConfig.ServerName = host tlsConfig.Host = host
} }
} }
v.gunTLSConfig = tlsConfig v.gunTLSConfig = tlsConfig
v.gunConfig = gunConfig 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 return v, nil

View File

@@ -135,6 +135,8 @@ func UEncryptedClientHelloKey(it tls.EncryptedClientHelloKey) utls.EncryptedClie
} }
} }
type ConnectionState = utls.ConnectionState
type Config = utls.Config type Config = utls.Config
var tlsCertificateRequestInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.CertificateRequestInfo)(nil)).Elem().FieldByName("ctx")).Offset var tlsCertificateRequestInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.CertificateRequestInfo)(nil)).Elem().FieldByName("ctx")).Offset

View File

@@ -18,9 +18,9 @@ import (
"github.com/metacubex/mihomo/common/buf" "github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/common/pool" "github.com/metacubex/mihomo/common/pool"
"github.com/metacubex/mihomo/component/ech"
tlsC "github.com/metacubex/mihomo/component/tls" tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant" C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/vmess"
"github.com/metacubex/http" "github.com/metacubex/http"
"github.com/metacubex/http/httptrace" "github.com/metacubex/http/httptrace"
@@ -59,10 +59,9 @@ type Conn struct {
} }
type Config struct { type Config struct {
ServiceName string ServiceName string
UserAgent string UserAgent string
Host string Host string
ClientFingerprint string
} }
func (g *Conn) initReader() { func (g *Conn) initReader() {
@@ -247,7 +246,7 @@ func (g *Conn) SetDeadline(t time.Time) error {
return nil 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) { 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()
@@ -260,65 +259,33 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri
return pconn, nil return pconn, nil
} }
if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok { conn, err := vmess.StreamTLSConn(ctx, pconn, tlsConfig)
if realityConfig == nil { if err != nil {
tlsConfig := tlsC.UConfig(cfg) _ = pconn.Close()
err := echConfig.ClientHandleUTLS(ctx, tlsConfig) return nil, err
if err != nil { }
pconn.Close()
return nil, err if tlsConfig.Reality == nil { // reality doesn't return the negotiated ALPN
} switch tlsConn := conn.(type) {
tlsConn := tlsC.UClient(pconn, tlsConfig, clientFingerprint) case interface{ ConnectionState() tls.ConnectionState }:
if err := tlsConn.HandshakeContext(ctx); err != nil {
pconn.Close()
return nil, err
}
state := tlsConn.ConnectionState() state := tlsConn.ConnectionState()
if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { 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 nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS)
} }
return tlsConn, nil case interface{ ConnectionState() tlsC.ConnectionState }:
} else { state := tlsConn.ConnectionState()
realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg.ServerName, realityConfig) if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS {
if err != nil { _ = conn.Close()
pconn.Close() return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS)
return nil, err
} }
//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 return conn, nil
} }
transport := &http.Http2Transport{ transport := &http.Http2Transport{
DialTLSContext: dialFunc, DialTLSContext: dialFunc,
TLSClientConfig: tlsConfig,
AllowHTTP: false, AllowHTTP: false,
DisableCompression: true, DisableCompression: true,
PingTimeout: 0, PingTimeout: 0,
@@ -394,12 +361,12 @@ 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, 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) { dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) {
return conn, nil return conn, nil
} }
transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, echConfig, realityConfig) transport := NewHTTP2Client(dialFn, tlsConfig)
c, err := StreamGunWithTransport(transport, cfg) c, err := StreamGunWithTransport(transport, cfg)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -24,10 +24,6 @@ type TLSConfig struct {
Reality *tlsC.RealityConfig Reality *tlsC.RealityConfig
} }
type ECHConfig struct {
Enable bool
}
func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) { func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
tlsConfig, err := ca.GetTLSConfig(ca.Option{ tlsConfig, err := ca.GetTLSConfig(ca.Option{
TLSConfig: &tls.Config{ TLSConfig: &tls.Config{