From 41f4b71a11c5cd37ae8dfb65b042bdc3b3ec6225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 23 Dec 2024 22:24:10 +0800 Subject: [PATCH] tun: Set address sets to routes --- docs/configuration/inbound/tun.md | 56 ++++++-- docs/configuration/inbound/tun.zh.md | 52 +++++-- experimental/libbox/config.go | 4 + experimental/libbox/platform.go | 1 + experimental/libbox/platform/interface.go | 1 + experimental/libbox/service.go | 18 ++- go.mod | 2 +- go.sum | 4 +- protocol/tun/inbound.go | 161 ++++++++++++++-------- route/router.go | 2 +- 10 files changed, 212 insertions(+), 89 deletions(-) diff --git a/docs/configuration/inbound/tun.md b/docs/configuration/inbound/tun.md index d82d451b2e..b6bf5c75f3 100644 --- a/docs/configuration/inbound/tun.md +++ b/docs/configuration/inbound/tun.md @@ -4,7 +4,9 @@ icon: material/alert-decagram !!! 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" @@ -248,7 +250,7 @@ use [VPNHotspot](https://github.com/Mygod/VPNHotspot). !!! 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. @@ -256,7 +258,7 @@ Connection input mark used by `route_address_set` and `route_exclude_address_set !!! 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. @@ -329,29 +331,55 @@ Exclude custom routes when `auto_route` is enabled. #### 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 -!!! 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. -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 diff --git a/docs/configuration/inbound/tun.zh.md b/docs/configuration/inbound/tun.zh.md index 2b5752ba44..c9bd844d41 100644 --- a/docs/configuration/inbound/tun.zh.md +++ b/docs/configuration/inbound/tun.zh.md @@ -4,7 +4,9 @@ icon: material/alert-decagram !!! 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 中的更改" @@ -329,29 +331,53 @@ tun 接口的 IPv6 前缀。 #### 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 -!!! 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 diff --git a/experimental/libbox/config.go b/experimental/libbox/config.go index b27d34abfd..7d0627fe17 100644 --- a/experimental/libbox/config.go +++ b/experimental/libbox/config.go @@ -66,6 +66,10 @@ func (s *platformInterfaceStub) OpenTun(options *tun.Options, platformOptions op return nil, os.ErrInvalid } +func (s *platformInterfaceStub) UpdateRouteOptions(options *tun.Options, platformInterface option.TunPlatformOptions) error { + return os.ErrInvalid +} + func (s *platformInterfaceStub) UsePlatformDefaultInterfaceMonitor() bool { return true } diff --git a/experimental/libbox/platform.go b/experimental/libbox/platform.go index 9b7423ad1d..f4bc7ea6bf 100644 --- a/experimental/libbox/platform.go +++ b/experimental/libbox/platform.go @@ -9,6 +9,7 @@ type PlatformInterface interface { UsePlatformAutoDetectInterfaceControl() bool AutoDetectInterfaceControl(fd int32) error OpenTun(options TunOptions) (int32, error) + UpdateRouteOptions(options TunOptions) error WriteLog(message string) UseProcFS() bool FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error) diff --git a/experimental/libbox/platform/interface.go b/experimental/libbox/platform/interface.go index 23849a3b83..1684d88cc5 100644 --- a/experimental/libbox/platform/interface.go +++ b/experimental/libbox/platform/interface.go @@ -13,6 +13,7 @@ type Interface interface { UsePlatformAutoDetectInterfaceControl() bool AutoDetectInterfaceControl(fd int) 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 Interfaces() ([]adapter.NetworkInterface, error) SetUnderlyingNetworks(networks []adapter.NetworkInterface) error diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index 34c3af924a..e04c040d9a 100644 --- a/experimental/libbox/service.go +++ b/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) { 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 { - return nil, E.New("android: unsupported android_user option") + return nil, E.New("platform: unsupported android_user option") } routeRanges, err := options.BuildAutoRouteRanges(true) if err != nil { @@ -174,6 +174,20 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions 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 { return &platformDefaultInterfaceMonitor{ platformInterfaceWrapper: w, diff --git a/go.mod b/go.mod index 936e995027..ebe55db7b3 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 - github.com/sagernet/sing-tun v0.6.0-beta.6 + github.com/sagernet/sing-tun v0.6.0-beta.7 github.com/sagernet/sing-vmess v0.2.0-beta.1 github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 github.com/sagernet/utls v1.6.7 diff --git a/go.sum b/go.sum index 13c1bb1ae1..988c516c9b 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.0-alpha.2 h1:RPrpgAdkP5td0vLfS5ldvYosFjSsZtRPxiyLV6jyKg0= github.com/sagernet/sing-shadowtls v0.2.0-alpha.2/go.mod h1:0j5XlzKxaWRIEjc1uiSKmVoWb0k+L9QgZVb876+thZA= -github.com/sagernet/sing-tun v0.6.0-beta.6 h1:xaIHoH78MqTSvZqQ4SQto8pC1A+X4qXReDRNaC8DQeI= -github.com/sagernet/sing-tun v0.6.0-beta.6/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= +github.com/sagernet/sing-tun v0.6.0-beta.7 h1:FCSX8oGBqb0H57AAvfGeeH/jMGYWCOg6XWkN/oeES+0= +github.com/sagernet/sing-tun v0.6.0-beta.7/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= github.com/sagernet/sing-vmess v0.2.0-beta.1 h1:5sXQ23uwNlZuDvygzi0dFtnG0Csm/SNqTjAHXJkpuj4= github.com/sagernet/sing-vmess v0.2.0-beta.1/go.mod h1:fLyE1emIcvQ5DV8reFWnufquZ7MkCSYM5ThodsR9NrQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= diff --git a/protocol/tun/inbound.go b/protocol/tun/inbound.go index 26158d7a56..51e7ca78fe 100644 --- a/protocol/tun/inbound.go +++ b/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), 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.AutoRoute { 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 { 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 == "" { 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 ( tunInterface tun.Tun err error ) 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 { - tunInterface, err = t.platformInterface.OpenTun(&t.tunOptions, t.platformOptions) + tunInterface, err = t.platformInterface.OpenTun(&tunOptions, t.platformOptions) } else { - tunInterface, err = tun.New(t.tunOptions) + tunInterface, err = tun.New(tunOptions) } monitor.Finish() + t.tunOptions.Name = tunOptions.Name if err != nil { 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") } 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") err := t.autoRedirect.Start() monitor.Finish() if err != nil { 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 } @@ -406,7 +421,41 @@ func (t *Inbound) Start(stage adapter.StartStage) error { func (t *Inbound) updateRouteAddressSet(it adapter.RuleSet) { t.routeAddressSet = common.FlatMap(t.routeRuleSet, 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.routeExcludeAddressSet = nil } diff --git a/route/router.go b/route/router.go index 6526778bea..642340d4ab 100644 --- a/route/router.go +++ b/route/router.go @@ -363,7 +363,6 @@ func (r *Router) Start(stage adapter.StartStage) error { return E.Cause(err, "initialize DNS server[", i, "]") } } - case adapter.StartStatePostStart: var cacheContext *adapter.HTTPStartContext if len(r.ruleSets) > 0 { 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 { monitor.Start("initialize rule[", i, "]") err := rule.Start()