Compare commits

..

26 Commits

Author SHA1 Message Date
世界
0e423a9133
ktls: Add warning for inappropriate scenarios 2025-09-08 19:48:01 +08:00
世界
64843452bc
ktls: Fix parse kernel version 2025-09-08 19:46:45 +08:00
世界
a832c26a2f
documentation: Bump version 2025-09-08 19:46:45 +08:00
世界
c3ac036aee
Update Go to 1.25.1 2025-09-08 19:46:45 +08:00
世界
c3d6f42a5a
documentation: Add kTLS 2025-09-08 19:46:45 +08:00
世界
73595dd75c
Add support for kTLS
Reference: https://gitlab.com/go-extension/tls
2025-09-08 19:46:44 +08:00
世界
61bb706ad7
Add proxy support for ICMP echo request 2025-09-08 19:46:43 +08:00
世界
f89ff2fb66
Fix resolve using resolved 2025-09-08 19:46:43 +08:00
世界
49c7ab402a
documentation: Update behavior of local DNS server on darwin 2025-09-08 19:46:43 +08:00
世界
2ff8e0babc
Stop using DHCP on iOS and tvOS
We do not have the `com.apple.developer.networking.multicast` entitlement and are unable to obtain it for non-technical reasons.
2025-09-08 19:46:43 +08:00
世界
bac7a5bc9e
Remove use of ldflags -checklinkname=0 on darwin 2025-09-08 19:46:43 +08:00
世界
ffc065bd74
Fix local DNS server on darwin
We mistakenly believed that `libresolv`'s `search` function worked correctly in NetworkExtension, but it seems only `getaddrinfo` does.

This commit changes the behavior of the `local` DNS server in NetworkExtension to prefer DHCP, falling back to `getaddrinfo` if DHCP servers are unavailable.

It's worth noting that `prefer_go` does not disable DHCP since it respects Dial Fields, but `getaddrinfo` does the opposite. The new behavior only applies to NetworkExtension, not to all scenarios (primarily command-line binaries) as it did previously.

In addition, this commit also improves the DHCP DNS server to use the same robust query logic as `local`.
2025-09-08 19:46:42 +08:00
世界
ca4bbff6f4
Fix legacy DNS config 2025-09-08 19:46:42 +08:00
世界
dea7b79d43
Fix rule-set format 2025-09-08 19:46:41 +08:00
世界
bf342408b8
documentation: Remove outdated icons 2025-09-08 19:46:41 +08:00
世界
d2856cea06
documentation: Improve local DNS server 2025-09-08 19:46:41 +08:00
世界
ff0c266ef0
Use libresolv in local DNS server on darwin 2025-09-08 19:46:41 +08:00
世界
bc11350397
Use resolved in local DNS server if available 2025-09-08 19:46:41 +08:00
xchacha20-poly1305
76a9d68566
Fix rule set version 2025-09-08 19:46:40 +08:00
世界
83a94a4384
documentation: Add preferred_by route rule item 2025-09-08 19:46:40 +08:00
世界
9ee622b807
Add preferred_by route rule item 2025-09-08 19:46:40 +08:00
世界
f8338b15e1
documentation: Add interface address rule items 2025-09-08 19:46:39 +08:00
世界
485405d350
Add interface address rule items 2025-09-08 19:46:39 +08:00
neletor
084c5f3797
Add support for ech retry configs 2025-09-08 19:46:39 +08:00
Zephyruso
55f7fa1243
Add /dns/flush-clash meta api 2025-09-08 19:46:39 +08:00
世界
79c0b9f51d
Fix tls options ignored in mixed inbounds 2025-09-08 19:45:52 +08:00
21 changed files with 339 additions and 107 deletions

View File

@ -46,7 +46,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.25.0
go-version: ^1.25.1
- name: Check input version
if: github.event_name == 'workflow_dispatch'
run: |-
@ -110,7 +110,7 @@ jobs:
if: ${{ ! (matrix.legacy_go123 || matrix.legacy_go124) }}
uses: actions/setup-go@v5
with:
go-version: ^1.25.0
go-version: ^1.25.1
- name: Setup Go 1.24
if: matrix.legacy_go124
uses: actions/setup-go@v5
@ -300,7 +300,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.25.0
go-version: ^1.25.1
- name: Setup Android NDK
id: setup-ndk
uses: nttld/setup-ndk@v1
@ -380,7 +380,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.25.0
go-version: ^1.25.1
- name: Setup Android NDK
id: setup-ndk
uses: nttld/setup-ndk@v1
@ -478,7 +478,7 @@ jobs:
if: matrix.if
uses: actions/setup-go@v5
with:
go-version: ^1.25.0
go-version: ^1.25.1
- name: Setup Xcode stable
if: matrix.if && github.ref == 'refs/heads/main-next'
run: |-

View File

@ -30,7 +30,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.25.0
go-version: ^1.25.1
- name: Check input version
if: github.event_name == 'workflow_dispatch'
run: |-
@ -71,7 +71,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.25.0
go-version: ^1.25.1
- name: Setup Android NDK
if: matrix.os == 'android'
uses: nttld/setup-ndk@v1

View File

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

View File

@ -10,9 +10,9 @@ func TestCompareVersion(t *testing.T) {
t.Parallel()
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.True(t, Parse("1.3.0").After(Parse("1.3-beta1")))
require.True(t, Parse("1.3.0").After(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.1").After(Parse("1.3.0")))
require.True(t, Parse("1.4").After(Parse("1.3")))
require.True(t, Parse("1.3.0").GreaterThan(Parse("1.3-beta1")))
require.True(t, Parse("1.3.0").GreaterThan(Parse("1.3.0-beta1")))
require.True(t, Parse("1.3.0-beta1").GreaterThan(Parse("1.3.0-alpha1")))
require.True(t, Parse("1.3.1").GreaterThan(Parse("1.3.0")))
require.True(t, Parse("1.4").GreaterThan(Parse("1.3")))
}

View File

@ -11,7 +11,6 @@ import (
"syscall"
"github.com/sagernet/sing-box/common/badtls"
// C "github.com/sagernet/sing-box/constant"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
N "github.com/sagernet/sing/common/network"
@ -29,8 +28,6 @@ type Conn struct {
readWaitOptions N.ReadWaitOptions
kernelTx bool
kernelRx bool
kernelDidRead bool
kernelDidWrite bool
}
func NewConn(ctx context.Context, logger logger.ContextLogger, conn aTLS.Conn, txOffload, rxOffload bool) (aTLS.Conn, error) {
@ -64,7 +61,7 @@ func NewConn(ctx context.Context, logger logger.ContextLogger, conn aTLS.Conn, t
for rawConn.Hand.Len() > 0 {
err = rawConn.HandlePostHandshakeMessage()
if err != nil {
return nil, E.Cause(err, "ktls: failed to handle post-handshake messages")
return nil, E.Cause(err, "handle post-handshake messages")
}
}
}
@ -85,36 +82,15 @@ func NewConn(ctx context.Context, logger logger.ContextLogger, conn aTLS.Conn, t
}
func (c *Conn) Upstream() any {
return c.conn
}
func (c *Conn) ReaderReplaceable() bool {
if !c.kernelRx {
return true
}
c.rawConn.In.Lock()
defer c.rawConn.In.Unlock()
return !c.kernelDidRead
}
func (c *Conn) WriterReplaceable() bool {
if !c.kernelTx {
return true
}
/*c.rawConn.Out.Lock()
defer c.rawConn.Out.Unlock()
return !c.kernelDidWrite*/
return true
return c.Conn
}
func (c *Conn) SyscallConnForRead() syscall.Conn {
if !c.kernelRx {
return nil
}
c.rawConn.In.Lock()
defer c.rawConn.In.Unlock()
if c.kernelDidRead {
c.logger.DebugContext(c.ctx, "ktls: RX splice not possible, since did read from user space")
if !*c.rawConn.IsClient {
c.logger.WarnContext(c.ctx, "ktls: RX splice is unavailable on the server size, since it will cause an unknown failure")
return nil
}
c.logger.DebugContext(c.ctx, "ktls: RX splice requested")
@ -125,13 +101,6 @@ func (c *Conn) SyscallConnForWrite() syscall.Conn {
if !c.kernelTx {
return nil
}
/*c.rawConn.Out.Lock()
defer c.rawConn.Out.Unlock()
if c.kernelDidWrite {
c.logger.DebugContext(c.ctx, "ktls: TX splice not possible, since did write from user space")
return nil
}
*/
c.logger.DebugContext(c.ctx, "ktls: TX splice requested")
return c.syscallConn
}

View File

@ -12,11 +12,11 @@ import (
"syscall"
"unsafe"
"github.com/sagernet/sing-box/common/badversion"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/shell"
"github.com/blang/semver/v4"
"golang.org/x/sys/unix"
)
@ -55,46 +55,42 @@ var KernelSupport = sync.OnceValues(func() (*Support, error) {
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 {
return nil, err
}
kernelVersion.Pre = nil
kernelVersion.Build = nil
var support Support
switch {
case kernelVersion.GTE(semver.Version{Major: 6, Minor: 14}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6, Minor: 14}):
support.TLS_Version13_KeyUpdate = true
fallthrough
case kernelVersion.GTE(semver.Version{Major: 6, Minor: 1}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6, Minor: 1}):
support.TLS_ARIA_GCM = true
fallthrough
case kernelVersion.GTE(semver.Version{Major: 6}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 6}):
support.TLS_Version13_RX = true
support.TLS_RX_NOPADDING = true
fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 19}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 19}):
support.TLS_TX_ZEROCOPY = true
fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 16}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 16}):
support.TLS_SM4 = true
fallthrough
case kernelVersion.GTE(semver.Version{Major: 5, Minor: 11}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 5, Minor: 11}):
support.TLS_CHACHA20_POLY1305 = true
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
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_Version13 = true
fallthrough
case kernelVersion.GTE(semver.Version{Major: 4, Minor: 17}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 4, Minor: 17}):
support.TLS_RX = true
fallthrough
case kernelVersion.GTE(semver.Version{Major: 4, Minor: 13}):
case kernelVersion.GreaterThanOrEqual(badversion.Version{Major: 4, Minor: 13}):
support.TLS = true
}
@ -118,7 +114,7 @@ var KernelSupport = sync.OnceValues(func() (*Support, error) {
func Load() error {
support, err := KernelSupport()
if err != nil {
return err
return E.Cause(err, "ktls: check availability")
}
if !support.TLS || !support.TLS_Version13 {
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()
if err != nil {
return err
return E.Cause(err, "check availability")
}
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()
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")
})
if err != nil {
return E.Cause(err, "initialize kernel TLS")
return os.NewSyscallError("setsockopt", err)
}
if txOffload {
txCrypto := kernelCipher(support, c.rawConn.Out, *c.rawConn.CipherSuite, false)
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 {
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 {
rxCrypto := kernelCipher(support, c.rawConn.In, *c.rawConn.CipherSuite, true)
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 {
return syscall.SetsockoptString(int(fd), unix.SOL_TLS, TLS_RX, rxCrypto.String())
@ -278,7 +274,6 @@ func (c *Conn) readKernelRecord() (uint8, []byte, error) {
default:
return 0, nil, err
}
c.kernelDidRead = true
if n <= 0 {
return 0, nil, io.EOF
@ -324,7 +319,6 @@ func (c *Conn) writeKernelRecord(typ uint16, data []byte) (int, error) {
if ew != nil {
return 0, ew
}
c.kernelDidWrite = true
return n, err
}

View File

@ -20,7 +20,12 @@ func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dial
if !options.Enabled {
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 {
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) {
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
}
if options.Reality != nil && options.Reality.Enabled {
return NewRealityClient(ctx, logger, serverAddress, options)
} else if options.UTLS != nil && options.UTLS.Enabled {
return NewUTLSClient(ctx, logger, serverAddress, options)
if !options.KTLSCompatible {
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 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) {

View File

@ -5,6 +5,7 @@ import (
"net"
"github.com/sagernet/sing-box/common/ktls"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
aTLS "github.com/sagernet/sing/common/tls"
)
@ -20,7 +21,12 @@ func (w *KTLSClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (
if err != nil {
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 {
@ -43,7 +49,12 @@ func (w *KTlSServerConfig) ServerHandshake(ctx context.Context, conn net.Conn) (
if err != nil {
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 {

View File

@ -12,14 +12,37 @@ import (
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) {
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
}
if options.Reality != nil && options.Reality.Enabled {
return NewRealityServer(ctx, logger, options)
if !options.KTLSCompatible {
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) {

View File

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

View File

@ -4,8 +4,13 @@ icon: material/alert-decagram
#### 1.13.0-alpha.9
* Add kTLS support **1**
* Fixes and improvements
**1**:
See [TLS](/configuration/shared/tls/).
#### 1.12.4
* Fixes and improvements

View File

@ -1,7 +1,12 @@
---
icon: material/alert-decagram
icon: material/new-box
---
!!! quote "Changes in sing-box 1.13.0"
:material-plus: [kernel_tx](#kernel_tx)
:material-plus: [kernel_rx](#kernel_rx)
!!! quote "Changes in sing-box 1.12.0"
:material-plus: [fragment](#fragment)
@ -28,6 +33,8 @@ icon: material/alert-decagram
"certificate_path": "",
"key": [],
"key_path": "",
"kernel_tx": false,
"kernel_rx": false,
"acme": {
"domain": [],
"data_directory": "",
@ -188,7 +195,8 @@ By default, the maximum version is currently TLS 1.3.
#### cipher_suites
A list of enabled TLS 1.01.2 cipher suites. The order of the list is ignored. Note that TLS 1.3 cipher suites are not configurable.
A list of enabled TLS 1.01.2 cipher suites. The order of the list is ignored.
Note that TLS 1.3 cipher suites are not configurable.
If empty, a safe default list is used. The default cipher suites might change over time.
@ -220,6 +228,50 @@ The server private key line array, in PEM format.
The path to the server private key, in PEM format.
#### kernel_tx
!!! question "Since sing-box 1.13.0"
!!! quote ""
Only supported on Linux 5.1+, use a newer kernel if possible.
!!! quote ""
Only TLS 1.3 is supported.
!!! warning ""
uTLS is compatible, but not other custom TLS.
!!! warning ""
kTLS TX may only improve performance when `splice(2)` is available (both ends must be TCP or TLS without additional protocols after handshake); otherwise, it will definitely degrade performance.
Enable kernel TLS transmit support.
#### kernel_rx
!!! question "Since sing-box 1.13.0"
!!! quote ""
Only supported on Linux 5.1+, use a newer kernel if possible.
!!! quote ""
Only TLS 1.3 is supported.
!!! warning ""
uTLS is compatible, but not other custom TLS.
!!! failure ""
kTLS RX will definitely degrade performance even if `splice(2)` is in use, so enabling it is not recommended.
Enable kernel TLS receive support.
## Custom TLS support
!!! info "QUIC support"

View File

@ -2,6 +2,11 @@
icon: material/alert-decagram
---
!!! quote "sing-box 1.13.0 中的更改"
:material-plus: [kernel_tx](#kernel_tx)
:material-plus: [kernel_rx](#kernel_rx)
!!! quote "sing-box 1.12.0 中的更改"
:material-plus: [tls_fragment](#tls_fragment)
@ -28,6 +33,8 @@ icon: material/alert-decagram
"certificate_path": "",
"key": [],
"key_path": "",
"kernel_tx": false,
"kernel_rx": false,
"acme": {
"domain": [],
"data_directory": "",
@ -216,6 +223,56 @@ TLS 版本值:
服务器 PEM 私钥路径。
#### kernel_tx
!!! question "自 sing-box 1.13.0 起"
!!! quote ""
仅支持 Linux 5.1+,如果可能,使用较新的内核。
!!! quote ""
仅支持 TLS 1.3。
!!! warning ""
兼容 uTLS但不兼容其他自定义 TLS。
!!! warning ""
kTLS TX 仅当 `splice(2)` 可用时(两端经过握手后必须为没有附加协议的 TCP 或 TLS才能提高性能否则肯定会降低性能。
启用内核 TLS 发送支持。
#### kernel_rx
!!! question "自 sing-box 1.13.0 起"
!!! quote ""
仅支持 Linux 5.1+,如果可能,使用较新的内核。
!!! quote ""
仅支持 TLS 1.3。
!!! warning ""
兼容 uTLS但不兼容其他自定义 TLS。
!!! failure ""
即使使用 `splice(2)`kTLS RX 也肯定会降低性能,因此不建议启用。
启用内核 TLS 接收支持。
## 自定义 TLS 支持
!!! info "QUIC 支持"
只有 ECH 在 QUIC 中被支持.
#### utls
==仅客户端==

3
go.mod
View File

@ -4,7 +4,6 @@ go 1.23.1
require (
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/coder/websocket v1.8.13
github.com/cretz/bine v0.2.0
@ -28,7 +27,7 @@ require (
github.com/sagernet/gomobile v0.1.8
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237
github.com/sagernet/quic-go v0.52.0-beta.1
github.com/sagernet/sing v0.7.8-0.20250908034727-1ceb6b183d75
github.com/sagernet/sing v0.7.8-0.20250908063931-beb351e61b89
github.com/sagernet/sing-mux v0.3.3
github.com/sagernet/sing-quic v0.5.2-0.20250908021228-186e280a524e
github.com/sagernet/sing-shadowsocks v0.2.8

6
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/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/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/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4=
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
@ -169,8 +167,8 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.7.8-0.20250908034727-1ceb6b183d75 h1:jc7lqbvND3htLpTeu6xPlhcVz01z7dEmikCZ46LmvxU=
github.com/sagernet/sing v0.7.8-0.20250908034727-1ceb6b183d75/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.7.8-0.20250908063931-beb351e61b89 h1:Of7kq85JItQmR4Y8m3L/DFFxaxyjK9rJvLMpmXPQ7g0=
github.com/sagernet/sing v0.7.8-0.20250908063931-beb351e61b89/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw=
github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
github.com/sagernet/sing-quic v0.5.2-0.20250908021228-186e280a524e h1:l+DICzp1OecGSDoiHE0Ebviaz3zqSp7XM27UcRbGkBM=

View File

@ -43,7 +43,12 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
authenticator: auth.NewAuthenticator(options.Users),
}
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 {
return nil, err
}

View File

@ -8,10 +8,12 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/inbound"
"github.com/sagernet/sing-box/common/listener"
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/common/uot"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network"
@ -33,6 +35,7 @@ type Inbound struct {
logger log.ContextLogger
listener *listener.Listener
authenticator *auth.Authenticator
tlsConfig tls.ServerConfig
}
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPMixedInboundOptions) (adapter.Inbound, error) {
@ -42,6 +45,18 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
logger: logger,
authenticator: auth.NewAuthenticator(options.Users),
}
if options.TLS != nil {
tlsConfig, err := tls.NewServerWithOptions(tls.ServerOptions{
Context: ctx,
Logger: logger,
Options: common.PtrValueOrDefault(options.TLS),
KTLSCompatible: true,
})
if err != nil {
return nil, err
}
inbound.tlsConfig = tlsConfig
}
inbound.listener = listener.New(listener.Options{
Context: ctx,
Logger: logger,
@ -58,11 +73,20 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateStart {
return nil
}
if h.tlsConfig != nil {
err := h.tlsConfig.Start()
if err != nil {
return E.Cause(err, "create TLS config")
}
}
return h.listener.Start()
}
func (h *Inbound) Close() error {
return h.listener.Close()
return common.Close(
h.listener,
h.tlsConfig,
)
}
func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
@ -78,6 +102,13 @@ func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata a
}
func (h *Inbound) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
if h.tlsConfig != nil {
tlsConn, err := tls.ServerHandshake(ctx, conn, h.tlsConfig)
if err != nil {
return E.Cause(err, "TLS handshake")
}
conn = tlsConn
}
reader := std_bufio.NewReader(conn)
headerBytes, err := reader.Peek(1)
if err != nil {

View File

@ -50,7 +50,13 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
users: options.Users,
}
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 {
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),
}
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 {
return nil, err
}

View File

@ -68,7 +68,16 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
}))
inbound.service = service
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 {
return nil, err
}

View File

@ -53,7 +53,15 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
serverAddr: options.ServerOptions.Build(),
}
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 {
return nil, err
}