From 43a9016c8304a4a15d2206ac1d9a8293f000fa36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 6 Jun 2025 14:28:09 +0800 Subject: [PATCH 1/6] Fix leak in hijack-dns --- route/dns.go | 12 +++++++++++- route/route.go | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/route/dns.go b/route/dns.go index 2c6efefe..8d57c646 100644 --- a/route/dns.go +++ b/route/dns.go @@ -31,7 +31,7 @@ func (r *Router) hijackDNSStream(ctx context.Context, conn net.Conn, metadata ad } } -func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetBuffers []*N.PacketBuffer, metadata adapter.InboundContext) { +func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetBuffers []*N.PacketBuffer, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) { if natConn, isNatConn := conn.(udpnat.Conn); isNatConn { metadata.Destination = M.Socksaddr{} for _, packet := range packetBuffers { @@ -45,10 +45,12 @@ func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetB conn: conn, ctx: ctx, metadata: metadata, + onClose: onClose, }) return } err := dnsOutbound.NewDNSPacketConnection(ctx, r, conn, packetBuffers, metadata) + N.CloseOnHandshakeFailure(conn, onClose, err) if err != nil && !E.IsClosedOrCanceled(err) { r.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection")) } @@ -85,8 +87,16 @@ type dnsHijacker struct { conn N.PacketConn ctx context.Context metadata adapter.InboundContext + onClose N.CloseHandlerFunc } func (h *dnsHijacker) NewPacketEx(buffer *buf.Buffer, destination M.Socksaddr) { go ExchangeDNSPacket(h.ctx, h.router, h.conn, buffer, h.metadata, destination) } + +func (h *dnsHijacker) Close() error { + if h.onClose != nil { + h.onClose(nil) + } + return nil +} diff --git a/route/route.go b/route/route.go index d0f93e0b..d9bf2638 100644 --- a/route/route.go +++ b/route/route.go @@ -120,7 +120,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad for _, buffer := range buffers { conn = bufio.NewCachedConn(conn, buffer) } - r.hijackDNSStream(ctx, conn, metadata) + N.CloseOnHandshakeFailure(conn, onClose, r.hijackDNSStream(ctx, conn, metadata)) return nil } } @@ -233,7 +233,7 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx)) return nil case *rule.RuleActionHijackDNS: - r.hijackDNSPacket(ctx, conn, packetBuffers, metadata) + r.hijackDNSPacket(ctx, conn, packetBuffers, metadata, onClose) return nil } } From cb435ea232e399fb2e487b6d6dfb1ae6deb31c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 6 Jun 2025 14:50:38 +0800 Subject: [PATCH 2/6] Fix default network strategy --- common/dialer/default.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/dialer/default.go b/common/dialer/default.go index bd8d9018..ff524d08 100644 --- a/common/dialer/default.go +++ b/common/dialer/default.go @@ -100,10 +100,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial } else if networkManager.AutoDetectInterface() { if platformInterface != nil { networkStrategy = (*C.NetworkStrategy)(options.NetworkStrategy) - if networkStrategy == nil { - networkStrategy = common.Ptr(C.NetworkStrategyDefault) - defaultNetworkStrategy = true - } networkType = common.Map(options.NetworkType, option.InterfaceType.Build) fallbackNetworkType = common.Map(options.FallbackNetworkType, option.InterfaceType.Build) if networkStrategy == nil && len(networkType) == 0 && len(fallbackNetworkType) == 0 { @@ -115,6 +111,10 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial if networkFallbackDelay == 0 && defaultOptions.FallbackDelay != 0 { networkFallbackDelay = defaultOptions.FallbackDelay } + if networkStrategy == nil { + networkStrategy = common.Ptr(C.NetworkStrategyDefault) + defaultNetworkStrategy = true + } bindFunc := networkManager.ProtectFunc() dialer.Control = control.Append(dialer.Control, bindFunc) listener.Control = control.Append(listener.Control, bindFunc) From d511698f3f6f7d1a684e740202be202a5e65c1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 6 Jun 2025 14:39:40 +0800 Subject: [PATCH 3/6] Fix slowOpenConn --- common/dialer/tfo.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/common/dialer/tfo.go b/common/dialer/tfo.go index 9f72208d..8ea59ca6 100644 --- a/common/dialer/tfo.go +++ b/common/dialer/tfo.go @@ -10,9 +10,7 @@ import ( "sync" "time" - "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" - E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" @@ -26,7 +24,9 @@ type slowOpenConn struct { destination M.Socksaddr conn net.Conn create chan struct{} + done chan struct{} access sync.Mutex + closeOnce sync.Once err error } @@ -45,6 +45,7 @@ func DialSlowContext(dialer *tcpDialer, ctx context.Context, network string, des network: network, destination: destination, create: make(chan struct{}), + done: make(chan struct{}), }, nil } @@ -55,8 +56,8 @@ func (c *slowOpenConn) Read(b []byte) (n int, err error) { if c.err != nil { return 0, c.err } - case <-c.ctx.Done(): - return 0, c.ctx.Err() + case <-c.done: + return 0, os.ErrClosed } } return c.conn.Read(b) @@ -74,12 +75,15 @@ func (c *slowOpenConn) Write(b []byte) (n int, err error) { return 0, c.err } return c.conn.Write(b) + case <-c.done: + return 0, os.ErrClosed default: } - c.conn, err = c.dialer.DialContext(c.ctx, c.network, c.destination.String(), b) + conn, err := c.dialer.DialContext(c.ctx, c.network, c.destination.String(), b) if err != nil { - c.conn = nil - c.err = E.Cause(err, "dial tcp fast open") + c.err = err + } else { + c.conn = conn } n = len(b) close(c.create) @@ -87,7 +91,13 @@ func (c *slowOpenConn) Write(b []byte) (n int, err error) { } func (c *slowOpenConn) Close() error { - return common.Close(c.conn) + c.closeOnce.Do(func() { + close(c.done) + if c.conn != nil { + c.conn.Close() + } + }) + return nil } func (c *slowOpenConn) LocalAddr() net.Addr { @@ -152,8 +162,8 @@ func (c *slowOpenConn) WriteTo(w io.Writer) (n int64, err error) { if c.err != nil { return 0, c.err } - case <-c.ctx.Done(): - return 0, c.ctx.Err() + case <-c.done: + return 0, c.err } } return bufio.Copy(w, c.conn) From 2d1b824b62d622b2d40478259be98d0b33c7e2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 14 Jun 2025 16:11:15 +0800 Subject: [PATCH 4/6] Fix gLazyConn race --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f44affae..fca179a4 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowtls v0.2.0 - github.com/sagernet/sing-tun v0.6.5 + github.com/sagernet/sing-tun v0.6.8 github.com/sagernet/sing-vmess v0.2.3 github.com/sagernet/smux v1.5.34-mod.2 github.com/sagernet/utls v1.6.7 diff --git a/go.sum b/go.sum index 8d01ac3b..55f165d4 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk= github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo= -github.com/sagernet/sing-tun v0.6.5 h1:nGfD6GNq/r0tEjdZHOV3BS6fydSmd4kBAokU5rffssg= -github.com/sagernet/sing-tun v0.6.5/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= +github.com/sagernet/sing-tun v0.6.8 h1:tr+LKHe09C2I9GfNuB2vnzaZm+ekoNlAhLLrdiLjtAA= +github.com/sagernet/sing-tun v0.6.8/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= github.com/sagernet/sing-vmess v0.2.3 h1:z6Ym8dnZG7k1fP3+54vz8G0tvRVJeOoTFFeUPwXTD44= github.com/sagernet/sing-vmess v0.2.3/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= From 47f18e823aede34f08e0365935d92740261937e3 Mon Sep 17 00:00:00 2001 From: dyhkwong <50692134+dyhkwong@users.noreply.github.com> Date: Wed, 18 Jun 2025 08:34:59 +0800 Subject: [PATCH 5/6] Fix: macOS udp find process should use unspecified fallback https://github.com/Dreamacro/clash/commit/be8d63ba8f70a6f4e7b240899cd2903a77243c24 --- common/process/searcher_darwin.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/common/process/searcher_darwin.go b/common/process/searcher_darwin.go index 4344c706..16e2c87a 100644 --- a/common/process/searcher_darwin.go +++ b/common/process/searcher_darwin.go @@ -76,6 +76,8 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) { // rup8(sizeof(xtcpcb_n)) itemSize += 208 } + + var fallbackUDPProcess string // skip the first xinpgen(24 bytes) block for i := 24; i+itemSize <= len(buf); i += itemSize { // offset of xinpcb_n and xsocket_n @@ -90,10 +92,12 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) { flag := buf[inp+44] var srcIP netip.Addr + srcIsIPv4 := false switch { case flag&0x1 > 0 && isIPv4: // ipv4 srcIP = netip.AddrFrom4(*(*[4]byte)(buf[inp+76 : inp+80])) + srcIsIPv4 = true case flag&0x2 > 0 && !isIPv4: // ipv6 srcIP = netip.AddrFrom16(*(*[16]byte)(buf[inp+64 : inp+80])) @@ -101,13 +105,21 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) { continue } - if ip != srcIP { - continue + if ip == srcIP { + // xsocket_n.so_last_pid + pid := readNativeUint32(buf[so+68 : so+72]) + return getExecPathFromPID(pid) } - // xsocket_n.so_last_pid - pid := readNativeUint32(buf[so+68 : so+72]) - return getExecPathFromPID(pid) + // udp packet connection may be not equal with srcIP + if network == N.NetworkUDP && srcIP.IsUnspecified() && isIPv4 == srcIsIPv4 { + pid := readNativeUint32(buf[so+68 : so+72]) + fallbackUDPProcess, _ = getExecPathFromPID(pid) + } + } + + if network == N.NetworkUDP && len(fallbackUDPProcess) > 0 { + return fallbackUDPProcess, nil } return "", ErrNotFound From 9b8ab3e61e5b3a199fce5575bc6a04373f222d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 18 Jun 2025 21:39:12 +0800 Subject: [PATCH 6/6] Bump version --- clients/android | 2 +- docs/changelog.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/clients/android b/clients/android index 320170a1..eb2e13a6 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit 320170a1077ea5c93872b3e055b96b8836615ef0 +Subproject commit eb2e13a6f9a8c03a35ae672395ccab0a6bdcd954 diff --git a/docs/changelog.md b/docs/changelog.md index 71f261c9..8f995cfd 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,13 @@ icon: material/alert-decagram --- +### 1.11.14 + +* Fixes and improvements + +_We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we +violated the rules (TestFlight users are not affected)._ + ### 1.11.13 * Fixes and improvements