From 58025a01f8091e114f79f2df6267d54682d3e572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 29 Jan 2026 12:07:15 +0800 Subject: [PATCH] Fix auto_redirect fallback rule --- docs/changelog.md | 8 ++++ docs/configuration/inbound/tun.md | 16 ++++++++ docs/configuration/inbound/tun.zh.md | 16 ++++++++ go.mod | 2 +- go.sum | 4 +- option/tun.go | 55 ++++++++++++++------------- protocol/tun/inbound.go | 57 +++++++++++++++------------- 7 files changed, 102 insertions(+), 56 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 305e0cff2..0ffc6087c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,8 +4,16 @@ icon: material/alert-decagram #### 1.12.18 +* Add fallback routing rule for `auto_redirect` **1** * Fixes and improvements +**1**: + +Adds a fallback iproute2 rule checked after system default rules (32766: main, 32767: default), +ensuring traffic is routed to the sing-box table when no route is found in system tables. + +The rule index can be customized via `auto_redirect_iproute2_fallback_rule_index` (default: 32768). + #### 1.12.17 * Update uTLS to v1.8.2 **1** diff --git a/docs/configuration/inbound/tun.md b/docs/configuration/inbound/tun.md index 92313c822..79ad9f1fd 100644 --- a/docs/configuration/inbound/tun.md +++ b/docs/configuration/inbound/tun.md @@ -2,6 +2,10 @@ icon: material/new-box --- +!!! quote "Changes in sing-box 1.12.18" + + :material-plus: [auto_redirect_iproute2_fallback_rule_index](#auto_redirect_iproute2_fallback_rule_index) + !!! quote "Changes in sing-box 1.12.0" :material-plus: [loopback_address](#loopback_address) @@ -63,6 +67,7 @@ icon: material/new-box "auto_redirect": true, "auto_redirect_input_mark": "0x2023", "auto_redirect_output_mark": "0x2024", + "auto_redirect_iproute2_fallback_rule_index": 32768, "loopback_address": [ "10.7.0.1" ], @@ -278,6 +283,17 @@ Connection output mark used by `auto_redirect`. `0x2024` is used by default. +#### auto_redirect_iproute2_fallback_rule_index + +!!! question "Since sing-box 1.12.18" + +Linux iproute2 fallback rule index generated by `auto_redirect`. + +This rule is checked after system default rules (32766: main, 32767: default), +routing traffic to the sing-box table only when no route is found in system tables. + +`32768` is used by default. + #### loopback_address !!! question "Since sing-box 1.12.0" diff --git a/docs/configuration/inbound/tun.zh.md b/docs/configuration/inbound/tun.zh.md index 9c0539991..4ba7aed74 100644 --- a/docs/configuration/inbound/tun.zh.md +++ b/docs/configuration/inbound/tun.zh.md @@ -2,6 +2,10 @@ icon: material/new-box --- +!!! quote "sing-box 1.12.18 中的更改" + + :material-plus: [auto_redirect_iproute2_fallback_rule_index](#auto_redirect_iproute2_fallback_rule_index) + !!! quote "sing-box 1.12.0 中的更改" :material-plus: [loopback_address](#loopback_address) @@ -63,6 +67,7 @@ icon: material/new-box "auto_redirect": true, "auto_redirect_input_mark": "0x2023", "auto_redirect_output_mark": "0x2024", + "auto_redirect_iproute2_fallback_rule_index": 32768, "loopback_address": [ "10.7.0.1" ], @@ -277,6 +282,17 @@ tun 接口的 IPv6 前缀。 默认使用 `0x2024`。 +#### auto_redirect_iproute2_fallback_rule_index + +!!! question "自 sing-box 1.12.18 起" + +`auto_redirect` 生成的 iproute2 回退规则索引。 + +此规则在系统默认规则(32766: main,32767: default)之后检查, +仅当系统路由表中未找到路由时才将流量路由到 sing-box 路由表。 + +默认使用 `32768`。 + #### loopback_address !!! question "自 sing-box 1.12.0 起" diff --git a/go.mod b/go.mod index 2c7ac263b..a3f2323a3 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.1-0.20250503051639-fcd445d33c11 - github.com/sagernet/sing-tun v0.7.8 + github.com/sagernet/sing-tun v0.7.9 github.com/sagernet/sing-vmess v0.2.7 github.com/sagernet/smux v1.5.50-sing-box-mod.1 github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.2 diff --git a/go.sum b/go.sum index c3b5607fb..21fde21ef 100644 --- a/go.sum +++ b/go.sum @@ -177,8 +177,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.7.8 h1:v9GYPL6V1ZiViqdoRYOy1MPE9b2E6SP0YYWCIGV5fGc= -github.com/sagernet/sing-tun v0.7.8/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM= +github.com/sagernet/sing-tun v0.7.9 h1:kcEFA0Xa+OVcrBGnlIl33+SrW/vuB3jtOw0HQNOSJzc= +github.com/sagernet/sing-tun v0.7.9/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM= github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk= github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478= diff --git a/option/tun.go b/option/tun.go index 89affb23c..6ff28a171 100644 --- a/option/tun.go +++ b/option/tun.go @@ -11,33 +11,34 @@ import ( ) type TunInboundOptions struct { - InterfaceName string `json:"interface_name,omitempty"` - MTU uint32 `json:"mtu,omitempty"` - Address badoption.Listable[netip.Prefix] `json:"address,omitempty"` - AutoRoute bool `json:"auto_route,omitempty"` - IPRoute2TableIndex int `json:"iproute2_table_index,omitempty"` - IPRoute2RuleIndex int `json:"iproute2_rule_index,omitempty"` - AutoRedirect bool `json:"auto_redirect,omitempty"` - AutoRedirectInputMark FwMark `json:"auto_redirect_input_mark,omitempty"` - AutoRedirectOutputMark FwMark `json:"auto_redirect_output_mark,omitempty"` - LoopbackAddress badoption.Listable[netip.Addr] `json:"loopback_address,omitempty"` - StrictRoute bool `json:"strict_route,omitempty"` - RouteAddress badoption.Listable[netip.Prefix] `json:"route_address,omitempty"` - RouteAddressSet badoption.Listable[string] `json:"route_address_set,omitempty"` - RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"route_exclude_address,omitempty"` - RouteExcludeAddressSet badoption.Listable[string] `json:"route_exclude_address_set,omitempty"` - IncludeInterface badoption.Listable[string] `json:"include_interface,omitempty"` - ExcludeInterface badoption.Listable[string] `json:"exclude_interface,omitempty"` - IncludeUID badoption.Listable[uint32] `json:"include_uid,omitempty"` - IncludeUIDRange badoption.Listable[string] `json:"include_uid_range,omitempty"` - ExcludeUID badoption.Listable[uint32] `json:"exclude_uid,omitempty"` - ExcludeUIDRange badoption.Listable[string] `json:"exclude_uid_range,omitempty"` - IncludeAndroidUser badoption.Listable[int] `json:"include_android_user,omitempty"` - IncludePackage badoption.Listable[string] `json:"include_package,omitempty"` - ExcludePackage badoption.Listable[string] `json:"exclude_package,omitempty"` - UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"` - Stack string `json:"stack,omitempty"` - Platform *TunPlatformOptions `json:"platform,omitempty"` + InterfaceName string `json:"interface_name,omitempty"` + MTU uint32 `json:"mtu,omitempty"` + Address badoption.Listable[netip.Prefix] `json:"address,omitempty"` + AutoRoute bool `json:"auto_route,omitempty"` + IPRoute2TableIndex int `json:"iproute2_table_index,omitempty"` + IPRoute2RuleIndex int `json:"iproute2_rule_index,omitempty"` + AutoRedirect bool `json:"auto_redirect,omitempty"` + AutoRedirectInputMark FwMark `json:"auto_redirect_input_mark,omitempty"` + AutoRedirectOutputMark FwMark `json:"auto_redirect_output_mark,omitempty"` + AutoRedirectIPRoute2FallbackRuleIndex int `json:"auto_redirect_iproute2_fallback_rule_index,omitempty"` + LoopbackAddress badoption.Listable[netip.Addr] `json:"loopback_address,omitempty"` + StrictRoute bool `json:"strict_route,omitempty"` + RouteAddress badoption.Listable[netip.Prefix] `json:"route_address,omitempty"` + RouteAddressSet badoption.Listable[string] `json:"route_address_set,omitempty"` + RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"route_exclude_address,omitempty"` + RouteExcludeAddressSet badoption.Listable[string] `json:"route_exclude_address_set,omitempty"` + IncludeInterface badoption.Listable[string] `json:"include_interface,omitempty"` + ExcludeInterface badoption.Listable[string] `json:"exclude_interface,omitempty"` + IncludeUID badoption.Listable[uint32] `json:"include_uid,omitempty"` + IncludeUIDRange badoption.Listable[string] `json:"include_uid_range,omitempty"` + ExcludeUID badoption.Listable[uint32] `json:"exclude_uid,omitempty"` + ExcludeUIDRange badoption.Listable[string] `json:"exclude_uid_range,omitempty"` + IncludeAndroidUser badoption.Listable[int] `json:"include_android_user,omitempty"` + IncludePackage badoption.Listable[string] `json:"include_package,omitempty"` + ExcludePackage badoption.Listable[string] `json:"exclude_package,omitempty"` + UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"` + Stack string `json:"stack,omitempty"` + Platform *TunPlatformOptions `json:"platform,omitempty"` InboundOptions // Deprecated: removed diff --git a/protocol/tun/inbound.go b/protocol/tun/inbound.go index fc69309c0..ee85f80b2 100644 --- a/protocol/tun/inbound.go +++ b/protocol/tun/inbound.go @@ -174,6 +174,10 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo if ruleIndex == 0 { ruleIndex = tun.DefaultIPRoute2RuleIndex } + autoRedirectFallbackRuleIndex := options.AutoRedirectIPRoute2FallbackRuleIndex + if autoRedirectFallbackRuleIndex == 0 { + autoRedirectFallbackRuleIndex = tun.DefaultIPRoute2AutoRedirectFallbackRuleIndex + } inputMark := uint32(options.AutoRedirectInputMark) if inputMark == 0 { inputMark = tun.DefaultAutoRedirectInputMark @@ -192,32 +196,33 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo logger: logger, inboundOptions: options.InboundOptions, tunOptions: tun.Options{ - Name: options.InterfaceName, - MTU: tunMTU, - GSO: enableGSO, - Inet4Address: inet4Address, - Inet6Address: inet6Address, - AutoRoute: options.AutoRoute, - IPRoute2TableIndex: tableIndex, - IPRoute2RuleIndex: ruleIndex, - AutoRedirectInputMark: inputMark, - AutoRedirectOutputMark: outputMark, - Inet4LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is4), - Inet6LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is6), - StrictRoute: options.StrictRoute, - IncludeInterface: options.IncludeInterface, - ExcludeInterface: options.ExcludeInterface, - Inet4RouteAddress: inet4RouteAddress, - Inet6RouteAddress: inet6RouteAddress, - Inet4RouteExcludeAddress: inet4RouteExcludeAddress, - Inet6RouteExcludeAddress: inet6RouteExcludeAddress, - IncludeUID: includeUID, - ExcludeUID: excludeUID, - IncludeAndroidUser: options.IncludeAndroidUser, - IncludePackage: options.IncludePackage, - ExcludePackage: options.ExcludePackage, - InterfaceMonitor: networkManager.InterfaceMonitor(), - EXP_MultiPendingPackets: multiPendingPackets, + Name: options.InterfaceName, + MTU: tunMTU, + GSO: enableGSO, + Inet4Address: inet4Address, + Inet6Address: inet6Address, + AutoRoute: options.AutoRoute, + IPRoute2TableIndex: tableIndex, + IPRoute2RuleIndex: ruleIndex, + IPRoute2AutoRedirectFallbackRuleIndex: autoRedirectFallbackRuleIndex, + AutoRedirectInputMark: inputMark, + AutoRedirectOutputMark: outputMark, + Inet4LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is4), + Inet6LoopbackAddress: common.Filter(options.LoopbackAddress, netip.Addr.Is6), + StrictRoute: options.StrictRoute, + IncludeInterface: options.IncludeInterface, + ExcludeInterface: options.ExcludeInterface, + Inet4RouteAddress: inet4RouteAddress, + Inet6RouteAddress: inet6RouteAddress, + Inet4RouteExcludeAddress: inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: inet6RouteExcludeAddress, + IncludeUID: includeUID, + ExcludeUID: excludeUID, + IncludeAndroidUser: options.IncludeAndroidUser, + IncludePackage: options.IncludePackage, + ExcludePackage: options.ExcludePackage, + InterfaceMonitor: networkManager.InterfaceMonitor(), + EXP_MultiPendingPackets: multiPendingPackets, }, udpTimeout: udpTimeout, stack: options.Stack,