mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-09 07:40:11 +00:00
Inverted rules whose address filter conditions come from rule sets or logical rules were rejected during pre-lookup matching, so the lookup was never sent and the rules never matched; for plain ip rule sets this was a regression from the rule-set invert fix in 1.12.22. Pre-lookup matching now tracks whether the result depends on deferred address filter conditions and defers such rules to the response phase, while results already determined by evaluated conditions are still decided during pre-lookup.
166 lines
4.1 KiB
Go
166 lines
4.1 KiB
Go
package rule
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/sagernet/sing-box/adapter"
|
|
"github.com/sagernet/sing/common"
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
F "github.com/sagernet/sing/common/format"
|
|
)
|
|
|
|
var _ RuleItem = (*RuleSetItem)(nil)
|
|
|
|
type RuleSetItem struct {
|
|
router adapter.Router
|
|
tagList []string
|
|
setList []adapter.RuleSet
|
|
ipCidrMatchSource bool
|
|
ipCidrAcceptEmpty bool
|
|
}
|
|
|
|
func NewRuleSetItem(router adapter.Router, tagList []string, ipCIDRMatchSource bool, ipCidrAcceptEmpty bool) *RuleSetItem {
|
|
return &RuleSetItem{
|
|
router: router,
|
|
tagList: tagList,
|
|
ipCidrMatchSource: ipCIDRMatchSource,
|
|
ipCidrAcceptEmpty: ipCidrAcceptEmpty,
|
|
}
|
|
}
|
|
|
|
func (r *RuleSetItem) Start() error {
|
|
_ = r.Close()
|
|
for _, tag := range r.tagList {
|
|
ruleSet, loaded := r.router.RuleSet(tag)
|
|
if !loaded {
|
|
_ = r.Close()
|
|
return E.New("rule-set not found: ", tag)
|
|
}
|
|
ruleSet.IncRef()
|
|
r.setList = append(r.setList, ruleSet)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *RuleSetItem) Close() error {
|
|
for _, ruleSet := range r.setList {
|
|
ruleSet.DecRef()
|
|
}
|
|
clear(r.setList)
|
|
r.setList = nil
|
|
return nil
|
|
}
|
|
|
|
func (r *RuleSetItem) Match(metadata *adapter.InboundContext) bool {
|
|
for _, ruleSet := range r.setList {
|
|
nestedMetadata := r.nestedMetadata(metadata)
|
|
if ruleSet.Match(&nestedMetadata) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r *RuleSetItem) matchWithOuterGroups(metadata *adapter.InboundContext, outerGroups ruleGroupMatch) bool {
|
|
outerDone := outerGroups.done()
|
|
var (
|
|
matched bool
|
|
deferredGroups uint8
|
|
)
|
|
for _, ruleSet := range r.setList {
|
|
nestedMetadata := r.nestedMetadata(metadata)
|
|
if provider, isProvider := ruleSet.(mergeableRuleProvider); isProvider {
|
|
branch := provider.mergeableRule()
|
|
if branch != nil {
|
|
branchGroups, branchMatched := branch.evaluateForMerge(&nestedMetadata)
|
|
if branchMatched {
|
|
merged := outerGroups.mergeWith(branchGroups)
|
|
if merged.done() {
|
|
branchDeferredGroups := nestedMetadata.DeferredIPCIDRMatchGroups &^ uint8(merged.satisfied)
|
|
if branchDeferredGroups == 0 {
|
|
metadata.DeferredIPCIDRMatchGroups &^= uint8(merged.satisfied)
|
|
return true
|
|
}
|
|
matched = true
|
|
deferredGroups |= branchDeferredGroups
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
if outerDone && ruleSet.Match(&nestedMetadata) {
|
|
if nestedMetadata.DeferredIPCIDRMatchGroups == 0 {
|
|
return true
|
|
}
|
|
matched = true
|
|
deferredGroups |= nestedMetadata.DeferredIPCIDRMatchGroups
|
|
}
|
|
}
|
|
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
|
|
}
|
|
|
|
type mergeableRuleProvider interface {
|
|
mergeableRule() *DefaultHeadlessRule
|
|
}
|
|
|
|
func mergeableRuleIn(rules []adapter.HeadlessRule) *DefaultHeadlessRule {
|
|
if len(rules) != 1 {
|
|
return nil
|
|
}
|
|
rule, isDefault := rules[0].(*DefaultHeadlessRule)
|
|
if !isDefault || rule.invert || rule.ruleSetItem != nil {
|
|
return nil
|
|
}
|
|
return rule
|
|
}
|
|
|
|
func matchAnyHeadlessRule(rules []adapter.HeadlessRule, metadata *adapter.InboundContext) bool {
|
|
var (
|
|
matched bool
|
|
deferredGroups uint8
|
|
)
|
|
for _, rule := range rules {
|
|
nestedMetadata := *metadata
|
|
nestedMetadata.ResetRuleMatchCache()
|
|
if rule.Match(&nestedMetadata) {
|
|
if nestedMetadata.DeferredIPCIDRMatchGroups == 0 {
|
|
return true
|
|
}
|
|
matched = true
|
|
deferredGroups |= nestedMetadata.DeferredIPCIDRMatchGroups
|
|
}
|
|
}
|
|
if matched {
|
|
metadata.DeferredIPCIDRMatchGroups |= deferredGroups
|
|
}
|
|
return matched
|
|
}
|
|
|
|
func (r *RuleSetItem) ContainsDestinationIPCIDRRule() bool {
|
|
if r.ipCidrMatchSource {
|
|
return false
|
|
}
|
|
return common.Any(r.setList, func(ruleSet adapter.RuleSet) bool {
|
|
return ruleSet.Metadata().ContainsIPCIDRRule
|
|
})
|
|
}
|
|
|
|
func (r *RuleSetItem) String() string {
|
|
if len(r.tagList) == 1 {
|
|
return F.ToString("rule_set=", r.tagList[0])
|
|
} else {
|
|
return F.ToString("rule_set=[", strings.Join(r.tagList, " "), "]")
|
|
}
|
|
}
|