From 63e66f49ca87e7a78689dcf85764cf98fcc8845f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 18 Apr 2025 16:59:28 +0800 Subject: [PATCH] chore: cleanup trojan code --- adapter/outbound/trojan.go | 82 ++++++++++++++--------- transport/trojan/trojan.go | 129 ++----------------------------------- 2 files changed, 56 insertions(+), 155 deletions(-) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 241666e5..49bc6cd2 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -18,12 +18,13 @@ import ( "github.com/metacubex/mihomo/transport/gun" "github.com/metacubex/mihomo/transport/shadowsocks/core" "github.com/metacubex/mihomo/transport/trojan" + "github.com/metacubex/mihomo/transport/vmess" ) type Trojan struct { *Base - instance *trojan.Trojan - option *TrojanOption + option *TrojanOption + hexPassword [trojan.KeyLength]byte // for gun mux gunTLSConfig *tls.Config @@ -62,14 +63,20 @@ type TrojanSSOption struct { } func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) { + var err error + if t.option.Network == "ws" { host, port, _ := net.SplitHostPort(t.addr) - wsOpts := &trojan.WebsocketOption{ + + wsOpts := &vmess.WebsocketConfig{ Host: host, Port: port, Path: t.option.WSOpts.Path, + MaxEarlyData: t.option.WSOpts.MaxEarlyData, + EarlyDataHeaderName: t.option.WSOpts.EarlyDataHeaderName, V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade, V2rayHttpUpgradeFastOpen: t.option.WSOpts.V2rayHttpUpgradeFastOpen, + ClientFingerprint: t.option.ClientFingerprint, Headers: http.Header{}, } @@ -83,10 +90,39 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) } } - return t.instance.StreamWebsocketConn(ctx, c, wsOpts) + alpn := trojan.DefaultWebsocketALPN + if len(t.option.ALPN) != 0 { + alpn = t.option.ALPN + } + + wsOpts.TLS = true + tlsConfig := &tls.Config{ + NextProtos: alpn, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: t.option.SkipCertVerify, + ServerName: t.option.SNI, + } + + wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint) + if err != nil { + return nil, err + } + + return vmess.StreamWebsocketConn(ctx, c, wsOpts) } - return t.instance.StreamConn(ctx, c) + alpn := trojan.DefaultALPN + if len(t.option.ALPN) != 0 { + alpn = t.option.ALPN + } + return vmess.StreamTLSConn(ctx, c, &vmess.TLSConfig{ + Host: t.option.SNI, + SkipCertVerify: t.option.SkipCertVerify, + FingerPrint: t.option.Fingerprint, + ClientFingerprint: t.option.ClientFingerprint, + NextProtos: alpn, + Reality: t.realityConfig, + }) } // StreamConnContext implements C.ProxyAdapter @@ -124,7 +160,7 @@ func (t *Trojan) writeHeaderContext(ctx context.Context, c net.Conn, metadata *C if metadata.NetWork == C.UDP { command = trojan.CommandUDP } - err = t.instance.WriteHeader(c, command, serializesSocksAddr(metadata)) + err = trojan.WriteHeader(c, t.hexPassword, command, serializesSocksAddr(metadata)) return err } @@ -199,7 +235,7 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return nil, err } - pc := t.instance.PacketConn(c) + pc := trojan.NewPacketConn(c) return newPacketConn(pc, t), err } return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.Base.DialOptions(opts...)...), metadata) @@ -234,7 +270,7 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me return nil, err } - pc := t.instance.PacketConn(c) + pc := trojan.NewPacketConn(c) return newPacketConn(pc, t), err } @@ -245,7 +281,7 @@ func (t *Trojan) SupportWithDialer() C.NetWork { // ListenPacketOnStreamConn implements C.ProxyAdapter func (t *Trojan) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { - pc := t.instance.PacketConn(c) + pc := trojan.NewPacketConn(c) return newPacketConn(pc, t), err } @@ -272,19 +308,6 @@ func (t *Trojan) Close() error { func NewTrojan(option TrojanOption) (*Trojan, error) { addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) - tOption := &trojan.Option{ - Password: option.Password, - ALPN: option.ALPN, - ServerName: option.Server, - SkipCertVerify: option.SkipCertVerify, - Fingerprint: option.Fingerprint, - ClientFingerprint: option.ClientFingerprint, - } - - if option.SNI != "" { - tOption.ServerName = option.SNI - } - t := &Trojan{ Base: &Base{ name: option.Name, @@ -297,8 +320,8 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, - instance: trojan.New(tOption), - option: &option, + option: &option, + hexPassword: trojan.Key(option.Password), } var err error @@ -306,7 +329,6 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { if err != nil { return nil, err } - tOption.Reality = t.realityConfig if option.SSOpts.Enabled { if option.SSOpts.Password == "" { @@ -342,8 +364,8 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { tlsConfig := &tls.Config{ NextProtos: option.ALPN, MinVersion: tls.VersionTLS12, - InsecureSkipVerify: tOption.SkipCertVerify, - ServerName: tOption.ServerName, + InsecureSkipVerify: option.SkipCertVerify, + ServerName: option.SNI, } var err error @@ -352,13 +374,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { return nil, err } - t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint, t.realityConfig) + t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, option.ClientFingerprint, t.realityConfig) t.gunTLSConfig = tlsConfig t.gunConfig = &gun.Config{ ServiceName: option.GrpcOpts.GrpcServiceName, - Host: tOption.ServerName, - ClientFingerprint: tOption.ClientFingerprint, + Host: option.SNI, + ClientFingerprint: option.ClientFingerprint, } } diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index e5000502..93819130 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -1,24 +1,17 @@ package trojan import ( - "context" "crypto/sha256" - "crypto/tls" "encoding/binary" "encoding/hex" "errors" "io" "net" - "net/http" "sync" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/pool" - "github.com/metacubex/mihomo/component/ca" - tlsC "github.com/metacubex/mihomo/component/tls" - C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" - "github.com/metacubex/mihomo/transport/vmess" ) const ( @@ -27,8 +20,8 @@ const ( ) var ( - defaultALPN = []string{"h2", "http/1.1"} - defaultWebsocketALPN = []string{"http/1.1"} + DefaultALPN = []string{"h2", "http/1.1"} + DefaultWebsocketALPN = []string{"http/1.1"} crlf = []byte{'\r', '\n'} ) @@ -43,115 +36,11 @@ const ( KeyLength = 56 ) -type Option struct { - Password string - ALPN []string - ServerName string - SkipCertVerify bool - Fingerprint string - ClientFingerprint string - Reality *tlsC.RealityConfig -} - -type WebsocketOption struct { - Host string - Port string - Path string - Headers http.Header - V2rayHttpUpgrade bool - V2rayHttpUpgradeFastOpen bool -} - -type Trojan struct { - option *Option - hexPassword [KeyLength]byte -} - -func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error) { - alpn := defaultALPN - if len(t.option.ALPN) != 0 { - alpn = t.option.ALPN - } - tlsConfig := &tls.Config{ - NextProtos: alpn, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: t.option.SkipCertVerify, - ServerName: t.option.ServerName, - } - - var err error - tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint) - if err != nil { - return nil, err - } - - if len(t.option.ClientFingerprint) != 0 { - if t.option.Reality == nil { - utlsConn, valid := vmess.GetUTLSConn(conn, t.option.ClientFingerprint, tlsConfig) - if valid { - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - - err := utlsConn.HandshakeContext(ctx) - return utlsConn, err - } - } else { - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - return tlsC.GetRealityConn(ctx, conn, t.option.ClientFingerprint, tlsConfig, t.option.Reality) - } - } - if t.option.Reality != nil { - return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") - } - - tlsConn := tls.Client(conn, tlsConfig) - - // fix tls handshake not timeout - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - - err = tlsConn.HandshakeContext(ctx) - return tlsConn, err -} - -func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) { - alpn := defaultWebsocketALPN - if len(t.option.ALPN) != 0 { - alpn = t.option.ALPN - } - - tlsConfig := &tls.Config{ - NextProtos: alpn, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: t.option.SkipCertVerify, - ServerName: t.option.ServerName, - } - - var err error - tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint) - if err != nil { - return nil, err - } - - return vmess.StreamWebsocketConn(ctx, conn, &vmess.WebsocketConfig{ - Host: wsOptions.Host, - Port: wsOptions.Port, - Path: wsOptions.Path, - Headers: wsOptions.Headers, - V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade, - V2rayHttpUpgradeFastOpen: wsOptions.V2rayHttpUpgradeFastOpen, - TLS: true, - TLSConfig: tlsConfig, - ClientFingerprint: t.option.ClientFingerprint, - }) -} - -func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error { +func WriteHeader(w io.Writer, hexPassword [KeyLength]byte, command Command, socks5Addr []byte) error { buf := pool.GetBuffer() defer pool.PutBuffer(buf) - buf.Write(t.hexPassword[:]) + buf.Write(hexPassword[:]) buf.Write(crlf) buf.WriteByte(command) @@ -162,12 +51,6 @@ func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) er return err } -func (t *Trojan) PacketConn(conn net.Conn) net.PacketConn { - return &PacketConn{ - Conn: conn, - } -} - func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) { buf := pool.GetBuffer() defer pool.PutBuffer(buf) @@ -243,10 +126,6 @@ func ReadPacket(r io.Reader, payload []byte) (net.Addr, int, int, error) { return uAddr, length, total - length, nil } -func New(option *Option) *Trojan { - return &Trojan{option, Key(option.Password)} -} - var _ N.EnhancePacketConn = (*PacketConn)(nil) type PacketConn struct {