Improve rule actions

This commit is contained in:
世界
2024-11-06 17:30:40 +08:00
parent eabe4dde4c
commit 8159c1f422
10 changed files with 414 additions and 138 deletions

View File

@@ -8,8 +8,10 @@ import (
"time"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
R "github.com/sagernet/sing-box/route/rule"
"github.com/sagernet/sing-dns"
tun "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/cache"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
@@ -48,38 +50,63 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int,
if ruleIndex != -1 {
dnsRules = dnsRules[ruleIndex+1:]
}
for currentRuleIndex, rule := range dnsRules {
if rule.WithAddressLimit() && !isAddressQuery {
for currentRuleIndex, currentRule := range dnsRules {
if currentRule.WithAddressLimit() && !isAddressQuery {
continue
}
metadata.ResetRuleCache()
if rule.Match(metadata) {
if currentRule.Match(metadata) {
displayRuleIndex := currentRuleIndex
if displayRuleIndex != -1 {
displayRuleIndex += displayRuleIndex + 1
}
if routeAction, isRoute := rule.Action().(*R.RuleActionDNSRoute); isRoute {
transport, loaded := r.transportMap[routeAction.Server]
ruleDescription := currentRule.String()
if ruleDescription != "" {
r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] ", currentRule, " => ", currentRule.Action())
} else {
r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action())
}
switch action := currentRule.Action().(type) {
case *R.RuleActionDNSRoute:
transport, loaded := r.transportMap[action.Server]
if !loaded {
r.dnsLogger.ErrorContext(ctx, "transport not found: ", routeAction.Server)
r.dnsLogger.ErrorContext(ctx, "transport not found: ", action.Server)
continue
}
_, isFakeIP := transport.(adapter.FakeIPTransport)
if isFakeIP && !allowFakeIP {
continue
}
options.DisableCache = isFakeIP || routeAction.DisableCache
options.RewriteTTL = routeAction.RewriteTTL
options.ClientSubnet = routeAction.ClientSubnet
if isFakeIP || action.DisableCache {
options.DisableCache = true
}
if action.RewriteTTL != nil {
options.RewriteTTL = action.RewriteTTL
}
if action.ClientSubnet.IsValid() {
options.ClientSubnet = action.ClientSubnet
}
if domainStrategy, dsLoaded := r.transportDomainStrategy[transport]; dsLoaded {
options.Strategy = domainStrategy
} else {
options.Strategy = r.defaultDomainStrategy
}
r.dnsLogger.DebugContext(ctx, "match[", displayRuleIndex, "] ", rule.String(), " => ", rule.Action())
return transport, options, rule, currentRuleIndex
} else {
return nil, options, rule, currentRuleIndex
r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action())
return transport, options, currentRule, currentRuleIndex
case *R.RuleActionDNSRouteOptions:
if action.DisableCache {
options.DisableCache = true
}
if action.RewriteTTL != nil {
options.RewriteTTL = action.RewriteTTL
}
if action.ClientSubnet.IsValid() {
options.ClientSubnet = action.ClientSubnet
}
r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action())
case *R.RuleActionReject:
r.logger.DebugContext(ctx, "match[", displayRuleIndex, "] => ", currentRule.Action())
return nil, options, currentRule, currentRuleIndex
}
}
}
@@ -127,6 +154,17 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er
dnsCtx := adapter.OverrideContext(ctx)
var addressLimit bool
transport, options, rule, ruleIndex = r.matchDNS(ctx, true, ruleIndex, isAddressQuery(message))
if rule != nil {
switch action := rule.Action().(type) {
case *R.RuleActionReject:
switch action.Method {
case C.RuleActionRejectMethodDefault:
return dns.FixedResponse(message.Id, message.Question[0], nil, 0), nil
case C.RuleActionRejectMethodDrop:
return nil, tun.ErrDrop
}
}
}
if rule != nil && rule.WithAddressLimit() {
addressLimit = true
response, err = r.dnsClient.ExchangeWithResponseCheck(dnsCtx, transport, message, options, func(response *mDNS.Msg) bool {
@@ -238,6 +276,17 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS
if strategy != dns.DomainStrategyAsIS {
options.Strategy = strategy
}
if rule != nil {
switch action := rule.Action().(type) {
case *R.RuleActionReject:
switch action.Method {
case C.RuleActionRejectMethodDefault:
return nil, nil
case C.RuleActionRejectMethodDrop:
return nil, tun.ErrDrop
}
}
}
if rule != nil && rule.WithAddressLimit() {
addressLimit = true
responseAddrs, err = r.dnsClient.LookupWithResponseCheck(dnsCtx, transport, domain, options, func(responseAddrs []netip.Addr) bool {