Compare commits

...

2 Commits

Author SHA1 Message Date
世界
34892f4c7e
ktls: Add warning for inappropriate scenarios 2025-09-08 21:27:13 +08:00
世界
94103df562
ktls: Fix parse kernel version 2025-09-08 21:27:13 +08:00
16 changed files with 186 additions and 57 deletions

View File

@ -5,6 +5,8 @@ import (
"strings" "strings"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"golang.org/x/mod/semver"
) )
type Version struct { type Version struct {
@ -16,7 +18,19 @@ type Version struct {
PreReleaseVersion int PreReleaseVersion int
} }
func (v Version) After(anotherVersion Version) bool { func (v Version) LessThan(anotherVersion Version) bool {
return !v.GreaterThanOrEqual(anotherVersion)
}
func (v Version) LessThanOrEqual(anotherVersion Version) bool {
return v == anotherVersion || anotherVersion.GreaterThan(v)
}
func (v Version) GreaterThanOrEqual(anotherVersion Version) bool {
return v == anotherVersion || v.GreaterThan(anotherVersion)
}
func (v Version) GreaterThan(anotherVersion Version) bool {
if v.Major > anotherVersion.Major { if v.Major > anotherVersion.Major {
return true return true
} else if v.Major < anotherVersion.Major { } else if v.Major < anotherVersion.Major {
@ -44,19 +58,29 @@ func (v Version) After(anotherVersion Version) bool {
} else if v.PreReleaseVersion < anotherVersion.PreReleaseVersion { } else if v.PreReleaseVersion < anotherVersion.PreReleaseVersion {
return false return false
} }
} else if v.PreReleaseIdentifier == "rc" && anotherVersion.PreReleaseIdentifier == "beta" { }
preReleaseIdentifier := parsePreReleaseIdentifier(v.PreReleaseIdentifier)
anotherPreReleaseIdentifier := parsePreReleaseIdentifier(anotherVersion.PreReleaseIdentifier)
if preReleaseIdentifier < anotherPreReleaseIdentifier {
return true return true
} else if v.PreReleaseIdentifier == "beta" && anotherVersion.PreReleaseIdentifier == "rc" { } else if preReleaseIdentifier > anotherPreReleaseIdentifier {
return false
} else if v.PreReleaseIdentifier == "beta" && anotherVersion.PreReleaseIdentifier == "alpha" {
return true
} else if v.PreReleaseIdentifier == "alpha" && anotherVersion.PreReleaseIdentifier == "beta" {
return false return false
} }
} }
return false return false
} }
func parsePreReleaseIdentifier(identifier string) int {
if strings.HasPrefix(identifier, "rc") {
return 1
} else if strings.HasPrefix(identifier, "beta") {
return 2
} else if strings.HasPrefix(identifier, "alpha") {
return 3
}
return 0
}
func (v Version) VersionString() string { func (v Version) VersionString() string {
return F.ToString(v.Major, ".", v.Minor, ".", v.Patch) return F.ToString(v.Major, ".", v.Minor, ".", v.Patch)
} }
@ -83,6 +107,10 @@ func (v Version) BadString() string {
return version return version
} }
func IsValid(versionName string) bool {
return semver.IsValid("v" + versionName)
}
func Parse(versionName string) (version Version) { func Parse(versionName string) (version Version) {
if strings.HasPrefix(versionName, "v") { if strings.HasPrefix(versionName, "v") {
versionName = versionName[1:] versionName = versionName[1:]

View File

@ -10,9 +10,9 @@ func TestCompareVersion(t *testing.T) {
t.Parallel() t.Parallel()
require.Equal(t, "1.3.0-beta.1", Parse("v1.3.0-beta1").String()) require.Equal(t, "1.3.0-beta.1", Parse("v1.3.0-beta1").String())
require.Equal(t, "1.3-beta1", Parse("v1.3.0-beta.1").BadString()) require.Equal(t, "1.3-beta1", Parse("v1.3.0-beta.1").BadString())
require.True(t, Parse("1.3.0").After(Parse("1.3-beta1"))) require.True(t, Parse("1.3.0").GreaterThan(Parse("1.3-beta1")))
require.True(t, Parse("1.3.0").After(Parse("1.3.0-beta1"))) require.True(t, Parse("1.3.0").GreaterThan(Parse("1.3.0-beta1")))
require.True(t, Parse("1.3.0-beta1").After(Parse("1.3.0-alpha1"))) require.True(t, Parse("1.3.0-beta1").GreaterThan(Parse("1.3.0-alpha1")))
require.True(t, Parse("1.3.1").After(Parse("1.3.0"))) require.True(t, Parse("1.3.1").GreaterThan(Parse("1.3.0")))
require.True(t, Parse("1.4").After(Parse("1.3"))) require.True(t, Parse("1.4").GreaterThan(Parse("1.3")))
} }

View File

@ -61,7 +61,7 @@ func NewConn(ctx context.Context, logger logger.ContextLogger, conn aTLS.Conn, t
for rawConn.Hand.Len() > 0 { for rawConn.Hand.Len() > 0 {
err = rawConn.HandlePostHandshakeMessage() err = rawConn.HandlePostHandshakeMessage()
if err != nil { if err != nil {
return nil, E.Cause(err, "ktls: failed to handle post-handshake messages") return nil, E.Cause(err, "handle post-handshake messages")
} }
} }
} }

View File

@ -12,11 +12,11 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/sagernet/sing-box/common/badversion"
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/shell" "github.com/sagernet/sing/common/shell"
"github.com/blang/semver/v4"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -55,46 +55,42 @@ var KernelSupport = sync.OnceValues(func() (*Support, error) {
return nil, err return nil, err
} }
kernelVersion, err := semver.Parse(strings.Trim(string(uname.Release[:]), "\x00")) kernelVersion := badversion.Parse(strings.Trim(string(uname.Release[:]), "\x00"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
kernelVersion.Pre = nil
kernelVersion.Build = nil
var support Support var support Support
switch { switch {
case kernelVersion.GTE(semver.Version{Major: 6, Minor: 14}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6, Minor: 14}):
support.TLS_Version13_KeyUpdate = true support.TLS_Version13_KeyUpdate = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 6, Minor: 1}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6, Minor: 1}):
support.TLS_ARIA_GCM = true support.TLS_ARIA_GCM = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 6}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6}):
support.TLS_Version13_RX = true support.TLS_Version13_RX = true
support.TLS_RX_NOPADDING = true support.TLS_RX_NOPADDING = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 19}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 19}):
support.TLS_TX_ZEROCOPY = true support.TLS_TX_ZEROCOPY = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 16}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 16}):
support.TLS_SM4 = true support.TLS_SM4 = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 11}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 11}):
support.TLS_CHACHA20_POLY1305 = true support.TLS_CHACHA20_POLY1305 = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 2}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 2}):
support.TLS_AES_128_CCM = true support.TLS_AES_128_CCM = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 1}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 1}):
support.TLS_AES_256_GCM = true support.TLS_AES_256_GCM = true
support.TLS_Version13 = true support.TLS_Version13 = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 4, Minor: 17}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 4, Minor: 17}):
support.TLS_RX = true support.TLS_RX = true
fallthrough fallthrough
case kernelVersion.GTE(semver.Version{Major: 4, Minor: 13}): case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 4, Minor: 13}):
support.TLS = true support.TLS = true
} }
@ -118,7 +114,7 @@ var KernelSupport = sync.OnceValues(func() (*Support, error) {
func Load() error { func Load() error {
support, err := KernelSupport() support, err := KernelSupport()
if err != nil { if err != nil {
return err return E.Cause(err, "ktls: check availability")
} }
if !support.TLS || !support.TLS_Version13 { if !support.TLS || !support.TLS_Version13 {
return E.New("ktls: kernel does not support TLS 1.3") return E.New("ktls: kernel does not support TLS 1.3")
@ -132,10 +128,10 @@ func (c *Conn) setupKernel(txOffload, rxOffload bool) error {
} }
support, err := KernelSupport() support, err := KernelSupport()
if err != nil { if err != nil {
return err return E.Cause(err, "check availability")
} }
if !support.TLS || !support.TLS_Version13 { if !support.TLS || !support.TLS_Version13 {
return E.New("ktls: kernel does not support TLS 1.3") return E.New("kernel does not support TLS 1.3")
} }
c.rawConn.Out.Lock() c.rawConn.Out.Lock()
defer c.rawConn.Out.Unlock() defer c.rawConn.Out.Unlock()
@ -143,13 +139,13 @@ func (c *Conn) setupKernel(txOffload, rxOffload bool) error {
return syscall.SetsockoptString(int(fd), unix.SOL_TCP, unix.TCP_ULP, "tls") return syscall.SetsockoptString(int(fd), unix.SOL_TCP, unix.TCP_ULP, "tls")
}) })
if err != nil { if err != nil {
return E.Cause(err, "initialize kernel TLS") return os.NewSyscallError("setsockopt", err)
} }
if txOffload { if txOffload {
txCrypto := kernelCipher(support, c.rawConn.Out, *c.rawConn.CipherSuite, false) txCrypto := kernelCipher(support, c.rawConn.Out, *c.rawConn.CipherSuite, false)
if txCrypto == nil { if txCrypto == nil {
return E.New("kTLS: unsupported cipher suite") return E.New("unsupported cipher suite")
} }
err = control.Raw(c.rawSyscallConn, func(fd uintptr) error { err = control.Raw(c.rawSyscallConn, func(fd uintptr) error {
return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_TX, txCrypto.String()) return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_TX, txCrypto.String())
@ -172,7 +168,7 @@ func (c *Conn) setupKernel(txOffload, rxOffload bool) error {
if rxOffload { if rxOffload {
rxCrypto := kernelCipher(support, c.rawConn.In, *c.rawConn.CipherSuite, true) rxCrypto := kernelCipher(support, c.rawConn.In, *c.rawConn.CipherSuite, true)
if rxCrypto == nil { if rxCrypto == nil {
return E.New("kTLS: unsupported cipher suite") return E.New("unsupported cipher suite")
} }
err = control.Raw(c.rawSyscallConn, func(fd uintptr) error { err = control.Raw(c.rawSyscallConn, func(fd uintptr) error {
return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_RX, rxCrypto.String()) return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_RX, rxCrypto.String())

View File

@ -20,7 +20,12 @@ func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dial
if !options.Enabled { if !options.Enabled {
return dialer, nil return dialer, nil
} }
config, err := NewClient(ctx, logger, serverAddress, options) config, err := NewClientWithOptions(ClientOptions{
Context: ctx,
Logger: logger,
ServerAddress: serverAddress,
Options: options,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -28,15 +33,40 @@ func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dial
} }
func NewClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) { func NewClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
if !options.Enabled { return NewClientWithOptions(ClientOptions{
Context: ctx,
Logger: logger,
ServerAddress: serverAddress,
Options: options,
})
}
type ClientOptions struct {
Context context.Context
Logger logger.ContextLogger
ServerAddress string
Options option.OutboundTLSOptions
KTLSCompatible bool
}
func NewClientWithOptions(options ClientOptions) (Config, error) {
if !options.Options.Enabled {
return nil, nil return nil, nil
} }
if options.Reality != nil && options.Reality.Enabled { if !options.KTLSCompatible {
return NewRealityClient(ctx, logger, serverAddress, options) if options.Options.KernelTx {
} else if options.UTLS != nil && options.UTLS.Enabled { options.Logger.Warn("enabling kTLS TX in current scenarios will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_tx")
return NewUTLSClient(ctx, logger, serverAddress, options) }
} }
return NewSTDClient(ctx, logger, serverAddress, options) if options.Options.KernelRx {
options.Logger.Warn("enabling kTLS RX will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_rx")
}
if options.Options.Reality != nil && options.Options.Reality.Enabled {
return NewRealityClient(options.Context, options.Logger, options.ServerAddress, options.Options)
} else if options.Options.UTLS != nil && options.Options.UTLS.Enabled {
return NewUTLSClient(options.Context, options.Logger, options.ServerAddress, options.Options)
}
return NewSTDClient(options.Context, options.Logger, options.ServerAddress, options.Options)
} }
func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) { func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {

View File

@ -5,6 +5,7 @@ import (
"net" "net"
"github.com/sagernet/sing-box/common/ktls" "github.com/sagernet/sing-box/common/ktls"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
aTLS "github.com/sagernet/sing/common/tls" aTLS "github.com/sagernet/sing/common/tls"
) )
@ -20,7 +21,12 @@ func (w *KTLSClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (
if err != nil { if err != nil {
return nil, err return nil, err
} }
return ktls.NewConn(ctx, w.logger, tlsConn, w.kernelTx, w.kernelRx) kConn, err := ktls.NewConn(ctx, w.logger, tlsConn, w.kernelTx, w.kernelRx)
if err != nil {
tlsConn.Close()
return nil, E.Cause(err, "initialize kernel TLS")
}
return kConn, nil
} }
func (w *KTLSClientConfig) Clone() Config { func (w *KTLSClientConfig) Clone() Config {
@ -43,7 +49,12 @@ func (w *KTlSServerConfig) ServerHandshake(ctx context.Context, conn net.Conn) (
if err != nil { if err != nil {
return nil, err return nil, err
} }
return ktls.NewConn(ctx, w.logger, tlsConn, w.kernelTx, w.kernelRx) kConn, err := ktls.NewConn(ctx, w.logger, tlsConn, w.kernelTx, w.kernelRx)
if err != nil {
tlsConn.Close()
return nil, E.Cause(err, "initialize kernel TLS")
}
return kConn, nil
} }
func (w *KTlSServerConfig) Clone() Config { func (w *KTlSServerConfig) Clone() Config {

View File

@ -12,14 +12,37 @@ import (
aTLS "github.com/sagernet/sing/common/tls" aTLS "github.com/sagernet/sing/common/tls"
) )
type ServerOptions struct {
Context context.Context
Logger log.ContextLogger
Options option.InboundTLSOptions
KTLSCompatible bool
}
func NewServer(ctx context.Context, logger log.ContextLogger, options option.InboundTLSOptions) (ServerConfig, error) { func NewServer(ctx context.Context, logger log.ContextLogger, options option.InboundTLSOptions) (ServerConfig, error) {
if !options.Enabled { return NewServerWithOptions(ServerOptions{
Context: ctx,
Logger: logger,
Options: options,
})
}
func NewServerWithOptions(options ServerOptions) (ServerConfig, error) {
if !options.Options.Enabled {
return nil, nil return nil, nil
} }
if options.Reality != nil && options.Reality.Enabled { if !options.KTLSCompatible {
return NewRealityServer(ctx, logger, options) if options.Options.KernelTx {
options.Logger.Warn("enabling kTLS TX in current scenarios will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_tx")
}
} }
return NewSTDServer(ctx, logger, options) if options.Options.KernelRx {
options.Logger.Warn("enabling kTLS RX will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_rx")
}
if options.Options.Reality != nil && options.Options.Reality.Enabled {
return NewRealityServer(options.Context, options.Logger, options.Options)
}
return NewSTDServer(options.Context, options.Logger, options.Options)
} }
func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) { func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) {

View File

@ -10,6 +10,7 @@ import (
"github.com/sagernet/fswatch" "github.com/sagernet/fswatch"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
@ -273,6 +274,9 @@ func NewSTDServer(ctx context.Context, logger log.ContextLogger, options option.
echKeyPath: echKeyPath, echKeyPath: echKeyPath,
} }
if options.KernelTx || options.KernelRx { if options.KernelTx || options.KernelRx {
if !C.IsLinux {
return nil, E.New("kTLS is only supported on Linux")
}
config = &KTlSServerConfig{ config = &KTlSServerConfig{
ServerConfig: config, ServerConfig: config,
logger: logger, logger: logger,

1
go.mod
View File

@ -4,7 +4,6 @@ go 1.23.1
require ( require (
github.com/anytls/sing-anytls v0.0.8 github.com/anytls/sing-anytls v0.0.8
github.com/blang/semver/v4 v4.0.0
github.com/caddyserver/certmagic v0.23.0 github.com/caddyserver/certmagic v0.23.0
github.com/coder/websocket v1.8.13 github.com/coder/websocket v1.8.13
github.com/cretz/bine v0.2.0 github.com/cretz/bine v0.2.0

2
go.sum
View File

@ -12,8 +12,6 @@ github.com/anytls/sing-anytls v0.0.8 h1:1u/fnH1HoeeMV5mX7/eUOjLBvPdkd1UJRmXiRi6V
github.com/anytls/sing-anytls v0.0.8/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= github.com/anytls/sing-anytls v0.0.8/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU= github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU=
github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4= github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4=
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=

View File

@ -43,7 +43,12 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
authenticator: auth.NewAuthenticator(options.Users), authenticator: auth.NewAuthenticator(options.Users),
} }
if options.TLS != nil { if options.TLS != nil {
tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) tlsConfig, err := tls.NewServerWithOptions(tls.ServerOptions{
Context: ctx,
Logger: logger,
Options: common.PtrValueOrDefault(options.TLS),
KTLSCompatible: true,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -46,7 +46,12 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
authenticator: auth.NewAuthenticator(options.Users), authenticator: auth.NewAuthenticator(options.Users),
} }
if options.TLS != nil { if options.TLS != nil {
tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) tlsConfig, err := tls.NewServerWithOptions(tls.ServerOptions{
Context: ctx,
Logger: logger,
Options: common.PtrValueOrDefault(options.TLS),
KTLSCompatible: true,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -50,7 +50,13 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
users: options.Users, users: options.Users,
} }
if options.TLS != nil { if options.TLS != nil {
tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) tlsConfig, err := tls.NewServerWithOptions(tls.ServerOptions{
Context: ctx,
Logger: logger,
Options: common.PtrValueOrDefault(options.TLS),
KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" &&
!common.PtrValueOrDefault(options.Multiplex).Enabled,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -51,7 +51,14 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
key: trojan.Key(options.Password), key: trojan.Key(options.Password),
} }
if options.TLS != nil { if options.TLS != nil {
outbound.tlsConfig, err = tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) outbound.tlsConfig, err = tls.NewClientWithOptions(tls.ClientOptions{
Context: ctx,
Logger: logger,
ServerAddress: options.Server,
Options: common.PtrValueOrDefault(options.TLS),
KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" &&
!common.PtrValueOrDefault(options.Multiplex).Enabled,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -68,7 +68,16 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
})) }))
inbound.service = service inbound.service = service
if options.TLS != nil { if options.TLS != nil {
inbound.tlsConfig, err = tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) inbound.tlsConfig, err = tls.NewServerWithOptions(tls.ServerOptions{
Context: ctx,
Logger: logger,
Options: common.PtrValueOrDefault(options.TLS),
KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" &&
!common.PtrValueOrDefault(options.Multiplex).Enabled &&
common.All(options.Users, func(it option.VLESSUser) bool {
return it.Flow == ""
}),
})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -53,7 +53,15 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
} }
if options.TLS != nil { if options.TLS != nil {
outbound.tlsConfig, err = tls.NewClient(ctx, logger, options.Server, common.PtrValueOrDefault(options.TLS)) outbound.tlsConfig, err = tls.NewClientWithOptions(tls.ClientOptions{
Context: ctx,
Logger: logger,
ServerAddress: options.Server,
Options: common.PtrValueOrDefault(options.TLS),
KTLSCompatible: common.PtrValueOrDefault(options.Transport).Type == "" &&
!common.PtrValueOrDefault(options.Multiplex).Enabled &&
options.Flow == "",
})
if err != nil { if err != nil {
return nil, err return nil, err
} }