Reduce rule matching memory allocations

This commit is contained in:
世界
2026-09-01 21:32:13 +08:00
parent 3e185071eb
commit b807ff30d0
5 changed files with 74 additions and 33 deletions
+15 -3
View File
@@ -129,7 +129,7 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
}
myResolvers = append(myResolvers, myResolver)
}
routes[domain.WithTrailingDot()] = myResolvers
routes[mDNS.CanonicalName(domain.WithTrailingDot())] = myResolvers
}
hosts := make(map[string][]netip.Addr)
for domain, addresses := range dnsConfig.Hosts {
@@ -275,14 +275,25 @@ func (t *DNSTransport) PreferredDomain(domain string) bool {
if t.acceptSearchDomain && len(searchDomains) > 0 && mDNS.CountLabel(domain) == 1 {
return true
}
canonicalDomain := mDNS.CanonicalName(domain)
for suffix := range routes {
if mDNS.IsSubDomain(suffix, domain) {
if matchDomainSuffix(canonicalDomain, suffix) {
return true
}
}
return false
}
func matchDomainSuffix(domain string, suffix string) bool {
if suffix == "." || suffix == "" {
return true
}
if !strings.HasSuffix(domain, suffix) {
return false
}
return len(domain) == len(suffix) || domain[len(domain)-len(suffix)-1] == '.'
}
func (t *DNSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
done := make(chan struct{})
var (
@@ -375,8 +386,9 @@ func (t *DNSTransport) exchangeOnce(ctx context.Context, message *mDNS.Msg, allo
}
return
}
canonicalName := mDNS.CanonicalName(question.Name)
for domainSuffix, transports := range routes {
if mDNS.IsSubDomain(domainSuffix, question.Name) {
if matchDomainSuffix(canonicalName, domainSuffix) {
if len(transports) == 0 {
callback(&mDNS.Msg{
MsgHdr: mDNS.MsgHdr{
+2 -2
View File
@@ -953,7 +953,7 @@ func (t *Endpoint) PreferredDomain(metadata *adapter.InboundContext, domain stri
}
}
for _, suffix := range t.routeSuffixes.Load() {
if mDNS.IsSubDomain(suffix, domain) {
if matchDomainSuffix(domain, suffix) {
return true
}
}
@@ -1000,7 +1000,7 @@ func (t *Endpoint) onReconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCf
}
routeSuffixes := make([]string, 0, len(dnsCfg.Routes))
for fqdn := range dnsCfg.Routes {
routeSuffixes = append(routeSuffixes, fqdn.WithoutTrailingDot())
routeSuffixes = append(routeSuffixes, strings.ToLower(fqdn.WithoutTrailingDot()))
}
t.routeDomains.Store(routeDomains)
t.routeSuffixes.Store(routeSuffixes)
+22
View File
@@ -1,5 +1,7 @@
package rule
import "github.com/sagernet/sing-box/adapter"
type ruleMatchState uint8
const (
@@ -24,3 +26,23 @@ func (g ruleGroupMatch) mergeWith(other ruleGroupMatch) ruleGroupMatch {
satisfied: g.satisfied | other.satisfied,
}
}
type ruleMatchSnapshot struct {
ipCidrMatchSource bool
ipCidrAcceptEmpty bool
deferredIPCIDRMatchGroups uint8
}
func snapshotRuleMatch(metadata *adapter.InboundContext) ruleMatchSnapshot {
return ruleMatchSnapshot{
ipCidrMatchSource: metadata.IPCIDRMatchSource,
ipCidrAcceptEmpty: metadata.IPCIDRAcceptEmpty,
deferredIPCIDRMatchGroups: metadata.DeferredIPCIDRMatchGroups,
}
}
func (s ruleMatchSnapshot) restore(metadata *adapter.InboundContext) {
metadata.IPCIDRMatchSource = s.ipCidrMatchSource
metadata.IPCIDRAcceptEmpty = s.ipCidrAcceptEmpty
metadata.DeferredIPCIDRMatchGroups = s.deferredIPCIDRMatchGroups
}
+9 -9
View File
@@ -206,32 +206,32 @@ func (r *abstractLogicalRule) Match(metadata *adapter.InboundContext) bool {
matched bool
deferredGroups uint8
)
snapshot := snapshotRuleMatch(metadata)
if r.mode == C.LogicalTypeAnd {
matched = true
for _, rule := range r.rules {
nestedMetadata := *metadata
nestedMetadata.ResetRuleCache()
if !rule.Match(&nestedMetadata) {
metadata.ResetRuleCache()
if !rule.Match(metadata) {
matched = false
deferredGroups = 0
break
}
deferredGroups |= nestedMetadata.DeferredIPCIDRMatchGroups
deferredGroups |= metadata.DeferredIPCIDRMatchGroups
}
} else {
for _, rule := range r.rules {
nestedMetadata := *metadata
nestedMetadata.ResetRuleCache()
if rule.Match(&nestedMetadata) {
metadata.ResetRuleCache()
if rule.Match(metadata) {
matched = true
if nestedMetadata.DeferredIPCIDRMatchGroups == 0 {
if metadata.DeferredIPCIDRMatchGroups == 0 {
deferredGroups = 0
break
}
deferredGroups |= nestedMetadata.DeferredIPCIDRMatchGroups
deferredGroups |= metadata.DeferredIPCIDRMatchGroups
}
}
}
snapshot.restore(metadata)
if matched {
metadata.DeferredIPCIDRMatchGroups |= deferredGroups
}
+26 -19
View File
@@ -52,12 +52,15 @@ func (r *RuleSetItem) Close() error {
}
func (r *RuleSetItem) Match(metadata *adapter.InboundContext) bool {
snapshot := snapshotRuleMatch(metadata)
for _, ruleSet := range r.setList {
nestedMetadata := r.nestedMetadata(metadata)
if ruleSet.Match(&nestedMetadata) {
r.prepareNestedMatch(metadata)
if ruleSet.Match(metadata) {
snapshot.restore(metadata)
return true
}
}
snapshot.restore(metadata)
return false
}
@@ -67,17 +70,19 @@ func (r *RuleSetItem) matchWithOuterGroups(metadata *adapter.InboundContext, out
matched bool
deferredGroups uint8
)
snapshot := snapshotRuleMatch(metadata)
for _, ruleSet := range r.setList {
nestedMetadata := r.nestedMetadata(metadata)
r.prepareNestedMatch(metadata)
if provider, isProvider := ruleSet.(mergeableRuleProvider); isProvider {
branch := provider.mergeableRule()
if branch != nil {
branchGroups, branchMatched := branch.evaluateForMerge(&nestedMetadata)
branchGroups, branchMatched := branch.evaluateForMerge(metadata)
if branchMatched {
merged := outerGroups.mergeWith(branchGroups)
if merged.done() {
branchDeferredGroups := nestedMetadata.DeferredIPCIDRMatchGroups &^ uint8(merged.satisfied)
branchDeferredGroups := metadata.DeferredIPCIDRMatchGroups &^ uint8(merged.satisfied)
if branchDeferredGroups == 0 {
snapshot.restore(metadata)
metadata.DeferredIPCIDRMatchGroups &^= uint8(merged.satisfied)
return true
}
@@ -88,26 +93,26 @@ func (r *RuleSetItem) matchWithOuterGroups(metadata *adapter.InboundContext, out
continue
}
}
if outerDone && ruleSet.Match(&nestedMetadata) {
if nestedMetadata.DeferredIPCIDRMatchGroups == 0 {
if outerDone && ruleSet.Match(metadata) {
if metadata.DeferredIPCIDRMatchGroups == 0 {
snapshot.restore(metadata)
return true
}
matched = true
deferredGroups |= nestedMetadata.DeferredIPCIDRMatchGroups
deferredGroups |= metadata.DeferredIPCIDRMatchGroups
}
}
snapshot.restore(metadata)
if matched {
metadata.DeferredIPCIDRMatchGroups |= deferredGroups
}
return matched
}
func (r *RuleSetItem) nestedMetadata(metadata *adapter.InboundContext) adapter.InboundContext {
nestedMetadata := *metadata
nestedMetadata.ResetRuleMatchCache()
nestedMetadata.IPCIDRMatchSource = r.ipCidrMatchSource
nestedMetadata.IPCIDRAcceptEmpty = r.ipCidrAcceptEmpty
return nestedMetadata
func (r *RuleSetItem) prepareNestedMatch(metadata *adapter.InboundContext) {
metadata.ResetRuleMatchCache()
metadata.IPCIDRMatchSource = r.ipCidrMatchSource
metadata.IPCIDRAcceptEmpty = r.ipCidrAcceptEmpty
}
type mergeableRuleProvider interface {
@@ -130,17 +135,19 @@ func matchAnyHeadlessRule(rules []adapter.HeadlessRule, metadata *adapter.Inboun
matched bool
deferredGroups uint8
)
snapshot := snapshotRuleMatch(metadata)
for _, rule := range rules {
nestedMetadata := *metadata
nestedMetadata.ResetRuleMatchCache()
if rule.Match(&nestedMetadata) {
if nestedMetadata.DeferredIPCIDRMatchGroups == 0 {
metadata.ResetRuleMatchCache()
if rule.Match(metadata) {
if metadata.DeferredIPCIDRMatchGroups == 0 {
snapshot.restore(metadata)
return true
}
matched = true
deferredGroups |= nestedMetadata.DeferredIPCIDRMatchGroups
deferredGroups |= metadata.DeferredIPCIDRMatchGroups
}
}
snapshot.restore(metadata)
if matched {
metadata.DeferredIPCIDRMatchGroups |= deferredGroups
}