chore: Remove legacy XTLS support (#645)
* chore: Remove legacy XTLS support * chore: Rename function
This commit is contained in:
parent
cbb8ef5dfe
commit
a82745f544
10 changed files with 55 additions and 264 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
@ -17,9 +16,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
globalClientSessionCache tls.ClientSessionCache
|
globalClientSessionCache tls.ClientSessionCache
|
||||||
globalClientXSessionCache xtls.ClientSessionCache
|
once sync.Once
|
||||||
once sync.Once
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func tcpKeepAlive(c net.Conn) {
|
func tcpKeepAlive(c net.Conn) {
|
||||||
|
@ -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()
|
||||||
|
|
|
@ -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) {
|
||||||
host, _, _ := net.SplitHostPort(v.addr)
|
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{
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
1
go.mod
|
@ -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
2
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-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=
|
||||||
|
|
|
@ -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,78 +70,50 @@ 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 {
|
tlsConfig := &tls.Config{
|
||||||
case vless.XRO, vless.XRD, vless.XRS:
|
NextProtos: alpn,
|
||||||
xtlsConfig := &xtls.Config{
|
MinVersion: tls.VersionTLS12,
|
||||||
NextProtos: alpn,
|
InsecureSkipVerify: t.option.SkipCertVerify,
|
||||||
MinVersion: xtls.VersionTLS12,
|
ServerName: t.option.ServerName,
|
||||||
InsecureSkipVerify: t.option.SkipCertVerify,
|
}
|
||||||
ServerName: t.option.ServerName,
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(t.option.Fingerprint) == 0 {
|
if len(t.option.Fingerprint) == 0 {
|
||||||
xtlsConfig = tlsC.GetGlobalXTLSConfig(xtlsConfig)
|
tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig)
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, t.option.Fingerprint); err != nil {
|
if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, 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 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 {
|
if len(t.option.ClientFingerprint) != 0 {
|
||||||
tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig)
|
if t.option.Reality == nil {
|
||||||
} else {
|
utlsConn, valid := vmess.GetUTLSConn(conn, t.option.ClientFingerprint, tlsConfig)
|
||||||
var err error
|
if valid {
|
||||||
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 {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||||
defer cancel()
|
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) {
|
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 {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -42,9 +42,8 @@ type DstAddr struct {
|
||||||
|
|
||||||
// Client is vless connection generator
|
// Client is vless connection generator
|
||||||
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,15 +52,14 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Client{
|
return &Client{
|
||||||
uuid: &uid,
|
uuid: &uid,
|
||||||
Addons: addons,
|
Addons: addons,
|
||||||
XTLSShow: xtlsShow,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
Loading…
Reference in a new issue