Improve compatibility for kTLS

This commit is contained in:
世界
2025-09-09 19:20:15 +08:00
parent 9110851af3
commit e9c46cc359
17 changed files with 555 additions and 218 deletions

View File

@@ -3,8 +3,10 @@
package ktls
import (
"bytes"
"context"
"crypto/tls"
"errors"
"io"
"net"
"os"
@@ -15,6 +17,8 @@ import (
"github.com/sagernet/sing/common/logger"
N "github.com/sagernet/sing/common/network"
aTLS "github.com/sagernet/sing/common/tls"
"golang.org/x/sys/unix"
)
type Conn struct {
@@ -85,7 +89,7 @@ func (c *Conn) Upstream() any {
return c.Conn
}
func (c *Conn) SyscallConnForRead() syscall.Conn {
func (c *Conn) SyscallConnForRead() syscall.RawConn {
if !c.kernelRx {
return nil
}
@@ -94,13 +98,34 @@ func (c *Conn) SyscallConnForRead() syscall.Conn {
return nil
}
c.logger.DebugContext(c.ctx, "ktls: RX splice requested")
return c.syscallConn
return c.rawSyscallConn
}
func (c *Conn) SyscallConnForWrite() syscall.Conn {
func (c *Conn) HandleSyscallReadError(inputErr error) ([]byte, error) {
if errors.Is(inputErr, unix.EINVAL) {
err := c.readRecord()
if err != nil {
return nil, E.Cause(err, "ktls: handle non-application-data record")
}
var input bytes.Buffer
if c.rawConn.Input.Len() > 0 {
_, err = c.rawConn.Input.WriteTo(&input)
if err != nil {
return nil, err
}
}
return input.Bytes(), nil
} else if errors.Is(inputErr, unix.EBADMSG) {
return nil, c.rawConn.In.SetErrorLocked(c.sendAlert(alertBadRecordMAC))
} else {
return nil, E.Cause(inputErr, "ktls: unexpected errno")
}
}
func (c *Conn) SyscallConnForWrite() syscall.RawConn {
if !c.kernelTx {
return nil
}
c.logger.DebugContext(c.ctx, "ktls: TX splice requested")
return c.syscallConn
return c.rawSyscallConn
}

View File

@@ -28,6 +28,7 @@ import (
"unsafe"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/debug"
@@ -50,7 +51,7 @@ type RealityClientConfig struct {
shortID [8]byte
}
func NewRealityClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (*RealityClientConfig, error) {
func NewRealityClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
if options.UTLS == nil || !options.UTLS.Enabled {
return nil, E.New("uTLS is required by reality client")
}
@@ -75,7 +76,20 @@ func NewRealityClient(ctx context.Context, logger logger.ContextLogger, serverAd
if decodedLen > 8 {
return nil, E.New("invalid short_id")
}
return &RealityClientConfig{ctx, uClient.(*UTLSClientConfig), publicKey, shortID}, nil
var config Config = &RealityClientConfig{ctx, uClient.(*UTLSClientConfig), publicKey, shortID}
if options.KernelRx || options.KernelTx {
if !C.IsLinux {
return nil, E.New("kTLS is only supported on Linux")
}
config = &KTLSClientConfig{
Config: config,
logger: logger,
kernelTx: options.KernelTx,
kernelRx: options.KernelRx,
}
}
return config, nil
}
func (e *RealityClientConfig) ServerName() string {

View File

@@ -12,6 +12,7 @@ import (
"time"
"github.com/sagernet/sing-box/common/dialer"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
@@ -28,7 +29,7 @@ type RealityServerConfig struct {
config *utls.RealityConfig
}
func NewRealityServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (*RealityServerConfig, error) {
func NewRealityServer(ctx context.Context, logger log.ContextLogger, options option.InboundTLSOptions) (ServerConfig, error) {
var tlsConfig utls.RealityConfig
if options.ACME != nil && len(options.ACME.Domain) > 0 {
@@ -122,11 +123,19 @@ func NewRealityServer(ctx context.Context, logger log.Logger, options option.Inb
if options.ECH != nil && options.ECH.Enabled {
return nil, E.New("Reality is conflict with ECH")
}
if options.KernelRx || options.KernelTx {
return nil, E.New("Reality is conflict with kTLS")
var config ServerConfig = &RealityServerConfig{&tlsConfig}
if options.KernelTx || options.KernelRx {
if !C.IsLinux {
return nil, E.New("kTLS is only supported on Linux")
}
config = &KTlSServerConfig{
ServerConfig: config,
logger: logger,
kernelTx: options.KernelTx,
kernelRx: options.KernelRx,
}
}
return &RealityServerConfig{&tlsConfig}, nil
return config, nil
}
func (c *RealityServerConfig) ServerName() string {

View File

@@ -16,6 +16,7 @@ import (
"github.com/sagernet/sing-box/common/tlsfragment"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/common/ntp"
@@ -226,10 +227,7 @@ func NewUTLSClient(ctx context.Context, logger logger.ContextLogger, serverAddre
return nil, err
}
}
if options.KernelRx || options.KernelTx {
if options.Reality != nil && options.Reality.Enabled {
return nil, E.New("Reality is conflict with kTLS")
}
if (options.KernelRx || options.KernelTx) && !common.PtrValueOrDefault(options.Reality).Enabled {
if !C.IsLinux {
return nil, E.New("kTLS is only supported on Linux")
}

View File

@@ -8,13 +8,14 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
)
func NewUTLSClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
func NewUTLSClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
return nil, E.New(`uTLS is not included in this build, rebuild with -tags with_utls`)
}
func NewRealityClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
func NewRealityClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
return nil, E.New(`uTLS, which is required by reality is not included in this build, rebuild with -tags with_utls`)
}

View File

@@ -11,7 +11,6 @@ import (
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/ntp"
@@ -100,7 +99,7 @@ func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err e
return
}
defer instance.Close()
if earlyConn, isEarlyConn := common.Cast[N.EarlyConn](instance); isEarlyConn && earlyConn.NeedHandshake() {
if N.NeedHandshakeForWrite(instance) {
start = time.Now()
}
req, err := http.NewRequest(http.MethodHead, link, nil)