From a82745f544f38b624dd19135fec8f69d52219c23 Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:26:07 +0800 Subject: [PATCH] chore: Remove legacy XTLS support (#645) * chore: Remove legacy XTLS support * chore: Rename function --- adapter/outbound/trojan.go | 28 -------- adapter/outbound/util.go | 13 +--- adapter/outbound/vless.go | 38 +++------- component/tls/config.go | 26 ------- go.mod | 1 - go.sum | 2 - transport/trojan/trojan.go | 141 ++++++++++--------------------------- transport/vless/conn.go | 21 ------ transport/vless/vless.go | 12 ++-- transport/vless/xtls.go | 37 ---------- 10 files changed, 55 insertions(+), 264 deletions(-) delete mode 100644 transport/vless/xtls.go diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 81fb1ceb..3af71b7d 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -14,7 +14,6 @@ import ( C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/trojan" - "github.com/Dreamacro/clash/transport/vless" ) type Trojan struct { @@ -45,8 +44,6 @@ type TrojanOption struct { RealityOpts RealityOptions `proxy:"reality-opts,omitempty"` GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` WSOpts WSOptions `proxy:"ws-opts,omitempty"` - Flow string `proxy:"flow,omitempty"` - FlowShow bool `proxy:"flow-show,omitempty"` ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } @@ -95,11 +92,6 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C. return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } - c, err = t.instance.PresetXTLSConn(c) - if err != nil { - return nil, err - } - if metadata.NetWork == C.UDP { err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) return c, err @@ -117,12 +109,6 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ... return nil, err } - c, err = t.instance.PresetXTLSConn(c) - if err != nil { - c.Close() - return nil, err - } - if err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)); err != nil { c.Close() return nil, err @@ -237,24 +223,10 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { ALPN: option.ALPN, ServerName: option.Server, SkipCertVerify: option.SkipCertVerify, - FlowShow: option.FlowShow, Fingerprint: option.Fingerprint, ClientFingerprint: option.ClientFingerprint, } - switch option.Network { - case "", "tcp": - if len(option.Flow) >= 16 { - option.Flow = option.Flow[:16] - switch option.Flow { - case vless.XRO, vless.XRD, vless.XRS: - tOption.Flow = option.Flow - default: - return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow) - } - } - } - if option.SNI != "" { tOption.ServerName = option.SNI } diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 68d6b355..0504d005 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "crypto/tls" - xtls "github.com/xtls/go" "net" "net/netip" "strconv" @@ -17,9 +16,8 @@ import ( ) var ( - globalClientSessionCache tls.ClientSessionCache - globalClientXSessionCache xtls.ClientSessionCache - once sync.Once + globalClientSessionCache tls.ClientSessionCache + once sync.Once ) func tcpKeepAlive(c net.Conn) { @@ -36,13 +34,6 @@ func getClientSessionCache() tls.ClientSessionCache { return globalClientSessionCache } -func getClientXSessionCache() xtls.ClientSessionCache { - once.Do(func() { - globalClientXSessionCache = xtls.NewLRUClientSessionCache(128) - }) - return globalClientXSessionCache -} - func serializesSocksAddr(metadata *C.Metadata) []byte { var buf [][]byte addrType := metadata.AddrType() diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 803e0f57..6423eb29 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -56,7 +56,6 @@ type VlessOption struct { Port int `proxy:"port"` UUID string `proxy:"uuid"` Flow string `proxy:"flow,omitempty"` - FlowShow bool `proxy:"flow-show,omitempty"` TLS bool `proxy:"tls,omitempty"` UDP bool `proxy:"udp,omitempty"` PacketAddr bool `proxy:"packet-addr,omitempty"` @@ -133,7 +132,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic - c, err = v.streamTLSOrXTLSConn(ctx, c, false) + c, err = v.streamTLSConn(ctx, c, false) if err != nil { return nil, err } @@ -148,7 +147,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c = vmess.StreamHTTPConn(c, httpOpts) case "h2": - c, err = v.streamTLSOrXTLSConn(ctx, c, true) + c, err = v.streamTLSConn(ctx, c, true) if err != nil { return nil, err } @@ -163,8 +162,8 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // default tcp network - // handle TLS And XTLS - c, err = v.streamTLSOrXTLSConn(ctx, c, false) + // handle TLS + c, err = v.streamTLSConn(ctx, c, false) } if err != nil { @@ -202,23 +201,10 @@ func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err return } -func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { - host, _, _ := net.SplitHostPort(v.addr) +func (v *Vless) streamTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { + if v.option.TLS { + host, _, _ := net.SplitHostPort(v.addr) - if v.isLegacyXTLSEnabled() && !isH2 { - xtlsOpts := vless.XTLSConfig{ - Host: host, - SkipCertVerify: v.option.SkipCertVerify, - Fingerprint: v.option.Fingerprint, - } - - if v.option.ServerName != "" { - xtlsOpts.Host = v.option.ServerName - } - - return vless.StreamXTLSConn(ctx, conn, &xtlsOpts) - - } else if v.option.TLS { tlsOpts := vmess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, @@ -241,10 +227,6 @@ func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 boo return conn, nil } -func (v *Vless) isLegacyXTLSEnabled() bool { - return v.client.Addons != nil && v.client.Addons.Flow != vless.XRV -} - // DialContext implements C.ProxyAdapter func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { // gun transport @@ -526,11 +508,11 @@ func NewVless(option VlessOption) (*Vless, error) { switch option.Flow { case vless.XRV: log.Warnln("To use %s, ensure your server is upgrade to Xray-core v1.8.0+", vless.XRV) - fallthrough - case vless.XRO, vless.XRD, vless.XRS: addons = &vless.Addons{ Flow: option.Flow, } + case vless.XRO, vless.XRD, vless.XRS: + log.Fatalln("Legacy XTLS protocol %s is deprecated and no longer supported", option.Flow) default: return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow) } @@ -549,7 +531,7 @@ func NewVless(option VlessOption) (*Vless, error) { option.PacketAddr = false } - client, err := vless.NewClient(option.UUID, addons, option.FlowShow) + client, err := vless.NewClient(option.UUID, addons) if err != nil { return nil, err } diff --git a/component/tls/config.go b/component/tls/config.go index 2896a1be..d7382f7c 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -10,8 +10,6 @@ import ( "fmt" "strings" "sync" - - xtls "github.com/xtls/go" ) var trustCerts []*x509.Certificate @@ -122,27 +120,3 @@ func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { tlsConfig.RootCAs = certPool return tlsConfig } - -// GetSpecifiedFingerprintXTLSConfig specified fingerprint -func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint string) (*xtls.Config, error) { - if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil { - return nil, err - } else { - tlsConfig = GetGlobalXTLSConfig(tlsConfig) - tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) - tlsConfig.InsecureSkipVerify = true - return tlsConfig, nil - } -} - -func GetGlobalXTLSConfig(tlsConfig *xtls.Config) *xtls.Config { - certPool := getCertPool() - if tlsConfig == nil { - return &xtls.Config{ - RootCAs: certPool, - } - } - - tlsConfig.RootCAs = certPool - return tlsConfig -} diff --git a/go.mod b/go.mod index bb6115ba..06e522c0 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,6 @@ require ( github.com/shirou/gopsutil/v3 v3.23.6 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 - github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 diff --git a/go.sum b/go.sum index 77508629..4f5a5aab 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,6 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= -github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index abe21f34..710905ad 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -7,7 +7,6 @@ import ( "encoding/binary" "encoding/hex" "errors" - "fmt" "io" "net" "net/http" @@ -18,10 +17,7 @@ import ( tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/vless" "github.com/Dreamacro/clash/transport/vmess" - - xtls "github.com/xtls/go" ) const ( @@ -42,7 +38,7 @@ const ( CommandTCP byte = 1 CommandUDP byte = 3 - // for XTLS + // deprecated XTLS commands, as souvenirs commandXRD byte = 0xf0 // XTLS direct mode commandXRO byte = 0xf1 // XTLS origin mode ) @@ -53,8 +49,6 @@ type Option struct { ServerName string SkipCertVerify bool Fingerprint string - Flow string - FlowShow bool ClientFingerprint string Reality *tlsC.RealityConfig } @@ -76,78 +70,50 @@ func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error if len(t.option.ALPN) != 0 { alpn = t.option.ALPN } - switch t.option.Flow { - case vless.XRO, vless.XRD, vless.XRS: - xtlsConfig := &xtls.Config{ - NextProtos: alpn, - MinVersion: xtls.VersionTLS12, - InsecureSkipVerify: t.option.SkipCertVerify, - ServerName: t.option.ServerName, - } + tlsConfig := &tls.Config{ + NextProtos: alpn, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: t.option.SkipCertVerify, + ServerName: t.option.ServerName, + } - if len(t.option.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalXTLSConfig(xtlsConfig) - } else { - var err error - if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, t.option.Fingerprint); err != nil { - return nil, err - } - } - - xtlsConn := xtls.Client(conn, xtlsConfig) - - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - if err := xtlsConn.HandshakeContext(ctx); err != nil { + if len(t.option.Fingerprint) == 0 { + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + } else { + var err error + if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint); err != nil { return nil, err } - return xtlsConn, nil - default: - tlsConfig := &tls.Config{ - NextProtos: alpn, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: t.option.SkipCertVerify, - ServerName: t.option.ServerName, - } + } - if len(t.option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - var err error - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint); 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.(*tlsC.UConn).HandshakeContext(ctx) - return utlsConn, err - } - } else { + 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() - return tlsC.GetRealityConn(ctx, conn, t.option.ClientFingerprint, tlsConfig, t.option.Reality) + + err := utlsConn.(*tlsC.UConn).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 } + 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) { @@ -174,37 +140,7 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio }) } -func (t *Trojan) PresetXTLSConn(conn net.Conn) (net.Conn, error) { - switch t.option.Flow { - case vless.XRO, vless.XRD, vless.XRS: - if xtlsConn, ok := conn.(*xtls.Conn); ok { - xtlsConn.RPRX = true - xtlsConn.SHOW = t.option.FlowShow - xtlsConn.MARK = "XTLS" - if t.option.Flow == vless.XRS { - t.option.Flow = vless.XRD - } - - if t.option.Flow == vless.XRD { - xtlsConn.DirectMode = true - } - } else { - return conn, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", t.option.Flow) - } - } - - return conn, nil -} - func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error { - if command == CommandTCP { - if t.option.Flow == vless.XRD { - command = commandXRD - } else if t.option.Flow == vless.XRO { - command = commandXRO - } - } - buf := pool.GetBuffer() defer pool.PutBuffer(buf) @@ -398,8 +334,7 @@ func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, er func hexSha224(data []byte) []byte { buf := make([]byte, 56) - hash := sha256.New224() - hash.Write(data) - hex.Encode(buf, hash.Sum(nil)) + hash := sha256.Sum224(data) + hex.Encode(buf, hash[:]) return buf } diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 3a2a6755..33ecd97a 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -3,7 +3,6 @@ package vless import ( "encoding/binary" "errors" - "fmt" "io" "net" "sync" @@ -13,7 +12,6 @@ import ( "github.com/Dreamacro/clash/transport/vless/vision" "github.com/gofrs/uuid/v5" - xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) @@ -201,25 +199,6 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { if client.Addons != nil { switch client.Addons.Flow { - case XRO, XRD, XRS: - if !dst.UDP { - if xtlsConn, ok := conn.(*xtls.Conn); ok { - xtlsConn.RPRX = true - xtlsConn.SHOW = client.XTLSShow - xtlsConn.MARK = "XTLS" - if client.Addons.Flow == XRS { - client.Addons.Flow = XRD - } - - if client.Addons.Flow == XRD { - xtlsConn.DirectMode = true - } - c.addons = client.Addons - } else { - return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow) - } - } - case XRV: visionConn, err := vision.NewConn(c, c.id) if err != nil { diff --git a/transport/vless/vless.go b/transport/vless/vless.go index c2066afe..6c01b839 100644 --- a/transport/vless/vless.go +++ b/transport/vless/vless.go @@ -42,9 +42,8 @@ type DstAddr struct { // Client is vless connection generator type Client struct { - uuid *uuid.UUID - Addons *Addons - XTLSShow bool + uuid *uuid.UUID + Addons *Addons } // StreamConn return a Conn with net.Conn and DstAddr @@ -53,15 +52,14 @@ func (c *Client) StreamConn(conn net.Conn, dst *DstAddr) (net.Conn, error) { } // NewClient return Client instance -func NewClient(uuidStr string, addons *Addons, xtlsShow bool) (*Client, error) { +func NewClient(uuidStr string, addons *Addons) (*Client, error) { uid, err := utils.UUIDMap(uuidStr) if err != nil { return nil, err } return &Client{ - uuid: &uid, - Addons: addons, - XTLSShow: xtlsShow, + uuid: &uid, + Addons: addons, }, nil } diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go deleted file mode 100644 index 071e6e8f..00000000 --- a/transport/vless/xtls.go +++ /dev/null @@ -1,37 +0,0 @@ -package vless - -import ( - "context" - "net" - - tlsC "github.com/Dreamacro/clash/component/tls" - xtls "github.com/xtls/go" -) - -type XTLSConfig struct { - Host string - SkipCertVerify bool - Fingerprint string - NextProtos []string -} - -func StreamXTLSConn(ctx context.Context, conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { - xtlsConfig := &xtls.Config{ - ServerName: cfg.Host, - InsecureSkipVerify: cfg.SkipCertVerify, - NextProtos: cfg.NextProtos, - } - if len(cfg.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalXTLSConfig(xtlsConfig) - } else { - var err error - if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, cfg.Fingerprint); err != nil { - return nil, err - } - } - - xtlsConn := xtls.Client(conn, xtlsConfig) - - err := xtlsConn.HandshakeContext(ctx) - return xtlsConn, err -}