浏览代码

tun: Set address sets to routes

世界 10 月之前
父节点
当前提交
0c754505f7

+ 42 - 14
docs/configuration/inbound/tun.md

@@ -4,7 +4,9 @@ icon: material/alert-decagram
 
 
 !!! quote "Changes in sing-box 1.11.0"
 !!! quote "Changes in sing-box 1.11.0"
 
 
-    :material-delete-alert: [gso](#gso)
+    :material-delete-alert: [gso](#gso)  
+    :material-alert-decagram: [route_address_set](#stack)  
+    :material-alert-decagram: [route_exclude_address_set](#stack)
 
 
 !!! quote "Changes in sing-box 1.10.0"
 !!! quote "Changes in sing-box 1.10.0"
 
 
@@ -248,7 +250,7 @@ use [VPNHotspot](https://github.com/Mygod/VPNHotspot).
 
 
 !!! question "Since sing-box 1.10.0"
 !!! question "Since sing-box 1.10.0"
 
 
-Connection input mark used by `route_address_set` and `route_exclude_address_set`.
+Connection input mark used by `route[_exclude]_address_set` with `auto_redirect`.
 
 
 `0x2023` is used by default.
 `0x2023` is used by default.
 
 
@@ -256,7 +258,7 @@ Connection input mark used by `route_address_set` and `route_exclude_address_set
 
 
 !!! question "Since sing-box 1.10.0"
 !!! question "Since sing-box 1.10.0"
 
 
-Connection output mark used by `route_address_set` and `route_exclude_address_set`.
+Connection input mark used by `route[_exclude]_address_set` with `auto_redirect`.
 
 
 `0x2024` is used by default.
 `0x2024` is used by default.
 
 
@@ -329,29 +331,55 @@ Exclude custom routes when `auto_route` is enabled.
 
 
 #### route_address_set
 #### route_address_set
 
 
-!!! question "Since sing-box 1.10.0"
+=== "With `auto_redirect` enabled"
 
 
-!!! quote ""
+    !!! question "Since sing-box 1.10.0"
 
 
-    Only supported on Linux with nftables and requires `auto_route` and `auto_redirect` enabled.
+    !!! quote ""
+    
+        Only supported on Linux with nftables and requires `auto_route` and `auto_redirect` enabled.
+    
+    Add the destination IP CIDR rules in the specified rule-sets to the firewall.
+    Unmatched traffic will bypass the sing-box routes.
+    
+    Conflict with `route.default_mark` and `[dialOptions].routing_mark`.
 
 
-Add the destination IP CIDR rules in the specified rule-sets to the firewall.
-Unmatched traffic will bypass the sing-box routes.
+=== "Without `auto_redirect` enabled"
 
 
-Conflict with `route.default_mark` and `[dialOptions].routing_mark`.
+    !!! question "Since sing-box 1.11.0"
+    
+    Add the destination IP CIDR rules in the specified rule-sets to routes, equivalent to adding to `route_address`.
+    Unmatched traffic will bypass the sing-box routes.
+
+    Note that it **doesn't work on the Android graphical client** due to
+    the Android VpnService not being able to handle a large number of routes (DeadSystemException),
+    but otherwise it works fine on all command line clients and Apple platforms.
 
 
 #### route_exclude_address_set
 #### route_exclude_address_set
 
 
-!!! question "Since sing-box 1.10.0"
+=== "With `auto_redirect` enabled"
 
 
-!!! quote ""
+    !!! question "Since sing-box 1.10.0"
+
+    !!! quote ""
 
 
     Only supported on Linux with nftables and requires `auto_route` and `auto_redirect` enabled.
     Only supported on Linux with nftables and requires `auto_route` and `auto_redirect` enabled.
 
 
-Add the destination IP CIDR rules in the specified rule-sets to the firewall.
-Matched traffic will bypass the sing-box routes.
+    Add the destination IP CIDR rules in the specified rule-sets to the firewall.
+    Matched traffic will bypass the sing-box routes.
+    
+    Conflict with `route.default_mark` and `[dialOptions].routing_mark`.
+
+=== "Without `auto_redirect` enabled"
+
+    !!! question "Since sing-box 1.11.0"
+    
+    Add the destination IP CIDR rules in the specified rule-sets to routes, equivalent to adding to `route_exclude_address`.
+    Matched traffic will bypass the sing-box routes.
 
 
-Conflict with `route.default_mark` and `[dialOptions].routing_mark`.
+    Note that it **doesn't work on the Android graphical client** due to
+    the Android VpnService not being able to handle a large number of routes (DeadSystemException),
+    but otherwise it works fine on all command line clients and Apple platforms.
 
 
 #### endpoint_independent_nat
 #### endpoint_independent_nat
 
 

+ 39 - 13
docs/configuration/inbound/tun.zh.md

@@ -4,7 +4,9 @@ icon: material/alert-decagram
 
 
 !!! quote "sing-box 1.11.0 中的更改"
 !!! quote "sing-box 1.11.0 中的更改"
 
 
-    :material-delete-alert: [gso](#gso)
+    :material-delete-alert: [gso](#gso)  
+    :material-alert-decagram: [route_address_set](#stack)  
+    :material-alert-decagram: [route_exclude_address_set](#stack)
 
 
 !!! quote "sing-box 1.10.0 中的更改"
 !!! quote "sing-box 1.10.0 中的更改"
 
 
@@ -329,29 +331,53 @@ tun 接口的 IPv6 前缀。
 
 
 #### route_address_set
 #### route_address_set
 
 
-!!! question "自 sing-box 1.10.0 起"
+=== "`auto_redirect` 已启用"
 
 
-!!! quote ""
+    !!! question "自 sing-box 1.10.0 起"
+    
+    !!! quote ""
+    
+        仅支持 Linux,且需要 nftables,`auto_route` 和 `auto_redirect` 已启用。 
+    
+    将指定规则集中的目标 IP CIDR 规则添加到防火墙。
+    不匹配的流量将绕过 sing-box 路由。
+    
+    与 `route.default_mark` 和 `[dialOptions].routing_mark` 冲突。
 
 
-    仅支持 Linux,且需要 nftables,`auto_route` 和 `auto_redirect` 已启用。 
+=== "`auto_redirect` 未启用"
 
 
-将指定规则集中的目标 IP CIDR 规则添加到防火墙。
-不匹配的流量将绕过 sing-box 路由。
+    !!! question "自 sing-box 1.11.0 起"
 
 
-与 `route.default_mark` 和 `[dialOptions].routing_mark` 冲突。
+    将指定规则集中的目标 IP CIDR 规则添加到路由,相当于添加到 `route_address`。
+    不匹配的流量将绕过 sing-box 路由。
+
+    请注意,由于 Android VpnService 无法处理大量路由(DeadSystemException),
+    因此它**在 Android 图形客户端上不起作用**,但除此之外,它在所有命令行客户端和 Apple 平台上都可以正常工作。
 
 
 #### route_exclude_address_set
 #### route_exclude_address_set
 
 
-!!! question "自 sing-box 1.10.0 起"
+=== "`auto_redirect` 已启用"
 
 
-!!! quote ""
+    !!! question "自 sing-box 1.10.0 起"
+    
+    !!! quote ""
+    
+        仅支持 Linux,且需要 nftables,`auto_route` 和 `auto_redirect` 已启用。 
+
+    将指定规则集中的目标 IP CIDR 规则添加到防火墙。
+    匹配的流量将绕过 sing-box 路由。
+
+    与 `route.default_mark` 和 `[dialOptions].routing_mark` 冲突。
+
+=== "`auto_redirect` 未启用"
 
 
-    仅支持 Linux,且需要 nftables,`auto_route` 和 `auto_redirect` 已启用。
+    !!! question "自 sing-box 1.11.0 起"
 
 
-将指定规则集中的目标 IP CIDR 规则添加到防火墙。
-匹配的流量将绕过 sing-box 路由。
+    将指定规则集中的目标 IP CIDR 规则添加到路由,相当于添加到 `route_exclude_address`
+    匹配的流量将绕过 sing-box 路由。
 
 
-与 `route.default_mark` 和 `[dialOptions].routing_mark` 冲突。
+    请注意,由于 Android VpnService 无法处理大量路由(DeadSystemException),
+    因此它**在 Android 图形客户端上不起作用**,但除此之外,它在所有命令行客户端和 Apple 平台上都可以正常工作。
 
 
 #### endpoint_independent_nat
 #### endpoint_independent_nat
 
 

+ 4 - 0
experimental/libbox/config.go

@@ -66,6 +66,10 @@ func (s *platformInterfaceStub) OpenTun(options *tun.Options, platformOptions op
 	return nil, os.ErrInvalid
 	return nil, os.ErrInvalid
 }
 }
 
 
+func (s *platformInterfaceStub) UpdateRouteOptions(options *tun.Options, platformInterface option.TunPlatformOptions) error {
+	return os.ErrInvalid
+}
+
 func (s *platformInterfaceStub) UsePlatformDefaultInterfaceMonitor() bool {
 func (s *platformInterfaceStub) UsePlatformDefaultInterfaceMonitor() bool {
 	return true
 	return true
 }
 }

+ 1 - 0
experimental/libbox/platform.go

@@ -9,6 +9,7 @@ type PlatformInterface interface {
 	UsePlatformAutoDetectInterfaceControl() bool
 	UsePlatformAutoDetectInterfaceControl() bool
 	AutoDetectInterfaceControl(fd int32) error
 	AutoDetectInterfaceControl(fd int32) error
 	OpenTun(options TunOptions) (int32, error)
 	OpenTun(options TunOptions) (int32, error)
+	UpdateRouteOptions(options TunOptions) error
 	WriteLog(message string)
 	WriteLog(message string)
 	UseProcFS() bool
 	UseProcFS() bool
 	FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
 	FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)

+ 1 - 0
experimental/libbox/platform/interface.go

@@ -13,6 +13,7 @@ type Interface interface {
 	UsePlatformAutoDetectInterfaceControl() bool
 	UsePlatformAutoDetectInterfaceControl() bool
 	AutoDetectInterfaceControl(fd int) error
 	AutoDetectInterfaceControl(fd int) error
 	OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
 	OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
+	UpdateRouteOptions(options *tun.Options, platformOptions option.TunPlatformOptions) error
 	CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
 	CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
 	Interfaces() ([]adapter.NetworkInterface, error)
 	Interfaces() ([]adapter.NetworkInterface, error)
 	SetUnderlyingNetworks(networks []adapter.NetworkInterface) error
 	SetUnderlyingNetworks(networks []adapter.NetworkInterface) error

+ 16 - 2
experimental/libbox/service.go

@@ -148,10 +148,10 @@ func (w *platformInterfaceWrapper) AutoDetectInterfaceControl(fd int) error {
 
 
 func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
 func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
 	if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
 	if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
-		return nil, E.New("android: unsupported uid options")
+		return nil, E.New("platform: unsupported uid options")
 	}
 	}
 	if len(options.IncludeAndroidUser) > 0 {
 	if len(options.IncludeAndroidUser) > 0 {
-		return nil, E.New("android: unsupported android_user option")
+		return nil, E.New("platform: unsupported android_user option")
 	}
 	}
 	routeRanges, err := options.BuildAutoRouteRanges(true)
 	routeRanges, err := options.BuildAutoRouteRanges(true)
 	if err != nil {
 	if err != nil {
@@ -174,6 +174,20 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions
 	return tun.New(*options)
 	return tun.New(*options)
 }
 }
 
 
+func (w *platformInterfaceWrapper) UpdateRouteOptions(options *tun.Options, platformOptions option.TunPlatformOptions) error {
+	if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
+		return E.New("android: unsupported uid options")
+	}
+	if len(options.IncludeAndroidUser) > 0 {
+		return E.New("android: unsupported android_user option")
+	}
+	routeRanges, err := options.BuildAutoRouteRanges(true)
+	if err != nil {
+		return err
+	}
+	return w.iif.UpdateRouteOptions(&tunOptions{options, routeRanges, platformOptions})
+}
+
 func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor {
 func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor {
 	return &platformDefaultInterfaceMonitor{
 	return &platformDefaultInterfaceMonitor{
 		platformInterfaceWrapper: w,
 		platformInterfaceWrapper: w,

+ 105 - 56
protocol/tun/inbound.go

@@ -209,6 +209,22 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
 		platformInterface: service.FromContext[platform.Interface](ctx),
 		platformInterface: service.FromContext[platform.Interface](ctx),
 		platformOptions:   common.PtrValueOrDefault(options.Platform),
 		platformOptions:   common.PtrValueOrDefault(options.Platform),
 	}
 	}
+	for _, routeAddressSet := range options.RouteAddressSet {
+		ruleSet, loaded := router.RuleSet(routeAddressSet)
+		if !loaded {
+			return nil, E.New("parse route_address_set: rule-set not found: ", routeAddressSet)
+		}
+		ruleSet.IncRef()
+		inbound.routeRuleSet = append(inbound.routeRuleSet, ruleSet)
+	}
+	for _, routeExcludeAddressSet := range options.RouteExcludeAddressSet {
+		ruleSet, loaded := router.RuleSet(routeExcludeAddressSet)
+		if !loaded {
+			return nil, E.New("parse route_exclude_address_set: rule-set not found: ", routeExcludeAddressSet)
+		}
+		ruleSet.IncRef()
+		inbound.routeExcludeRuleSet = append(inbound.routeExcludeRuleSet, ruleSet)
+	}
 	if options.AutoRedirect {
 	if options.AutoRedirect {
 		if !options.AutoRoute {
 		if !options.AutoRoute {
 			return nil, E.New("`auto_route` is required by `auto_redirect`")
 			return nil, E.New("`auto_route` is required by `auto_redirect`")
@@ -229,32 +245,11 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
 		if err != nil {
 		if err != nil {
 			return nil, E.Cause(err, "initialize auto-redirect")
 			return nil, E.Cause(err, "initialize auto-redirect")
 		}
 		}
-		if runtime.GOOS != "android" {
-			var markMode bool
-			for _, routeAddressSet := range options.RouteAddressSet {
-				ruleSet, loaded := router.RuleSet(routeAddressSet)
-				if !loaded {
-					return nil, E.New("parse route_address_set: rule-set not found: ", routeAddressSet)
-				}
-				ruleSet.IncRef()
-				inbound.routeRuleSet = append(inbound.routeRuleSet, ruleSet)
-				markMode = true
-			}
-			for _, routeExcludeAddressSet := range options.RouteExcludeAddressSet {
-				ruleSet, loaded := router.RuleSet(routeExcludeAddressSet)
-				if !loaded {
-					return nil, E.New("parse route_exclude_address_set: rule-set not found: ", routeExcludeAddressSet)
-				}
-				ruleSet.IncRef()
-				inbound.routeExcludeRuleSet = append(inbound.routeExcludeRuleSet, ruleSet)
-				markMode = true
-			}
-			if markMode {
-				inbound.tunOptions.AutoRedirectMarkMode = true
-				err = networkManager.RegisterAutoRedirectOutputMark(inbound.tunOptions.AutoRedirectOutputMark)
-				if err != nil {
-					return nil, err
-				}
+		if runtime.GOOS != "android" && len(inbound.routeAddressSet) > 0 || len(inbound.routeExcludeAddressSet) > 0 {
+			inbound.tunOptions.AutoRedirectMarkMode = true
+			err = networkManager.RegisterAutoRedirectOutputMark(inbound.tunOptions.AutoRedirectOutputMark)
+			if err != nil {
+				return nil, err
 			}
 			}
 		}
 		}
 	}
 	}
@@ -310,18 +305,62 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
 		if t.tunOptions.Name == "" {
 		if t.tunOptions.Name == "" {
 			t.tunOptions.Name = tun.CalculateInterfaceName("")
 			t.tunOptions.Name = tun.CalculateInterfaceName("")
 		}
 		}
+		if t.platformInterface == nil || runtime.GOOS != "android" {
+			t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet)
+			for _, routeRuleSet := range t.routeRuleSet {
+				ipSets := routeRuleSet.ExtractIPSet()
+				if len(ipSets) == 0 {
+					t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeRuleSet.Name())
+				}
+				t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet))
+				routeRuleSet.DecRef()
+				t.routeAddressSet = append(t.routeAddressSet, ipSets...)
+			}
+			t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet)
+			for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
+				ipSets := routeExcludeRuleSet.ExtractIPSet()
+				if len(ipSets) == 0 {
+					t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name())
+				}
+				t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
+				routeExcludeRuleSet.DecRef()
+				t.routeExcludeAddressSet = append(t.routeExcludeAddressSet, ipSets...)
+			}
+		}
 		var (
 		var (
 			tunInterface tun.Tun
 			tunInterface tun.Tun
 			err          error
 			err          error
 		)
 		)
 		monitor := taskmonitor.New(t.logger, C.StartTimeout)
 		monitor := taskmonitor.New(t.logger, C.StartTimeout)
-		monitor.Start("open tun interface")
+		tunOptions := t.tunOptions
+		if t.autoRedirect == nil && !(runtime.GOOS == "android" && t.platformInterface != nil) {
+			for _, ipSet := range t.routeAddressSet {
+				for _, prefix := range ipSet.Prefixes() {
+					if prefix.Addr().Is4() {
+						tunOptions.Inet4RouteAddress = append(tunOptions.Inet4RouteAddress, prefix)
+					} else {
+						tunOptions.Inet6RouteAddress = append(tunOptions.Inet6RouteAddress, prefix)
+					}
+				}
+			}
+			for _, ipSet := range t.routeExcludeAddressSet {
+				for _, prefix := range ipSet.Prefixes() {
+					if prefix.Addr().Is4() {
+						tunOptions.Inet4RouteExcludeAddress = append(tunOptions.Inet4RouteExcludeAddress, prefix)
+					} else {
+						tunOptions.Inet6RouteExcludeAddress = append(tunOptions.Inet6RouteExcludeAddress, prefix)
+					}
+				}
+			}
+		}
+		monitor.Start("open interface")
 		if t.platformInterface != nil {
 		if t.platformInterface != nil {
-			tunInterface, err = t.platformInterface.OpenTun(&t.tunOptions, t.platformOptions)
+			tunInterface, err = t.platformInterface.OpenTun(&tunOptions, t.platformOptions)
 		} else {
 		} else {
-			tunInterface, err = tun.New(t.tunOptions)
+			tunInterface, err = tun.New(tunOptions)
 		}
 		}
 		monitor.Finish()
 		monitor.Finish()
+		t.tunOptions.Name = tunOptions.Name
 		if err != nil {
 		if err != nil {
 			return E.Cause(err, "configure tun interface")
 			return E.Cause(err, "configure tun interface")
 		}
 		}
@@ -366,39 +405,15 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
 			return E.Cause(err, "starting TUN interface")
 			return E.Cause(err, "starting TUN interface")
 		}
 		}
 		if t.autoRedirect != nil {
 		if t.autoRedirect != nil {
-			t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet)
-			for _, routeRuleSet := range t.routeRuleSet {
-				ipSets := routeRuleSet.ExtractIPSet()
-				if len(ipSets) == 0 {
-					t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeRuleSet.Name())
-				}
-				t.routeAddressSet = append(t.routeAddressSet, ipSets...)
-			}
-			t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet)
-			for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
-				ipSets := routeExcludeRuleSet.ExtractIPSet()
-				if len(ipSets) == 0 {
-					t.logger.Warn("route_address_set: no destination IP CIDR rules found in rule-set: ", routeExcludeRuleSet.Name())
-				}
-				t.routeExcludeAddressSet = append(t.routeExcludeAddressSet, ipSets...)
-			}
 			monitor.Start("initialize auto-redirect")
 			monitor.Start("initialize auto-redirect")
 			err := t.autoRedirect.Start()
 			err := t.autoRedirect.Start()
 			monitor.Finish()
 			monitor.Finish()
 			if err != nil {
 			if err != nil {
 				return E.Cause(err, "auto-redirect")
 				return E.Cause(err, "auto-redirect")
 			}
 			}
-			for _, routeRuleSet := range t.routeRuleSet {
-				t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet))
-				routeRuleSet.DecRef()
-			}
-			for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
-				t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
-				routeExcludeRuleSet.DecRef()
-			}
-			t.routeAddressSet = nil
-			t.routeExcludeAddressSet = nil
 		}
 		}
+		t.routeAddressSet = nil
+		t.routeExcludeAddressSet = nil
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -406,7 +421,41 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
 func (t *Inbound) updateRouteAddressSet(it adapter.RuleSet) {
 func (t *Inbound) updateRouteAddressSet(it adapter.RuleSet) {
 	t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet)
 	t.routeAddressSet = common.FlatMap(t.routeRuleSet, adapter.RuleSet.ExtractIPSet)
 	t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet)
 	t.routeExcludeAddressSet = common.FlatMap(t.routeExcludeRuleSet, adapter.RuleSet.ExtractIPSet)
-	t.autoRedirect.UpdateRouteAddressSet()
+	if t.autoRedirect != nil {
+		t.autoRedirect.UpdateRouteAddressSet()
+	} else {
+		tunOptions := t.tunOptions
+		for _, ipSet := range t.routeAddressSet {
+			for _, prefix := range ipSet.Prefixes() {
+				if prefix.Addr().Is4() {
+					tunOptions.Inet4RouteAddress = append(tunOptions.Inet4RouteAddress, prefix)
+				} else {
+					tunOptions.Inet6RouteAddress = append(tunOptions.Inet6RouteAddress, prefix)
+				}
+			}
+		}
+		for _, ipSet := range t.routeExcludeAddressSet {
+			for _, prefix := range ipSet.Prefixes() {
+				if prefix.Addr().Is4() {
+					tunOptions.Inet4RouteExcludeAddress = append(tunOptions.Inet4RouteExcludeAddress, prefix)
+				} else {
+					tunOptions.Inet6RouteExcludeAddress = append(tunOptions.Inet6RouteExcludeAddress, prefix)
+				}
+			}
+		}
+		if t.platformInterface != nil {
+			err := t.platformInterface.UpdateRouteOptions(&tunOptions, t.platformOptions)
+			if err != nil {
+				t.logger.Error("update route addresses: ", err)
+			}
+		} else {
+			err := t.tunIf.UpdateRouteOptions(tunOptions)
+			if err != nil {
+				t.logger.Error("update route addresses: ", err)
+			}
+		}
+		t.logger.Info("updated route addresses")
+	}
 	t.routeAddressSet = nil
 	t.routeAddressSet = nil
 	t.routeExcludeAddressSet = nil
 	t.routeExcludeAddressSet = nil
 }
 }

+ 1 - 1
route/router.go

@@ -363,7 +363,6 @@ func (r *Router) Start(stage adapter.StartStage) error {
 				return E.Cause(err, "initialize DNS server[", i, "]")
 				return E.Cause(err, "initialize DNS server[", i, "]")
 			}
 			}
 		}
 		}
-	case adapter.StartStatePostStart:
 		var cacheContext *adapter.HTTPStartContext
 		var cacheContext *adapter.HTTPStartContext
 		if len(r.ruleSets) > 0 {
 		if len(r.ruleSets) > 0 {
 			monitor.Start("initialize rule-set")
 			monitor.Start("initialize rule-set")
@@ -419,6 +418,7 @@ func (r *Router) Start(stage adapter.StartStage) error {
 				}
 				}
 			}
 			}
 		}
 		}
+	case adapter.StartStatePostStart:
 		for i, rule := range r.rules {
 		for i, rule := range r.rules {
 			monitor.Start("initialize rule[", i, "]")
 			monitor.Start("initialize rule[", i, "]")
 			err := rule.Start()
 			err := rule.Start()