From 64843452bcdce6271652ad5b9e91ca74c676daf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 8 Sep 2025 19:02:48 +0800 Subject: [PATCH] ktls: Fix parse kernel version --- common/badversion/version.go | 42 ++++++++++++++++++++++++------- common/badversion/version_test.go | 10 ++++---- common/ktls/ktls.go | 2 +- common/ktls/ktls_linux.go | 40 +++++++++++++---------------- common/tls/ktls.go | 15 +++++++++-- go.mod | 1 - go.sum | 2 -- 7 files changed, 70 insertions(+), 42 deletions(-) diff --git a/common/badversion/version.go b/common/badversion/version.go index ccff02a6..4bcb5361 100644 --- a/common/badversion/version.go +++ b/common/badversion/version.go @@ -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:] diff --git a/common/badversion/version_test.go b/common/badversion/version_test.go index 9d6e8a7c..d6d5a73c 100644 --- a/common/badversion/version_test.go +++ b/common/badversion/version_test.go @@ -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"))) } diff --git a/common/ktls/ktls.go b/common/ktls/ktls.go index 86182c2e..36f36b25 100644 --- a/common/ktls/ktls.go +++ b/common/ktls/ktls.go @@ -61,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") } } } diff --git a/common/ktls/ktls_linux.go b/common/ktls/ktls_linux.go index ef493d4c..313fe381 100644 --- a/common/ktls/ktls_linux.go +++ b/common/ktls/ktls_linux.go @@ -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()) diff --git a/common/tls/ktls.go b/common/tls/ktls.go index 936b8365..dd564f53 100644 --- a/common/tls/ktls.go +++ b/common/tls/ktls.go @@ -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 { diff --git a/go.mod b/go.mod index 042a1ecb..e3b91e8c 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 01c0f962..ed625e3a 100644 --- a/go.sum +++ b/go.sum @@ -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=