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

View file

@ -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()

View file

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

View file

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

1
go.mod
View file

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

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-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=

View file

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

View file

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

View file

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

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
}