chore: Remove legacy XTLS support (#645)

* chore: Remove legacy XTLS support

* chore: Rename function
This commit is contained in:
Hellojack 2023-07-16 23:26:07 +08:00 committed by GitHub
parent cbb8ef5dfe
commit a82745f544
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 55 additions and 264 deletions

View File

@ -14,7 +14,6 @@ import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/gun"
"github.com/Dreamacro/clash/transport/trojan" "github.com/Dreamacro/clash/transport/trojan"
"github.com/Dreamacro/clash/transport/vless"
) )
type Trojan struct { type Trojan struct {
@ -45,8 +44,6 @@ type TrojanOption struct {
RealityOpts RealityOptions `proxy:"reality-opts,omitempty"` RealityOpts RealityOptions `proxy:"reality-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-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"` 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) 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 { if metadata.NetWork == C.UDP {
err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata))
return c, err return c, err
@ -117,12 +109,6 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ...
return nil, err 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 { if err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)); err != nil {
c.Close() c.Close()
return nil, err return nil, err
@ -237,24 +223,10 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
ALPN: option.ALPN, ALPN: option.ALPN,
ServerName: option.Server, ServerName: option.Server,
SkipCertVerify: option.SkipCertVerify, SkipCertVerify: option.SkipCertVerify,
FlowShow: option.FlowShow,
Fingerprint: option.Fingerprint, Fingerprint: option.Fingerprint,
ClientFingerprint: option.ClientFingerprint, 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 != "" { if option.SNI != "" {
tOption.ServerName = option.SNI tOption.ServerName = option.SNI
} }

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"context" "context"
"crypto/tls" "crypto/tls"
xtls "github.com/xtls/go"
"net" "net"
"net/netip" "net/netip"
"strconv" "strconv"
@ -18,7 +17,6 @@ import (
var ( var (
globalClientSessionCache tls.ClientSessionCache globalClientSessionCache tls.ClientSessionCache
globalClientXSessionCache xtls.ClientSessionCache
once sync.Once once sync.Once
) )
@ -36,13 +34,6 @@ func getClientSessionCache() tls.ClientSessionCache {
return globalClientSessionCache return globalClientSessionCache
} }
func getClientXSessionCache() xtls.ClientSessionCache {
once.Do(func() {
globalClientXSessionCache = xtls.NewLRUClientSessionCache(128)
})
return globalClientXSessionCache
}
func serializesSocksAddr(metadata *C.Metadata) []byte { func serializesSocksAddr(metadata *C.Metadata) []byte {
var buf [][]byte var buf [][]byte
addrType := metadata.AddrType() addrType := metadata.AddrType()

View File

@ -56,7 +56,6 @@ type VlessOption struct {
Port int `proxy:"port"` Port int `proxy:"port"`
UUID string `proxy:"uuid"` UUID string `proxy:"uuid"`
Flow string `proxy:"flow,omitempty"` Flow string `proxy:"flow,omitempty"`
FlowShow bool `proxy:"flow-show,omitempty"`
TLS bool `proxy:"tls,omitempty"` TLS bool `proxy:"tls,omitempty"`
UDP bool `proxy:"udp,omitempty"` UDP bool `proxy:"udp,omitempty"`
PacketAddr bool `proxy:"packet-addr,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) c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts)
case "http": case "http":
// readability first, so just copy default TLS logic // 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 { if err != nil {
return nil, err 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) c = vmess.StreamHTTPConn(c, httpOpts)
case "h2": case "h2":
c, err = v.streamTLSOrXTLSConn(ctx, c, true) c, err = v.streamTLSConn(ctx, c, true)
if err != nil { if err != nil {
return nil, err 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) 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
c, err = v.streamTLSOrXTLSConn(ctx, c, false) c, err = v.streamTLSConn(ctx, c, false)
} }
if err != nil { if err != nil {
@ -202,23 +201,10 @@ func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err
return return
} }
func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { func (v *Vless) streamTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) {
if v.option.TLS {
host, _, _ := net.SplitHostPort(v.addr) 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{ tlsOpts := vmess.TLSConfig{
Host: host, Host: host,
SkipCertVerify: v.option.SkipCertVerify, SkipCertVerify: v.option.SkipCertVerify,
@ -241,10 +227,6 @@ func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 boo
return conn, nil return conn, nil
} }
func (v *Vless) isLegacyXTLSEnabled() bool {
return v.client.Addons != nil && v.client.Addons.Flow != vless.XRV
}
// DialContext implements C.ProxyAdapter // DialContext implements C.ProxyAdapter
func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
// gun transport // gun transport
@ -526,11 +508,11 @@ func NewVless(option VlessOption) (*Vless, error) {
switch option.Flow { switch option.Flow {
case vless.XRV: case vless.XRV:
log.Warnln("To use %s, ensure your server is upgrade to Xray-core v1.8.0+", 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{ addons = &vless.Addons{
Flow: option.Flow, 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: default:
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow) return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
} }
@ -549,7 +531,7 @@ func NewVless(option VlessOption) (*Vless, error) {
option.PacketAddr = false option.PacketAddr = false
} }
client, err := vless.NewClient(option.UUID, addons, option.FlowShow) client, err := vless.NewClient(option.UUID, addons)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -10,8 +10,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"sync" "sync"
xtls "github.com/xtls/go"
) )
var trustCerts []*x509.Certificate var trustCerts []*x509.Certificate
@ -122,27 +120,3 @@ func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config {
tlsConfig.RootCAs = certPool tlsConfig.RootCAs = certPool
return tlsConfig 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
}

1
go.mod
View File

@ -42,7 +42,6 @@ require (
github.com/shirou/gopsutil/v3 v3.23.6 github.com/shirou/gopsutil/v3 v3.23.6
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3
github.com/zhangyunhao116/fastrand v0.3.0 github.com/zhangyunhao116/fastrand v0.3.0
go.etcd.io/bbolt v1.3.7 go.etcd.io/bbolt v1.3.7
go.uber.org/automaxprocs v1.5.2 go.uber.org/automaxprocs v1.5.2

2
go.sum
View File

@ -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-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 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= 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/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 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=

View File

@ -7,7 +7,6 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt"
"io" "io"
"net" "net"
"net/http" "net/http"
@ -18,10 +17,7 @@ import (
tlsC "github.com/Dreamacro/clash/component/tls" tlsC "github.com/Dreamacro/clash/component/tls"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/transport/vless"
"github.com/Dreamacro/clash/transport/vmess" "github.com/Dreamacro/clash/transport/vmess"
xtls "github.com/xtls/go"
) )
const ( const (
@ -42,7 +38,7 @@ const (
CommandTCP byte = 1 CommandTCP byte = 1
CommandUDP byte = 3 CommandUDP byte = 3
// for XTLS // deprecated XTLS commands, as souvenirs
commandXRD byte = 0xf0 // XTLS direct mode commandXRD byte = 0xf0 // XTLS direct mode
commandXRO byte = 0xf1 // XTLS origin mode commandXRO byte = 0xf1 // XTLS origin mode
) )
@ -53,8 +49,6 @@ type Option struct {
ServerName string ServerName string
SkipCertVerify bool SkipCertVerify bool
Fingerprint string Fingerprint string
Flow string
FlowShow bool
ClientFingerprint string ClientFingerprint string
Reality *tlsC.RealityConfig Reality *tlsC.RealityConfig
} }
@ -76,33 +70,6 @@ func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error
if len(t.option.ALPN) != 0 { if len(t.option.ALPN) != 0 {
alpn = t.option.ALPN 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,
}
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 {
return nil, err
}
return xtlsConn, nil
default:
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
NextProtos: alpn, NextProtos: alpn,
MinVersion: tls.VersionTLS12, MinVersion: tls.VersionTLS12,
@ -148,7 +115,6 @@ func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error
err := tlsConn.HandshakeContext(ctx) err := tlsConn.HandshakeContext(ctx)
return tlsConn, err return tlsConn, err
} }
}
func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) { func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
alpn := defaultWebsocketALPN alpn := defaultWebsocketALPN
@ -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 { 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() buf := pool.GetBuffer()
defer pool.PutBuffer(buf) 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 { func hexSha224(data []byte) []byte {
buf := make([]byte, 56) buf := make([]byte, 56)
hash := sha256.New224() hash := sha256.Sum224(data)
hash.Write(data) hex.Encode(buf, hash[:])
hex.Encode(buf, hash.Sum(nil))
return buf return buf
} }

View File

@ -3,7 +3,6 @@ package vless
import ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"io" "io"
"net" "net"
"sync" "sync"
@ -13,7 +12,6 @@ import (
"github.com/Dreamacro/clash/transport/vless/vision" "github.com/Dreamacro/clash/transport/vless/vision"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
xtls "github.com/xtls/go"
"google.golang.org/protobuf/proto" "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 { if client.Addons != nil {
switch client.Addons.Flow { 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: case XRV:
visionConn, err := vision.NewConn(c, c.id) visionConn, err := vision.NewConn(c, c.id)
if err != nil { if err != nil {

View File

@ -44,7 +44,6 @@ type DstAddr struct {
type Client struct { type Client struct {
uuid *uuid.UUID uuid *uuid.UUID
Addons *Addons Addons *Addons
XTLSShow bool
} }
// StreamConn return a Conn with net.Conn and DstAddr // StreamConn return a Conn with net.Conn and DstAddr
@ -53,7 +52,7 @@ func (c *Client) StreamConn(conn net.Conn, dst *DstAddr) (net.Conn, error) {
} }
// NewClient return Client instance // 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) uid, err := utils.UUIDMap(uuidStr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -62,6 +61,5 @@ func NewClient(uuidStr string, addons *Addons, xtlsShow bool) (*Client, error) {
return &Client{ return &Client{
uuid: &uid, uuid: &uid,
Addons: addons, Addons: addons,
XTLSShow: xtlsShow,
}, nil }, nil
} }

View File

@ -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
}