From 7126ab726444e7b305926f680110316ea488fa11 Mon Sep 17 00:00:00 2001 From: XYenon Date: Wed, 12 Nov 2025 15:53:14 +0800 Subject: [PATCH] Fix routing rules referencing endpoints being filtered out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two related issues were fixed: 1. The filter_null_references filter only checked if routing rules referenced valid outbounds, causing rules that reference endpoints to be incorrectly removed 2. Endpoints were assigned to options after template rendering and filtering, so the filter couldn't access them Changes: - Modified filter to allow routing rules to reference both outbounds and endpoints as valid targets - Moved endpoint assignment to before filtering by passing endpoints to template.Render() and setting them early in the render process - This allows custom_rules in extended templates to route traffic to endpoints (e.g., Tailscale) without being filtered out 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- server/profile.go | 5 +---- template/filter/filter_null_references.go | 8 ++++++-- template/template.go | 6 +++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/server/profile.go b/server/profile.go index 44f0a37..b8f5b08 100644 --- a/server/profile.go +++ b/server/profile.go @@ -159,13 +159,10 @@ func (p *Profile) Render(metadata metadata.Metadata) (*boxOption.Options, error) if metadata.Version == nil || metadata.Version.LessThan(semver.ParseVersion("1.12.0-alpha.1")) { ctx = boxOption.ContextWithDontUpgrade(ctx) } - options, err := selectedTemplate.Render(ctx, metadata, p.Name, outbounds, subscriptions) + options, err := selectedTemplate.Render(ctx, metadata, p.Name, endpoints, outbounds, subscriptions) if err != nil { return nil, err } - if metadata.Version != nil && metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.12.0-alpha.1")) { - options.Endpoints = endpoints - } options, err = badjson.Omitempty(ctx, options) if err != nil { return nil, E.Cause(err, "omitempty") diff --git a/template/filter/filter_null_references.go b/template/filter/filter_null_references.go index 3f88beb..b221a89 100644 --- a/template/filter/filter_null_references.go +++ b/template/filter/filter_null_references.go @@ -15,6 +15,10 @@ func filterNullGroupReference(metadata M.Metadata, options *option.Options) erro outboundTags := common.Map(options.Outbounds, func(it option.Outbound) string { return it.Tag }) + endpointTags := common.Map(options.Endpoints, func(it option.Endpoint) string { + return it.Tag + }) + routingTargets := append(outboundTags, endpointTags...) for _, outbound := range options.Outbounds { switch outboundOptions := outbound.Options.(type) { case *option.SelectorOutboundOptions: @@ -35,12 +39,12 @@ func filterNullGroupReference(metadata M.Metadata, options *option.Options) erro if it.DefaultOptions.Action != C.RuleActionTypeRoute { return true } - return common.Contains(outboundTags, it.DefaultOptions.RouteOptions.Outbound) + return common.Contains(routingTargets, it.DefaultOptions.RouteOptions.Outbound) case C.RuleTypeLogical: if it.LogicalOptions.Action != C.RuleActionTypeRoute { return true } - return common.Contains(outboundTags, it.LogicalOptions.RouteOptions.Outbound) + return common.Contains(routingTargets, it.LogicalOptions.RouteOptions.Outbound) default: panic("no") } diff --git a/template/template.go b/template/template.go index 9535701..26b5438 100644 --- a/template/template.go +++ b/template/template.go @@ -5,6 +5,7 @@ import ( "regexp" M "github.com/sagernet/serenity/common/metadata" + "github.com/sagernet/serenity/common/semver" "github.com/sagernet/serenity/option" "github.com/sagernet/serenity/subscription" "github.com/sagernet/serenity/template/filter" @@ -40,9 +41,12 @@ type ExtraGroup struct { exclude []*regexp.Regexp } -func (t *Template) Render(ctx context.Context, metadata M.Metadata, profileName string, outbounds [][]boxOption.Outbound, subscriptions []*subscription.Subscription) (*boxOption.Options, error) { +func (t *Template) Render(ctx context.Context, metadata M.Metadata, profileName string, endpoints []boxOption.Endpoint, outbounds [][]boxOption.Outbound, subscriptions []*subscription.Subscription) (*boxOption.Options, error) { var options boxOption.Options options.Log = t.Log + if metadata.Version != nil && metadata.Version.GreaterThanOrEqual(semver.ParseVersion("1.12.0-alpha.1")) { + options.Endpoints = endpoints + } err := t.renderDNS(ctx, metadata, &options) if err != nil { return nil, E.Cause(err, "render dns")