Skip to content

feat(route): add optional "name" field to route and DNS rules#4061

Open
Pushkinmazila2 wants to merge 101 commits into
SagerNet:testingfrom
Pushkinmazila2:testing
Open

feat(route): add optional "name" field to route and DNS rules#4061
Pushkinmazila2 wants to merge 101 commits into
SagerNet:testingfrom
Pushkinmazila2:testing

Conversation

@Pushkinmazila2
Copy link
Copy Markdown

Summary

Adds an optional name field to DefaultRule and LogicalRule (both route and DNS) that allows users to label individual rules with human-readable names. The field is purely cosmetic — it has no effect on matching logic — and is fully backward-compatible.

Motivation

Large sing-box configurations can contain dozens of rules. Without labels, log output and debugging rely entirely on auto-generated descriptions like rule_set(geosite-category-ads) domain_keyword(...), which makes it hard to understand at a glance which rule fired and why.

A name field solves this with zero risk: old configs without it continue to work unchanged, and new configs with it work fine on old builds (unknown fields are ignored by the JSON parser).

Changes

option/rule.go

  • Added Name string \json:"name,omitempty"`toRawDefaultRule`
  • Added Name string \json:"name,omitempty"`toRawLogicalRule`

option/dns_rule.go

  • Added Name string \json:"name,omitempty"`toRawDefaultDNSRule`
  • Added Name string \json:"name,omitempty"`toLogicalDNSRule`

route/rule/rule_abstract.go

  • abstractDefaultRule.String() now prefixes output with [name] when tag is set
  • abstractLogicalRule.String() now prefixes output with [name] when tag is set

route/rule/rule_default.go

  • NewDefaultRule: passes options.NameabstractDefaultRule.tag
  • NewLogicalRule: passes options.NameabstractLogicalRule.tag

Behavior

When name is set, log lines change from:

rule_set(geosite-category-ads)

to:

[Block ads] rule_set(geosite-category-ads)

When name is omitted, output is identical to the current behavior.

Example

{
  "route": {
    "rules": [
      {
        "name": "Block ads",
        "rule_set": ["geosite-category-ads"],
        "action": "reject"
      },
      {
        "name": "Force direct for CN",
        "rule_set": ["geoip-cn", "geosite-cn"],
        "action": "route",
        "outbound": "direct"
      },
      {
        "name": "Proxy everything else",
        "type": "logical",
        "mode": "or",
        "rules": [
          { "network": "tcp" },
          { "network": "udp" }
        ],
        "action": "route",
        "outbound": "proxy"
      }
    ]
  }
}

Backward Compatibility

Scenario Result
Old config (no name) → new build ✅ Works, field defaults to ""
New config (with name) → old build ✅ Works, unknown field is silently ignored
New config (with name) → new build ✅ Works, name appears in logs

Testing

Built and verified using Docker:

docker build -t sing-box-dev .
docker run --rm \
  -v $(pwd)/test-config.json:/etc/sing-box/config.json \
  sing-box-dev check -c /etc/sing-box/config.json

Log output confirms [name] prefix appears correctly on rule match.

image

Serialize probe rounds in startProber to eliminate unbounded fan-out of
fire-and-forget probe goroutines (up to 100/sec per direction), and close
HTTP/3 transports via transport.Close() in addition to CloseIdleConnections.
Signed-off-by: Pushkinmazila2 <zavalny199@yandex.com>
@Pushkinmazila2
Copy link
Copy Markdown
Author

@nekohasekai ive tested in new build.I tested the new version with your changes, everything works. Whether you have a "name" or not, everything works too.

@hdrover
Copy link
Copy Markdown
Contributor

hdrover commented Apr 22, 2026

Was name chosen intentionally instead of tag?

I’m wondering because if rules ever become referenceable in the future, having name now and tag later could create two almost overlapping fields. So is the idea that name should stay purely cosmetic / log-only and never be used semantically?

@Pushkinmazila2
Copy link
Copy Markdown
Author

The trick here is that if there are tags in the future, I'm only in favor,
Right now this value is logical (cosmetic), to navigate among dozens of rules.

@nekohasekai nekohasekai force-pushed the testing branch 6 times, most recently from 1b0e6c5 to abedea4 Compare April 28, 2026 07:12
@nekohasekai nekohasekai force-pushed the testing branch 6 times, most recently from 057f540 to 6b07a22 Compare May 15, 2026 05:29
@nekohasekai nekohasekai force-pushed the testing branch 5 times, most recently from abac453 to bf9ea6d Compare May 21, 2026 07:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants