From bb3ad9c694004353cb32b320d4da9a5194eb42d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 14 Apr 2026 16:00:47 +0800 Subject: [PATCH 01/20] documentation: Fix typo --- docs/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.md b/docs/changelog.md index 8e500b75..8f826099 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,7 +5,7 @@ icon: material/alert-decagram #### 1.13.8 * Update naiveproxy to v147.0.7727.49-1 -* Fix fake-ip DNS server should return SUCCESS when another address type is not configured +* Fix fake-ip DNS server should return SUCCESS when address type is not configured * Fixes and improvements #### 1.13.7 From 7ed5ef6da4d095616f869627163c311e00894f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 16 Apr 2026 00:27:14 +0800 Subject: [PATCH 02/20] sing: Fix udpnat2 timeout --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5aec4dba..736336e9 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/gomobile v0.1.12 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 - github.com/sagernet/sing v0.8.4 + github.com/sagernet/sing v0.8.6 github.com/sagernet/sing-mux v0.3.4 github.com/sagernet/sing-quic v0.6.1 github.com/sagernet/sing-shadowsocks v0.2.8 diff --git a/go.sum b/go.sum index 26f9d0e2..e56d9d70 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,8 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= -github.com/sagernet/sing v0.8.4 h1:Fj+jlY3F8vhcRfz/G/P3Dwcs5wqnmyNPT7u1RVVmjFI= -github.com/sagernet/sing v0.8.4/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.8.6 h1:9rAYgDzNkjHkdMnmyOVQr1SR+U8QvUojBcmAdAK0Mkw= +github.com/sagernet/sing v0.8.6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= github.com/sagernet/sing-quic v0.6.1 h1:lx0tcm99wIA1RkyvILNzRSsMy1k7TTQYIhx71E/WBlw= From 9b155ba467945eb91cf42426b178abbad9949e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 16 Apr 2026 16:08:44 +0800 Subject: [PATCH 03/20] Fix rdrc cache --- experimental/cachefile/rdrc.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/experimental/cachefile/rdrc.go b/experimental/cachefile/rdrc.go index d27ea8b2..dde324c3 100644 --- a/experimental/cachefile/rdrc.go +++ b/experimental/cachefile/rdrc.go @@ -72,6 +72,9 @@ func (c *CacheFile) LoadRDRC(transportName string, qName string, qType uint16) ( } func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) error { + expiresAt := buf.Get(8) + defer buf.Put(expiresAt) + binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix())) return c.batch(func(tx *bbolt.Tx) error { bucket, err := c.createBucket(tx, bucketRDRC) if err != nil { @@ -85,9 +88,6 @@ func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) e binary.BigEndian.PutUint16(key, qType) copy(key[2:], qName) defer buf.Put(key) - expiresAt := buf.Get(8) - defer buf.Put(expiresAt) - binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix())) return bucket.Put(key, expiresAt) }) } From 0bd109d7bc75a92f1247e6728508f3ca62a2d04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 20:38:52 +0800 Subject: [PATCH 04/20] sing: Fix interface finder --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 736336e9..1be5d2d5 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/gomobile v0.1.12 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 - github.com/sagernet/sing v0.8.6 + github.com/sagernet/sing v0.8.7 github.com/sagernet/sing-mux v0.3.4 github.com/sagernet/sing-quic v0.6.1 github.com/sagernet/sing-shadowsocks v0.2.8 diff --git a/go.sum b/go.sum index e56d9d70..9c50a82f 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,8 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= -github.com/sagernet/sing v0.8.6 h1:9rAYgDzNkjHkdMnmyOVQr1SR+U8QvUojBcmAdAK0Mkw= -github.com/sagernet/sing v0.8.6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.8.7 h1:XQKFtGasfW9XmfRghZs7f6hLk/7vFCdqdY2ha8qGyDg= +github.com/sagernet/sing v0.8.7/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= github.com/sagernet/sing-quic v0.6.1 h1:lx0tcm99wIA1RkyvILNzRSsMy1k7TTQYIhx71E/WBlw= From ca76c5637762b5efa2c8f305d3ce6b5b2f82d250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 20:39:38 +0800 Subject: [PATCH 05/20] daemon: Fix registry leak --- daemon/instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/instance.go b/daemon/instance.go index 4ed74182..3acf75cc 100644 --- a/daemon/instance.go +++ b/daemon/instance.go @@ -69,7 +69,7 @@ type OverrideOptions struct { } func (s *StartedService) newInstance(profileContent string, overrideOptions *OverrideOptions) (*Instance, error) { - ctx := s.ctx + ctx := service.ExtendContext(s.ctx) service.MustRegister[deprecated.Manager](ctx, new(deprecatedManager)) ctx, cancel := context.WithCancel(include.Context(ctx)) options, err := parseConfig(ctx, profileContent) From 3a236d9c3c4530715c7b0fac0cb7f7ae2f9fb174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 20:41:33 +0800 Subject: [PATCH 06/20] fswatch: Fix close --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 1be5d2d5..96f46a1a 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/sagernet/cors v1.2.1 github.com/sagernet/cronet-go v0.0.0-20260413093659-e4926ba205fa github.com/sagernet/cronet-go/all v0.0.0-20260413093659-e4926ba205fa - github.com/sagernet/fswatch v0.1.1 + github.com/sagernet/fswatch v0.1.2 github.com/sagernet/gomobile v0.1.12 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 @@ -76,7 +76,7 @@ require ( github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect github.com/ebitengine/purego v0.9.1 // indirect github.com/florianl/go-nfqueue/v2 v2.0.2 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gaissmai/bart v0.18.0 // indirect github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect diff --git a/go.sum b/go.sum index 9c50a82f..ebb4d843 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/florianl/go-nfqueue/v2 v2.0.2 h1:FL5lQTeetgpCvac1TRwSfgaXUn0YSO7WzGvWNIp3JPE= github.com/florianl/go-nfqueue/v2 v2.0.2/go.mod h1:VA09+iPOT43OMoCKNfXHyzujQUty2xmzyCRkBOlmabc= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= @@ -224,8 +224,8 @@ github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260413092954-cd09eb3e27 github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260413092954-cd09eb3e271b/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8= github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260413092954-cd09eb3e271b h1:hy/3lPV11pKAAojDFnb95l9NpwOym6kME7FxS9p8sXs= github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260413092954-cd09eb3e271b/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw= -github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= -github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= +github.com/sagernet/fswatch v0.1.2 h1:/TT7k4mkce1qFPxamLO842WjqBgbTBiXP2mlUjp9PFk= +github.com/sagernet/fswatch v0.1.2/go.mod h1:5BpGmpUQVd3Mc5r313HRpvADHRg3/rKn5QbwFteB880= github.com/sagernet/gomobile v0.1.12 h1:XwzjZaclFF96deLqwAgK8gU3w0M2A8qxgDmhV+A0wjg= github.com/sagernet/gomobile v0.1.12/go.mod h1:A8l3FlHi2D/+mfcd4HHvk5DGFPW/ShFb9jHP5VmSiDY= github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 h1:AzCE2RhBjLJ4WIWc/GejpNh+z30d5H1hwaB0nD9eY3o= From a80ef94f090cb5024b5dd74304d003b462f4a9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 21:15:54 +0800 Subject: [PATCH 07/20] Fix tailscale endpoint early-start close panic --- protocol/tailscale/endpoint.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/protocol/tailscale/endpoint.go b/protocol/tailscale/endpoint.go index 33b76930..30db4b6a 100644 --- a/protocol/tailscale/endpoint.go +++ b/protocol/tailscale/endpoint.go @@ -110,6 +110,7 @@ type Endpoint struct { systemInterface bool systemInterfaceName string systemInterfaceMTU uint32 + serverStarted bool systemTun tun.Tun systemDialer *dialer.DefaultDialer fallbackTCPCloser func() @@ -365,6 +366,7 @@ func (t *Endpoint) postStart() error { } return err } + t.serverStarted = true if t.fallbackTCPCloser == nil { t.fallbackTCPCloser = t.server.RegisterFallbackTCPHandler(func(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) { return func(conn net.Conn) { @@ -482,7 +484,11 @@ func (t *Endpoint) watchState() { } func (t *Endpoint) Close() error { - err := common.Close(common.PtrOrNil(t.server)) + var err error + if t.serverStarted { + err = common.Close(common.PtrOrNil(t.server)) + t.serverStarted = false + } netmon.RegisterInterfaceGetter(nil) netns.SetControlFunc(nil) if t.fallbackTCPCloser != nil { From fb61987d9384b391932e75cda2f20aee2db9b823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 21:54:20 +0800 Subject: [PATCH 08/20] tun: memmod: be more resilient toward weird PE files --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 96f46a1a..2574e604 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,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.1-0.20250503051639-fcd445d33c11 - github.com/sagernet/sing-tun v0.8.7 + github.com/sagernet/sing-tun v0.8.8 github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 github.com/sagernet/smux v1.5.50-sing-box-mod.1 github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7 diff --git a/go.sum b/go.sum index ebb4d843..20270241 100644 --- a/go.sum +++ b/go.sum @@ -248,8 +248,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.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= -github.com/sagernet/sing-tun v0.8.7 h1:q49cI7Cbp+BcgzaJitQ9QdLO77BqnnaQRkSEMoGmF3g= -github.com/sagernet/sing-tun v0.8.7/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs= +github.com/sagernet/sing-tun v0.8.8 h1:cnEjNKUPiE3F20l4umFBaWxEjL4insMiNFxwaXqooEc= +github.com/sagernet/sing-tun v0.8.8/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY= github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478= From 9b72b352d59a05835315cf9c03c6874b4c339690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 20 Apr 2026 00:10:46 +0800 Subject: [PATCH 09/20] sing: Fix UoT connect race --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2574e604..099f3359 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/gomobile v0.1.12 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 - github.com/sagernet/sing v0.8.7 + github.com/sagernet/sing v0.8.8 github.com/sagernet/sing-mux v0.3.4 github.com/sagernet/sing-quic v0.6.1 github.com/sagernet/sing-shadowsocks v0.2.8 diff --git a/go.sum b/go.sum index 20270241..e83f7537 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,8 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= -github.com/sagernet/sing v0.8.7 h1:XQKFtGasfW9XmfRghZs7f6hLk/7vFCdqdY2ha8qGyDg= -github.com/sagernet/sing v0.8.7/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.8.8 h1:1dRlGJ3wm4d2nwjKI1R/dr/7GKDKgUvXyD4OAWlQyt8= +github.com/sagernet/sing v0.8.8/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= github.com/sagernet/sing-quic v0.6.1 h1:lx0tcm99wIA1RkyvILNzRSsMy1k7TTQYIhx71E/WBlw= From b3606e33a615acd88777ff415bb3d01b8587e3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 22:45:54 +0800 Subject: [PATCH 10/20] release: fix apk package file ownership --- .github/build_alpine_apk.sh | 17 +++++++++++++++-- .github/build_openwrt_apk.sh | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/.github/build_alpine_apk.sh b/.github/build_alpine_apk.sh index aaaa04f9..610103b5 100755 --- a/.github/build_alpine_apk.sh +++ b/.github/build_alpine_apk.sh @@ -2,6 +2,18 @@ set -e -o pipefail +prepare_apk_root() { + # apk mkpkg resolves owner/group names through --root/etc/{passwd,group}. + APK_ROOT_DIR=$(mktemp -d) + mkdir -p "$APK_ROOT_DIR/etc" + cat > "$APK_ROOT_DIR/etc/passwd" < "$APK_ROOT_DIR/etc/group" < "$PACKAGES_DIR/.conffiles_static" | sort > "$PACKAGES_DIR/.list" # Build APK -apk mkpkg \ +apk --root "$APK_ROOT_DIR" mkpkg \ --info "name:sing-box" \ --info "version:${APK_VERSION}" \ --info "description:The universal proxy platform." \ diff --git a/.github/build_openwrt_apk.sh b/.github/build_openwrt_apk.sh index 49e1c131..59f07fd8 100755 --- a/.github/build_openwrt_apk.sh +++ b/.github/build_openwrt_apk.sh @@ -2,6 +2,18 @@ set -e -o pipefail +prepare_apk_root() { + # apk mkpkg resolves owner/group names through --root/etc/{passwd,group}. + APK_ROOT_DIR=$(mktemp -d) + mkdir -p "$APK_ROOT_DIR/etc" + cat > "$APK_ROOT_DIR/etc/passwd" < "$APK_ROOT_DIR/etc/group" < "$PACKAGES_DIR/.conffiles_static" | sort > "$PACKAGES_DIR/.list" # Build APK -apk mkpkg \ +apk --root "$APK_ROOT_DIR" mkpkg \ --info "name:sing-box" \ --info "version:${APK_VERSION}" \ --info "description:The universal proxy platform." \ From 3124cdd6619d0b5d3fd223efbb8170bf404eb101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 23:45:12 +0800 Subject: [PATCH 11/20] Fix windows bssid matching --- adapter/network.go | 21 +++++++++++++++++++++ route/network.go | 1 + route/rule/rule_item_wifi_bssid.go | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/adapter/network.go b/adapter/network.go index dd53b2b4..14fe46c8 100644 --- a/adapter/network.go +++ b/adapter/network.go @@ -1,6 +1,9 @@ package adapter import ( + "encoding/hex" + "net" + "strings" "time" C "github.com/sagernet/sing-box/constant" @@ -51,6 +54,24 @@ type WIFIState struct { BSSID string } +func NormalizeWIFIBSSID(bssid string) string { + bssid = strings.TrimSpace(bssid) + if bssid == "" { + return "" + } + parsed, err := net.ParseMAC(bssid) + if err == nil && len(parsed) == 6 { + return parsed.String() + } + if len(bssid) == 12 { + decoded, err := hex.DecodeString(bssid) + if err == nil { + return net.HardwareAddr(decoded).String() + } + } + return bssid +} + type NetworkInterface struct { control.Interface Type C.InterfaceType diff --git a/route/network.go b/route/network.go index b8eefdc0..03e94879 100644 --- a/route/network.go +++ b/route/network.go @@ -424,6 +424,7 @@ func (r *NetworkManager) WIFIState() adapter.WIFIState { } func (r *NetworkManager) onWIFIStateChanged(state adapter.WIFIState) { + state.BSSID = adapter.NormalizeWIFIBSSID(state.BSSID) r.wifiStateMutex.Lock() if state != r.wifiState { r.wifiState = state diff --git a/route/rule/rule_item_wifi_bssid.go b/route/rule/rule_item_wifi_bssid.go index 8f887322..703562ba 100644 --- a/route/rule/rule_item_wifi_bssid.go +++ b/route/rule/rule_item_wifi_bssid.go @@ -18,7 +18,7 @@ type WIFIBSSIDItem struct { func NewWIFIBSSIDItem(networkManager adapter.NetworkManager, bssidList []string) *WIFIBSSIDItem { bssidMap := make(map[string]bool) for _, bssid := range bssidList { - bssidMap[bssid] = true + bssidMap[adapter.NormalizeWIFIBSSID(bssid)] = true } return &WIFIBSSIDItem{ bssidList, From e4bc459975deb09e06c17e96df4c4c33760feb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 23:25:00 +0800 Subject: [PATCH 12/20] Skip process search for non-local source addresses --- route/process_cache.go | 58 ++++++++++++++++++++++++++++++++++++++++++ route/route.go | 32 +---------------------- 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/route/process_cache.go b/route/process_cache.go index 691a4e8e..01b477c4 100644 --- a/route/process_cache.go +++ b/route/process_cache.go @@ -3,6 +3,7 @@ package route import ( "context" "net/netip" + "strings" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/process" @@ -32,3 +33,60 @@ func (r *Router) findProcessInfoCached(ctx context.Context, network string, sour r.processCache.Add(key, processCacheEntry{result: result, err: err}) return result, err } + +func (r *Router) searchProcessInfo(ctx context.Context, metadata *adapter.InboundContext) { + if r.processSearcher == nil || metadata.ProcessInfo != nil || !r.isLocalSource(metadata.Source.Addr) { + return + } + var originDestination netip.AddrPort + if metadata.OriginDestination.IsValid() { + originDestination = metadata.OriginDestination.AddrPort() + } else if metadata.Destination.IsIP() { + originDestination = metadata.Destination.AddrPort() + } + processInfo, err := r.findProcessInfoCached(ctx, metadata.Network, metadata.Source.AddrPort(), originDestination) + if err != nil { + r.logger.InfoContext(ctx, "failed to search process: ", err) + return + } + metadata.ProcessInfo = processInfo + if processInfo.ProcessPath != "" { + if processInfo.UserName != "" { + r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath, ", user: ", processInfo.UserName) + } else if processInfo.UserId != -1 { + r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath, ", user id: ", processInfo.UserId) + } else { + r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath) + } + return + } + if len(processInfo.AndroidPackageNames) > 0 { + r.logger.InfoContext(ctx, "found package name: ", strings.Join(processInfo.AndroidPackageNames, ", ")) + return + } + if processInfo.UserId != -1 { + if processInfo.UserName != "" { + r.logger.InfoContext(ctx, "found user: ", processInfo.UserName) + } else { + r.logger.InfoContext(ctx, "found user id: ", processInfo.UserId) + } + } +} + +func (r *Router) isLocalSource(source netip.Addr) bool { + if !source.IsValid() { + return false + } + source = source.Unmap() + if source.IsLoopback() { + return true + } + for _, netInterface := range r.network.InterfaceFinder().Interfaces() { + for _, prefix := range netInterface.Addresses { + if prefix.Addr().Unmap() == source { + return true + } + } + } + return false +} diff --git a/route/route.go b/route/route.go index 77b66ea4..7c24219e 100644 --- a/route/route.go +++ b/route/route.go @@ -407,37 +407,7 @@ func (r *Router) matchRule( selectedRule adapter.Rule, selectedRuleIndex int, buffers []*buf.Buffer, packetBuffers []*N.PacketBuffer, fatalErr error, ) { - if r.processSearcher != nil && metadata.ProcessInfo == nil { - var originDestination netip.AddrPort - if metadata.OriginDestination.IsValid() { - originDestination = metadata.OriginDestination.AddrPort() - } else if metadata.Destination.IsIP() { - originDestination = metadata.Destination.AddrPort() - } - processInfo, fErr := r.findProcessInfoCached(ctx, metadata.Network, metadata.Source.AddrPort(), originDestination) - if fErr != nil { - r.logger.InfoContext(ctx, "failed to search process: ", fErr) - } else { - if processInfo.ProcessPath != "" { - if processInfo.UserName != "" { - r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath, ", user: ", processInfo.UserName) - } else if processInfo.UserId != -1 { - r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath, ", user id: ", processInfo.UserId) - } else { - r.logger.InfoContext(ctx, "found process path: ", processInfo.ProcessPath) - } - } else if len(processInfo.AndroidPackageNames) > 0 { - r.logger.InfoContext(ctx, "found package name: ", strings.Join(processInfo.AndroidPackageNames, ", ")) - } else if processInfo.UserId != -1 { - if processInfo.UserName != "" { - r.logger.InfoContext(ctx, "found user: ", processInfo.UserName) - } else { - r.logger.InfoContext(ctx, "found user id: ", processInfo.UserId) - } - } - metadata.ProcessInfo = processInfo - } - } + r.searchProcessInfo(ctx, metadata) if metadata.Destination.Addr.IsValid() && r.dnsTransport.FakeIP() != nil && r.dnsTransport.FakeIP().Store().Contains(metadata.Destination.Addr) { domain, loaded := r.dnsTransport.FakeIP().Store().Lookup(metadata.Destination.Addr) if !loaded { From 60dd7ea5c9f9503440861af913dce0f37d4a517d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Apr 2026 23:25:00 +0800 Subject: [PATCH 13/20] Simplify lifecycle logs --- adapter/endpoint/manager.go | 7 +++---- adapter/inbound/manager.go | 7 +++---- adapter/lifecycle.go | 11 +++++++++-- adapter/outbound/manager.go | 11 +++++------ adapter/service/manager.go | 7 +++---- box.go | 6 +++--- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/adapter/endpoint/manager.go b/adapter/endpoint/manager.go index 8b7c287f..7d7aa4bc 100644 --- a/adapter/endpoint/manager.go +++ b/adapter/endpoint/manager.go @@ -12,7 +12,6 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" ) var _ adapter.EndpointManager = (*Manager)(nil) @@ -55,7 +54,7 @@ func (m *Manager) Start(stage adapter.StartStage) error { if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } return nil } @@ -80,7 +79,7 @@ func (m *Manager) Close() error { return E.Cause(err, "close ", name) }) monitor.Finish() - m.logger.Trace("close ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, "close ", name) } return nil } @@ -137,7 +136,7 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } if existsEndpoint, loaded := m.endpointByTag[tag]; loaded { diff --git a/adapter/inbound/manager.go b/adapter/inbound/manager.go index 438c20f4..2d1b0d2e 100644 --- a/adapter/inbound/manager.go +++ b/adapter/inbound/manager.go @@ -12,7 +12,6 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" ) var _ adapter.InboundManager = (*Manager)(nil) @@ -54,7 +53,7 @@ func (m *Manager) Start(stage adapter.StartStage) error { if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } return nil } @@ -79,7 +78,7 @@ func (m *Manager) Close() error { return E.Cause(err, "close ", name) }) monitor.Finish() - m.logger.Trace("close ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, "close ", name) } return nil } @@ -139,7 +138,7 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } if existsInbound, loaded := m.inboundByTag[tag]; loaded { diff --git a/adapter/lifecycle.go b/adapter/lifecycle.go index b969c98a..ebc0a303 100644 --- a/adapter/lifecycle.go +++ b/adapter/lifecycle.go @@ -83,7 +83,7 @@ func Start(logger log.ContextLogger, stage StartStage, services ...Lifecycle) er if err != nil { return err } - logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + LogElapsed(logger, startTime, stage, " ", name) } return nil } @@ -96,7 +96,14 @@ func StartNamed(logger log.ContextLogger, stage StartStage, services []Lifecycle if err != nil { return E.Cause(err, stage.String(), " ", service.Name()) } - logger.Trace(stage, " ", service.Name(), " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + LogElapsed(logger, startTime, stage, " ", service.Name()) } return nil } + +func LogElapsed(logger log.ContextLogger, startTime time.Time, description ...any) { + duration := time.Since(startTime) + if duration > time.Second { + logger.Trace(append(description, " completed (", F.Seconds(duration.Seconds()), "s)")...) + } +} diff --git a/adapter/outbound/manager.go b/adapter/outbound/manager.go index 5c1b5d99..287f1a91 100644 --- a/adapter/outbound/manager.go +++ b/adapter/outbound/manager.go @@ -14,7 +14,6 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/logger" ) @@ -90,7 +89,7 @@ func (m *Manager) Start(stage adapter.StartStage) error { if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } return nil @@ -125,7 +124,7 @@ func (m *Manager) startOutbounds(outbounds []adapter.Outbound) error { if err != nil { return E.Cause(err, "start ", name) } - m.logger.Trace("start ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, "start ", name) } else if starter, isStarter := outboundToStart.(interface { Start() error }); isStarter { @@ -137,7 +136,7 @@ func (m *Manager) startOutbounds(outbounds []adapter.Outbound) error { if err != nil { return E.Cause(err, "start ", name) } - m.logger.Trace("start ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, "start ", name) } } if len(started) == len(outbounds) { @@ -192,7 +191,7 @@ func (m *Manager) Close() error { return E.Cause(err, "close ", name) }) monitor.Finish() - m.logger.Trace("close ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, "close ", name) } } return nil @@ -281,7 +280,7 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } m.access.Lock() diff --git a/adapter/service/manager.go b/adapter/service/manager.go index f17aa07e..8ae961de 100644 --- a/adapter/service/manager.go +++ b/adapter/service/manager.go @@ -12,7 +12,6 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" ) var _ adapter.ServiceManager = (*Manager)(nil) @@ -52,7 +51,7 @@ func (m *Manager) Start(stage adapter.StartStage) error { if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } return nil } @@ -77,7 +76,7 @@ func (m *Manager) Close() error { return E.Cause(err, "close ", name) }) monitor.Finish() - m.logger.Trace("close ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, "close ", name) } return nil } @@ -134,7 +133,7 @@ func (m *Manager) Create(ctx context.Context, logger log.ContextLogger, tag stri if err != nil { return E.Cause(err, stage, " ", name) } - m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } if existsService, loaded := m.serviceByTag[tag]; loaded { diff --git a/box.go b/box.go index a72884e0..549f2fe0 100644 --- a/box.go +++ b/box.go @@ -520,7 +520,7 @@ func (s *Box) Close() error { err = E.Append(err, closeItem.service.Close(), func(err error) error { return E.Cause(err, "close ", closeItem.name) }) - s.logger.Trace("close ", closeItem.name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(s.logger, startTime, "close ", closeItem.name) } for _, lifecycleService := range s.internalService { s.logger.Trace("close ", lifecycleService.Name()) @@ -528,14 +528,14 @@ func (s *Box) Close() error { err = E.Append(err, lifecycleService.Close(), func(err error) error { return E.Cause(err, "close ", lifecycleService.Name()) }) - s.logger.Trace("close ", lifecycleService.Name(), " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(s.logger, startTime, "close ", lifecycleService.Name()) } s.logger.Trace("close logger") startTime := time.Now() err = E.Append(err, s.logFactory.Close(), func(err error) error { return E.Cause(err, "close logger") }) - s.logger.Trace("close logger completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") + adapter.LogElapsed(s.logger, startTime, "close logger") return err } From b3523abad54b25347cc6bfa1db5db5eb37b38c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 20 Apr 2026 07:42:16 +0800 Subject: [PATCH 14/20] tun: Fix multi include/exclude interfaces --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 099f3359..38f33d5a 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,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.1-0.20250503051639-fcd445d33c11 - github.com/sagernet/sing-tun v0.8.8 + github.com/sagernet/sing-tun v0.8.9 github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 github.com/sagernet/smux v1.5.50-sing-box-mod.1 github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7 @@ -135,7 +135,7 @@ require ( github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260413092954-cd09eb3e271b // indirect github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260413092954-cd09eb3e271b // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect - github.com/sagernet/nftables v0.3.0-beta.4 // indirect + github.com/sagernet/nftables v0.3.0-mod.2 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect diff --git a/go.sum b/go.sum index e83f7537..b03c857a 100644 --- a/go.sum +++ b/go.sum @@ -232,8 +232,8 @@ github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 h1:AzCE2RhBjLJ4WIWc/ github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1/go.mod h1:NJKBtm9nVEK3iyOYWsUlrDQuoGh4zJ4KOPhSYVidvQ4= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= -github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= +github.com/sagernet/nftables v0.3.0-mod.2 h1:ck2KMU02OxL1eDFgGaWYglMDpoOZ7OHzxje+vW5Q0OQ= +github.com/sagernet/nftables v0.3.0-mod.2/go.mod h1:8kslHG4VvYNihcco+i6uxIX7qbT8A56T0y5q7U44ZaQ= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= github.com/sagernet/sing v0.8.8 h1:1dRlGJ3wm4d2nwjKI1R/dr/7GKDKgUvXyD4OAWlQyt8= @@ -248,8 +248,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.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= -github.com/sagernet/sing-tun v0.8.8 h1:cnEjNKUPiE3F20l4umFBaWxEjL4insMiNFxwaXqooEc= -github.com/sagernet/sing-tun v0.8.8/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs= +github.com/sagernet/sing-tun v0.8.9 h1:ixFKKUGdVcJl4wb0xbL36hobiw9l6DIH497EQf5ILpM= +github.com/sagernet/sing-tun v0.8.9/go.mod h1:QvarqUtHfj1ULaRR+6kZOS/OoCE+pYGq67A5tyIy+dQ= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o= github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY= github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478= From c3de6a25fbe1fca4d0313109e91b07af28937b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 20 Apr 2026 07:43:55 +0800 Subject: [PATCH 15/20] documentation: Remove warp ads --- README.md | 8 -------- docs/sponsors.md | 6 ------ 2 files changed, 14 deletions(-) diff --git a/README.md b/README.md index 90be2a83..7b1c833a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,3 @@ -> Sponsored by [Warp](https://go.warp.dev/sing-box), built for coding with multiple AI agents - - -Warp sponsorship - - ---- - # sing-box The universal proxy platform. diff --git a/docs/sponsors.md b/docs/sponsors.md index 33898928..4e4dd07c 100644 --- a/docs/sponsors.md +++ b/docs/sponsors.md @@ -11,12 +11,6 @@ the project maintainer via [GitHub Sponsors](https://github.com/sponsors/nekohas ![](https://nekohasekai.github.io/sponsor-images/sponsors.svg) -## Commercial Sponsors - -> [Warp](https://go.warp.dev/sing-box), Built for coding with multiple AI agents. - -[![](https://github.com/warpdotdev/brand-assets/raw/refs/heads/main/Github/Sponsor/Warp-Github-LG-02.png)](https://go.warp.dev/sing-box) - ## Special Sponsors > Viral Tech, Inc. From d942ecc90474c600c30bd00ecce822ac91b7643d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 20 Apr 2026 07:42:45 +0800 Subject: [PATCH 16/20] Bump version 1.13.9 --- clients/android | 2 +- clients/apple | 2 +- docs/changelog.md | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clients/android b/clients/android index ab099186..67a19777 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit ab09918615e3fbfb6f2f17a06f1b49448dcccbb1 +Subproject commit 67a19777ce5787843f40fc8bc8b83fe6a1274fa0 diff --git a/clients/apple b/clients/apple index ad7434d6..43a2bf46 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit ad7434d6769382a9b9e6919fb925840f5cabe43e +Subproject commit 43a2bf467fb31e303b7dc988d87ad3ea77608405 diff --git a/docs/changelog.md b/docs/changelog.md index 8f826099..096b7228 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,10 @@ icon: material/alert-decagram --- +#### 1.13.9 + +* Fixes and improvements + #### 1.13.8 * Update naiveproxy to v147.0.7727.49-1 From 71f6a2ab4ebc2cbf3664e35e8be1e2a07e984abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 21 Apr 2026 15:23:05 +0800 Subject: [PATCH 17/20] Fix process search skipped for TUN --- common/dialer/default_parallel_interface.go | 6 ++++++ experimental/libbox/service.go | 5 +---- route/rule/rule_network_interface_address.go | 4 ++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/common/dialer/default_parallel_interface.go b/common/dialer/default_parallel_interface.go index ca374b2e..eafab75a 100644 --- a/common/dialer/default_parallel_interface.go +++ b/common/dialer/default_parallel_interface.go @@ -184,6 +184,12 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene func selectInterfaces(networkManager adapter.NetworkManager, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType) (primaryInterfaces []adapter.NetworkInterface, fallbackInterfaces []adapter.NetworkInterface) { interfaces := networkManager.NetworkInterfaces() + myInterface := networkManager.InterfaceMonitor().MyInterface() + if myInterface != "" { + interfaces = common.Filter(interfaces, func(it adapter.NetworkInterface) bool { + return it.Name != myInterface + }) + } switch strategy { case C.NetworkStrategyDefault: if len(interfaceType) == 0 { diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index 0a841a1b..7d0b3004 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -103,14 +103,11 @@ func (w *platformInterfaceWrapper) NetworkInterfaces() ([]adapter.NetworkInterfa } var interfaces []adapter.NetworkInterface for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) { - if netInterface.Name == w.myTunName { - continue - } w.defaultInterfaceAccess.Lock() // (GOOS=windows) SA4006: this value of `isDefault` is never used // Why not used? //nolint:staticcheck - isDefault := w.defaultInterface != nil && int(netInterface.Index) == w.defaultInterface.Index + isDefault := netInterface.Name != w.myTunName && w.defaultInterface != nil && int(netInterface.Index) == w.defaultInterface.Index w.defaultInterfaceAccess.Unlock() interfaces = append(interfaces, adapter.NetworkInterface{ Interface: control.Interface{ diff --git a/route/rule/rule_network_interface_address.go b/route/rule/rule_network_interface_address.go index c699c593..135a703e 100644 --- a/route/rule/rule_network_interface_address.go +++ b/route/rule/rule_network_interface_address.go @@ -40,9 +40,13 @@ func NewNetworkInterfaceAddressItem(networkManager adapter.NetworkManager, inter func (r *NetworkInterfaceAddressItem) Match(metadata *adapter.InboundContext) bool { interfaces := r.networkManager.NetworkInterfaces() + myInterface := r.networkManager.InterfaceMonitor().MyInterface() match: for ifType, addresses := range r.interfaceAddresses { for _, networkInterface := range interfaces { + if networkInterface.Name == myInterface { + continue + } if networkInterface.Type != ifType { continue } From 83d3a6d4e1ee88dc6731410ce4cc18add9f71642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 21 Apr 2026 17:15:16 +0800 Subject: [PATCH 18/20] Hide lifecycle logs for fast operations --- adapter/endpoint/manager.go | 16 ++++++---------- adapter/inbound/manager.go | 16 ++++++---------- adapter/lifecycle.go | 25 +++++++++++++++---------- adapter/outbound/manager.go | 26 ++++++++++---------------- adapter/service/manager.go | 16 ++++++---------- box.go | 15 ++++++--------- 6 files changed, 49 insertions(+), 65 deletions(-) diff --git a/adapter/endpoint/manager.go b/adapter/endpoint/manager.go index 7d7aa4bc..535c31b4 100644 --- a/adapter/endpoint/manager.go +++ b/adapter/endpoint/manager.go @@ -4,7 +4,6 @@ import ( "context" "os" "sync" - "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/taskmonitor" @@ -48,13 +47,12 @@ func (m *Manager) Start(stage adapter.StartStage) error { } for _, endpoint := range m.endpoints { name := "endpoint/" + endpoint.Type() + "[" + endpoint.Tag() + "]" - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err := adapter.LegacyStart(endpoint, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } return nil } @@ -72,14 +70,13 @@ func (m *Manager) Close() error { var err error for _, endpoint := range endpoints { name := "endpoint/" + endpoint.Type() + "[" + endpoint.Tag() + "]" - m.logger.Trace("close ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, "close ", name) monitor.Start("close ", name) err = E.Append(err, endpoint.Close(), func(err error) error { return E.Cause(err, "close ", name) }) monitor.Finish() - adapter.LogElapsed(m.logger, startTime, "close ", name) + done() } return nil } @@ -130,13 +127,12 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. if m.started { name := "endpoint/" + endpoint.Type() + "[" + endpoint.Tag() + "]" for _, stage := range adapter.ListStartStages { - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err = adapter.LegacyStart(endpoint, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } if existsEndpoint, loaded := m.endpointByTag[tag]; loaded { diff --git a/adapter/inbound/manager.go b/adapter/inbound/manager.go index 2d1b0d2e..d6567cde 100644 --- a/adapter/inbound/manager.go +++ b/adapter/inbound/manager.go @@ -4,7 +4,6 @@ import ( "context" "os" "sync" - "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/taskmonitor" @@ -47,13 +46,12 @@ func (m *Manager) Start(stage adapter.StartStage) error { m.access.Unlock() for _, inbound := range inbounds { name := "inbound/" + inbound.Type() + "[" + inbound.Tag() + "]" - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err := adapter.LegacyStart(inbound, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } return nil } @@ -71,14 +69,13 @@ func (m *Manager) Close() error { var err error for _, inbound := range inbounds { name := "inbound/" + inbound.Type() + "[" + inbound.Tag() + "]" - m.logger.Trace("close ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, "close ", name) monitor.Start("close ", name) err = E.Append(err, inbound.Close(), func(err error) error { return E.Cause(err, "close ", name) }) monitor.Finish() - adapter.LogElapsed(m.logger, startTime, "close ", name) + done() } return nil } @@ -132,13 +129,12 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. if m.started { name := "inbound/" + inbound.Type() + "[" + inbound.Tag() + "]" for _, stage := range adapter.ListStartStages { - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err = adapter.LegacyStart(inbound, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } if existsInbound, loaded := m.inboundByTag[tag]; loaded { diff --git a/adapter/lifecycle.go b/adapter/lifecycle.go index ebc0a303..2a6a8ed7 100644 --- a/adapter/lifecycle.go +++ b/adapter/lifecycle.go @@ -77,33 +77,38 @@ func getServiceName(service any) string { func Start(logger log.ContextLogger, stage StartStage, services ...Lifecycle) error { for _, service := range services { name := getServiceName(service) - logger.Trace(stage, " ", name) - startTime := time.Now() + done := LogElapsed(logger, stage, " ", name) err := service.Start(stage) + done() if err != nil { return err } - LogElapsed(logger, startTime, stage, " ", name) } return nil } func StartNamed(logger log.ContextLogger, stage StartStage, services []LifecycleService) error { for _, service := range services { - logger.Trace(stage, " ", service.Name()) - startTime := time.Now() + done := LogElapsed(logger, stage, " ", service.Name()) err := service.Start(stage) + done() if err != nil { return E.Cause(err, stage.String(), " ", service.Name()) } - LogElapsed(logger, startTime, stage, " ", service.Name()) } return nil } -func LogElapsed(logger log.ContextLogger, startTime time.Time, description ...any) { - duration := time.Since(startTime) - if duration > time.Second { - logger.Trace(append(description, " completed (", F.Seconds(duration.Seconds()), "s)")...) +func LogElapsed(logger log.ContextLogger, description ...any) func() { + prefix := F.ToString(description...) + startTime := time.Now() + timer := time.AfterFunc(time.Second, func() { + logger.Trace(prefix, "...") + }) + return func() { + if timer.Stop() { + return + } + logger.Trace(prefix, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)") } } diff --git a/adapter/outbound/manager.go b/adapter/outbound/manager.go index 287f1a91..1bbad69e 100644 --- a/adapter/outbound/manager.go +++ b/adapter/outbound/manager.go @@ -6,7 +6,6 @@ import ( "os" "strings" "sync" - "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/taskmonitor" @@ -83,13 +82,12 @@ func (m *Manager) Start(stage adapter.StartStage) error { m.access.Unlock() for _, outbound := range outbounds { name := "outbound/" + outbound.Type() + "[" + outbound.Tag() + "]" - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err := adapter.LegacyStart(outbound, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } return nil @@ -116,27 +114,25 @@ func (m *Manager) startOutbounds(outbounds []adapter.Outbound) error { canContinue = true name := "outbound/" + outboundToStart.Type() + "[" + outboundTag + "]" if starter, isStarter := outboundToStart.(adapter.Lifecycle); isStarter { - m.logger.Trace("start ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, "start ", name) monitor.Start("start ", name) err := starter.Start(adapter.StartStateStart) monitor.Finish() + done() if err != nil { return E.Cause(err, "start ", name) } - adapter.LogElapsed(m.logger, startTime, "start ", name) } else if starter, isStarter := outboundToStart.(interface { Start() error }); isStarter { - m.logger.Trace("start ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, "start ", name) monitor.Start("start ", name) err := starter.Start() monitor.Finish() + done() if err != nil { return E.Cause(err, "start ", name) } - adapter.LogElapsed(m.logger, startTime, "start ", name) } } if len(started) == len(outbounds) { @@ -184,14 +180,13 @@ func (m *Manager) Close() error { for _, outbound := range outbounds { if closer, isCloser := outbound.(io.Closer); isCloser { name := "outbound/" + outbound.Type() + "[" + outbound.Tag() + "]" - m.logger.Trace("close ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, "close ", name) monitor.Start("close ", name) err = E.Append(err, closer.Close(), func(err error) error { return E.Cause(err, "close ", name) }) monitor.Finish() - adapter.LogElapsed(m.logger, startTime, "close ", name) + done() } } return nil @@ -274,13 +269,12 @@ func (m *Manager) Create(ctx context.Context, router adapter.Router, logger log. if m.started { name := "outbound/" + outbound.Type() + "[" + outbound.Tag() + "]" for _, stage := range adapter.ListStartStages { - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err = adapter.LegacyStart(outbound, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } m.access.Lock() diff --git a/adapter/service/manager.go b/adapter/service/manager.go index 8ae961de..1a83c503 100644 --- a/adapter/service/manager.go +++ b/adapter/service/manager.go @@ -4,7 +4,6 @@ import ( "context" "os" "sync" - "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/taskmonitor" @@ -45,13 +44,12 @@ func (m *Manager) Start(stage adapter.StartStage) error { m.access.Unlock() for _, service := range services { name := "service/" + service.Type() + "[" + service.Tag() + "]" - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err := adapter.LegacyStart(service, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } return nil } @@ -69,14 +67,13 @@ func (m *Manager) Close() error { var err error for _, service := range services { name := "service/" + service.Type() + "[" + service.Tag() + "]" - m.logger.Trace("close ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, "close ", name) monitor.Start("close ", name) err = E.Append(err, service.Close(), func(err error) error { return E.Cause(err, "close ", name) }) monitor.Finish() - adapter.LogElapsed(m.logger, startTime, "close ", name) + done() } return nil } @@ -127,13 +124,12 @@ func (m *Manager) Create(ctx context.Context, logger log.ContextLogger, tag stri if m.started { name := "service/" + service.Type() + "[" + service.Tag() + "]" for _, stage := range adapter.ListStartStages { - m.logger.Trace(stage, " ", name) - startTime := time.Now() + done := adapter.LogElapsed(m.logger, stage, " ", name) err = adapter.LegacyStart(service, stage) + done() if err != nil { return E.Cause(err, stage, " ", name) } - adapter.LogElapsed(m.logger, startTime, stage, " ", name) } } if existsService, loaded := m.serviceByTag[tag]; loaded { diff --git a/box.go b/box.go index 549f2fe0..c88a9bc9 100644 --- a/box.go +++ b/box.go @@ -515,27 +515,24 @@ func (s *Box) Close() error { {"dns-transport", s.dnsTransport}, {"network", s.network}, } { - s.logger.Trace("close ", closeItem.name) - startTime := time.Now() + done := adapter.LogElapsed(s.logger, "close ", closeItem.name) err = E.Append(err, closeItem.service.Close(), func(err error) error { return E.Cause(err, "close ", closeItem.name) }) - adapter.LogElapsed(s.logger, startTime, "close ", closeItem.name) + done() } for _, lifecycleService := range s.internalService { - s.logger.Trace("close ", lifecycleService.Name()) - startTime := time.Now() + done := adapter.LogElapsed(s.logger, "close ", lifecycleService.Name()) err = E.Append(err, lifecycleService.Close(), func(err error) error { return E.Cause(err, "close ", lifecycleService.Name()) }) - adapter.LogElapsed(s.logger, startTime, "close ", lifecycleService.Name()) + done() } - s.logger.Trace("close logger") - startTime := time.Now() + done := adapter.LogElapsed(s.logger, "close logger") err = E.Append(err, s.logFactory.Close(), func(err error) error { return E.Cause(err, "close logger") }) - adapter.LogElapsed(s.logger, startTime, "close logger") + done() return err } From 8947cb243e453a60beb298676887427b59a20ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 21 Apr 2026 18:54:45 +0800 Subject: [PATCH 19/20] sing: Fix UoT write race --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 38f33d5a..2b7f9435 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/gomobile v0.1.12 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 - github.com/sagernet/sing v0.8.8 + github.com/sagernet/sing v0.8.9 github.com/sagernet/sing-mux v0.3.4 github.com/sagernet/sing-quic v0.6.1 github.com/sagernet/sing-shadowsocks v0.2.8 diff --git a/go.sum b/go.sum index b03c857a..ccb4c909 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,8 @@ github.com/sagernet/nftables v0.3.0-mod.2 h1:ck2KMU02OxL1eDFgGaWYglMDpoOZ7OHzxje github.com/sagernet/nftables v0.3.0-mod.2/go.mod h1:8kslHG4VvYNihcco+i6uxIX7qbT8A56T0y5q7U44ZaQ= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o= github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= -github.com/sagernet/sing v0.8.8 h1:1dRlGJ3wm4d2nwjKI1R/dr/7GKDKgUvXyD4OAWlQyt8= -github.com/sagernet/sing v0.8.8/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.8.9 h1:iX8FyMrWNl/divVgTe7cLT9n36v6bfzfnCYlcM1cLaU= +github.com/sagernet/sing v0.8.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= github.com/sagernet/sing-quic v0.6.1 h1:lx0tcm99wIA1RkyvILNzRSsMy1k7TTQYIhx71E/WBlw= From a3fc14f35f610de6d741912e80ccff925a5ff4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 21 Apr 2026 17:31:41 +0800 Subject: [PATCH 20/20] Bump version --- clients/android | 2 +- clients/apple | 2 +- docs/changelog.md | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/clients/android b/clients/android index 67a19777..a3f4ca31 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit 67a19777ce5787843f40fc8bc8b83fe6a1274fa0 +Subproject commit a3f4ca31d122756f36e8f41e5d3d8d676ba3e4dd diff --git a/clients/apple b/clients/apple index 43a2bf46..376f927c 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit 43a2bf467fb31e303b7dc988d87ad3ea77608405 +Subproject commit 376f927ccd943e369c3af0b3e845418137251524 diff --git a/docs/changelog.md b/docs/changelog.md index 096b7228..c6b0b585 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,10 @@ icon: material/alert-decagram --- +#### 1.13.10 + +* Fix process searcher failure introduced in 1.13.9 + #### 1.13.9 * Fixes and improvements