dns: make rule strategy legacy-only

This commit is contained in:
世界
2026-03-29 00:27:59 +08:00
parent 036ef04da1
commit 4df38c3244
8 changed files with 378 additions and 531 deletions

View File

@@ -15,62 +15,31 @@ import (
"github.com/stretchr/testify/require"
)
func TestReproLookupWithRulesIgnoresRouteStrategy(t *testing.T) {
func TestReproLookupWithRulesUsesRequestStrategy(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
router := newTestRouter(t, []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeEvaluate,
RouteOptions: option.DNSRouteActionOptions{Server: "default"},
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected",
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
},
}, &fakeDNSTransportManager{
var qTypes []uint16
router := newTestRouter(t, nil, &fakeDNSTransportManager{
defaultTransport: defaultTransport,
transports: map[string]adapter.DNSTransport{
"default": defaultTransport,
"selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP},
"default": defaultTransport,
},
}, &fakeDNSClient{
exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) {
if transport.Tag() == "default" {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("1.1.1.1")}, 60), nil
}
switch message.Question[0].Qtype {
case mDNS.TypeA:
qTypes = append(qTypes, message.Question[0].Qtype)
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2.2.2.2")}, 60), nil
case mDNS.TypeAAAA:
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::1")}, 60), nil
default:
return nil, errors.New("unexpected qtype")
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::1")}, 60), nil
},
})
addrs, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
addrs, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{
Strategy: C.DomainStrategyIPv4Only,
})
require.NoError(t, err)
require.Equal(t, []uint16{mDNS.TypeA}, qTypes)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addrs)
}

View File

@@ -38,22 +38,23 @@ type dnsRuleSetCallback struct {
}
type Router struct {
ctx context.Context
logger logger.ContextLogger
transport adapter.DNSTransportManager
outbound adapter.OutboundManager
client adapter.DNSClient
rawRules []option.DNSRule
rules []adapter.DNSRule
defaultDomainStrategy C.DomainStrategy
dnsReverseMapping freelru.Cache[netip.Addr, string]
platformInterface adapter.PlatformInterface
legacyAddressFilterMode bool
rulesAccess sync.RWMutex
closing bool
ruleSetCallbacks []dnsRuleSetCallback
runtimeRuleError error
deprecatedReported bool
ctx context.Context
logger logger.ContextLogger
transport adapter.DNSTransportManager
outbound adapter.OutboundManager
client adapter.DNSClient
rawRules []option.DNSRule
rules []adapter.DNSRule
defaultDomainStrategy C.DomainStrategy
dnsReverseMapping freelru.Cache[netip.Addr, string]
platformInterface adapter.PlatformInterface
legacyDNSMode bool
rulesAccess sync.RWMutex
closing bool
ruleSetCallbacks []dnsRuleSetCallback
runtimeRuleError error
addressFilterDeprecatedReported bool
ruleStrategyDeprecatedReported bool
}
func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOptions) *Router {
@@ -152,17 +153,21 @@ func (r *Router) rebuildRules(startRules bool) error {
if r.isClosing() {
return nil
}
newRules, legacyAddressFilterMode, err := r.buildRules(startRules)
newRules, legacyDNSMode, err := r.buildRules(startRules)
if err != nil {
if r.isClosing() {
return nil
}
return err
}
shouldReportDeprecated := startRules &&
legacyAddressFilterMode &&
!r.deprecatedReported &&
shouldReportAddressFilterDeprecated := startRules &&
legacyDNSMode &&
!r.addressFilterDeprecatedReported &&
common.Any(newRules, func(rule adapter.DNSRule) bool { return rule.WithAddressLimit() })
shouldReportRuleStrategyDeprecated := startRules &&
legacyDNSMode &&
!r.ruleStrategyDeprecatedReported &&
hasDNSRuleActionStrategy(r.rawRules)
r.rulesAccess.Lock()
if r.closing {
r.rulesAccess.Unlock()
@@ -171,16 +176,22 @@ func (r *Router) rebuildRules(startRules bool) error {
}
oldRules := r.rules
r.rules = newRules
r.legacyAddressFilterMode = legacyAddressFilterMode
r.legacyDNSMode = legacyDNSMode
r.runtimeRuleError = nil
if shouldReportDeprecated {
r.deprecatedReported = true
if shouldReportAddressFilterDeprecated {
r.addressFilterDeprecatedReported = true
}
if shouldReportRuleStrategyDeprecated {
r.ruleStrategyDeprecatedReported = true
}
r.rulesAccess.Unlock()
closeRules(oldRules)
if shouldReportDeprecated {
if shouldReportAddressFilterDeprecated {
deprecated.Report(r.ctx, deprecated.OptionLegacyDNSAddressFilter)
}
if shouldReportRuleStrategyDeprecated {
deprecated.Report(r.ctx, deprecated.OptionLegacyDNSRuleStrategy)
}
return nil
}
@@ -192,19 +203,19 @@ func (r *Router) isClosing() bool {
func (r *Router) buildRules(startRules bool) ([]adapter.DNSRule, bool, error) {
router := service.FromContext[adapter.Router](r.ctx)
legacyAddressFilterMode, err := resolveLegacyAddressFilterMode(router, r.rawRules)
legacyDNSMode, err := resolveLegacyDNSMode(router, r.rawRules)
if err != nil {
return nil, false, err
}
if !legacyAddressFilterMode {
err = validateNonLegacyAddressFilterRules(r.rawRules)
if !legacyDNSMode {
err = validateLegacyDNSModeDisabledRules(r.rawRules)
if err != nil {
return nil, false, err
}
}
newRules := make([]adapter.DNSRule, 0, len(r.rawRules))
for i, ruleOptions := range r.rawRules {
dnsRule, err := R.NewDNSRule(r.ctx, r.logger, ruleOptions, true, legacyAddressFilterMode)
dnsRule, err := R.NewDNSRule(r.ctx, r.logger, ruleOptions, true, legacyDNSMode)
if err != nil {
closeRules(newRules)
return nil, false, E.Cause(err, "parse dns rule[", i, "]")
@@ -220,7 +231,7 @@ func (r *Router) buildRules(startRules bool) ([]adapter.DNSRule, bool, error) {
}
}
}
return newRules, legacyAddressFilterMode, nil
return newRules, legacyDNSMode, nil
}
func closeRules(rules []adapter.DNSRule) {
@@ -349,12 +360,7 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int,
return transport, nil, -1
}
func (r *Router) applyDNSRouteOptions(options *adapter.DNSQueryOptions, routeOptions R.RuleActionDNSRouteOptions) bool {
var strategyOverridden bool
if routeOptions.Strategy != C.DomainStrategyAsIS {
options.Strategy = routeOptions.Strategy
strategyOverridden = true
}
func (r *Router) applyDNSRouteOptions(options *adapter.DNSQueryOptions, routeOptions R.RuleActionDNSRouteOptions) {
if routeOptions.DisableCache {
options.DisableCache = true
}
@@ -364,7 +370,6 @@ func (r *Router) applyDNSRouteOptions(options *adapter.DNSQueryOptions, routeOpt
if routeOptions.ClientSubnet.IsValid() {
options.ClientSubnet = routeOptions.ClientSubnet
}
return strategyOverridden
}
type dnsRouteStatus uint8
@@ -375,20 +380,20 @@ const (
dnsRouteStatusResolved
)
func (r *Router) resolveDNSRoute(action *R.RuleActionDNSRoute, allowFakeIP bool, options *adapter.DNSQueryOptions) (adapter.DNSTransport, dnsRouteStatus, bool) {
func (r *Router) resolveDNSRoute(action *R.RuleActionDNSRoute, allowFakeIP bool, options *adapter.DNSQueryOptions) (adapter.DNSTransport, dnsRouteStatus) {
transport, loaded := r.transport.Transport(action.Server)
if !loaded {
return nil, dnsRouteStatusMissing, false
return nil, dnsRouteStatusMissing
}
isFakeIP := transport.Type() == C.DNSTypeFakeIP
if isFakeIP && !allowFakeIP {
return transport, dnsRouteStatusSkipped, false
return transport, dnsRouteStatusSkipped
}
strategyOverridden := r.applyDNSRouteOptions(options, action.RuleActionDNSRouteOptions)
r.applyDNSRouteOptions(options, action.RuleActionDNSRouteOptions)
if isFakeIP {
options.DisableCache = true
}
return transport, dnsRouteStatusResolved, strategyOverridden
return transport, dnsRouteStatusResolved
}
func (r *Router) logRuleMatch(ctx context.Context, ruleIndex int, currentRule adapter.DNSRule) {
@@ -400,12 +405,10 @@ func (r *Router) logRuleMatch(ctx context.Context, ruleIndex int, currentRule ad
}
type exchangeWithRulesResult struct {
response *mDNS.Msg
transport adapter.DNSTransport
queryOptions adapter.DNSQueryOptions
strategyOverridden bool
rejectAction *R.RuleActionReject
err error
response *mDNS.Msg
transport adapter.DNSTransport
rejectAction *R.RuleActionReject
err error
}
func (r *Router) exchangeWithRules(ctx context.Context, message *mDNS.Msg, options adapter.DNSQueryOptions, allowFakeIP bool) exchangeWithRulesResult {
@@ -414,7 +417,6 @@ func (r *Router) exchangeWithRules(ctx context.Context, message *mDNS.Msg, optio
panic("no context")
}
effectiveOptions := options
effectiveStrategyOverridden := false
var savedResponse *mDNS.Msg
for currentRuleIndex, currentRule := range r.rules {
metadata.ResetRuleCache()
@@ -426,10 +428,10 @@ func (r *Router) exchangeWithRules(ctx context.Context, message *mDNS.Msg, optio
r.logRuleMatch(ctx, currentRuleIndex, currentRule)
switch action := currentRule.Action().(type) {
case *R.RuleActionDNSRouteOptions:
effectiveStrategyOverridden = r.applyDNSRouteOptions(&effectiveOptions, *action) || effectiveStrategyOverridden
r.applyDNSRouteOptions(&effectiveOptions, *action)
case *R.RuleActionEvaluate:
queryOptions := effectiveOptions
transport, status, _ := r.resolveDNSRoute(&R.RuleActionDNSRoute{
transport, status := r.resolveDNSRoute(&R.RuleActionDNSRoute{
Server: action.Server,
RuleActionDNSRouteOptions: action.RuleActionDNSRouteOptions,
}, allowFakeIP, &queryOptions)
@@ -454,7 +456,7 @@ func (r *Router) exchangeWithRules(ctx context.Context, message *mDNS.Msg, optio
savedResponse = response
case *R.RuleActionDNSRoute:
queryOptions := effectiveOptions
transport, status, strategyOverridden := r.resolveDNSRoute(action, allowFakeIP, &queryOptions)
transport, status := r.resolveDNSRoute(action, allowFakeIP, &queryOptions)
switch status {
case dnsRouteStatusMissing:
r.logger.ErrorContext(ctx, "transport not found: ", action.Server)
@@ -468,11 +470,9 @@ func (r *Router) exchangeWithRules(ctx context.Context, message *mDNS.Msg, optio
}
response, err := r.client.Exchange(adapter.OverrideContext(ctx), transport, message, exchangeOptions, nil)
return exchangeWithRulesResult{
response: response,
transport: transport,
queryOptions: queryOptions,
strategyOverridden: effectiveStrategyOverridden || strategyOverridden,
err: err,
response: response,
transport: transport,
err: err,
}
case *R.RuleActionReject:
switch action.Method {
@@ -486,23 +486,17 @@ func (r *Router) exchangeWithRules(ctx context.Context, message *mDNS.Msg, optio
},
Question: []mDNS.Question{message.Question[0]},
},
queryOptions: effectiveOptions,
strategyOverridden: effectiveStrategyOverridden,
rejectAction: action,
rejectAction: action,
}
case C.RuleActionRejectMethodDrop:
return exchangeWithRulesResult{
queryOptions: effectiveOptions,
strategyOverridden: effectiveStrategyOverridden,
rejectAction: action,
err: tun.ErrDrop,
rejectAction: action,
err: tun.ErrDrop,
}
}
case *R.RuleActionPredefined:
return exchangeWithRulesResult{
response: action.Response(message),
queryOptions: effectiveOptions,
strategyOverridden: effectiveStrategyOverridden,
response: action.Response(message),
}
}
}
@@ -514,36 +508,20 @@ func (r *Router) exchangeWithRules(ctx context.Context, message *mDNS.Msg, optio
}
response, err := r.client.Exchange(adapter.OverrideContext(ctx), transport, message, exchangeOptions, nil)
return exchangeWithRulesResult{
response: response,
transport: transport,
queryOptions: queryOptions,
strategyOverridden: effectiveStrategyOverridden,
err: err,
response: response,
transport: transport,
err: err,
}
}
type lookupWithRulesResponse struct {
addresses []netip.Addr
strategy C.DomainStrategy
explicitStrategy C.DomainStrategy
addresses []netip.Addr
}
func lookupInputStrategy(options adapter.DNSQueryOptions) C.DomainStrategy {
func (r *Router) resolveLookupStrategy(options adapter.DNSQueryOptions) C.DomainStrategy {
if options.LookupStrategy != C.DomainStrategyAsIS {
return options.LookupStrategy
}
return options.Strategy
}
func (r *Router) resolveLookupStrategy(options adapter.DNSQueryOptions, strategies ...C.DomainStrategy) C.DomainStrategy {
if options.LookupStrategy != C.DomainStrategyAsIS {
return options.LookupStrategy
}
for _, strategy := range strategies {
if strategy != C.DomainStrategyAsIS {
return strategy
}
}
if options.Strategy != C.DomainStrategyAsIS {
return options.Strategy
}
@@ -561,60 +539,6 @@ func lookupStrategyAllowsQueryType(strategy C.DomainStrategy, qType uint16) bool
}
}
func lookupStrategyOverride(queryOptions adapter.DNSQueryOptions, strategyOverridden bool) C.DomainStrategy {
if !strategyOverridden {
return C.DomainStrategyAsIS
}
return queryOptions.Strategy
}
func isSingleFamilyLookupStrategy(strategy C.DomainStrategy) bool {
return strategy == C.DomainStrategyIPv4Only || strategy == C.DomainStrategyIPv6Only
}
func resolveExplicitLookupStrategy(strategies ...C.DomainStrategy) (C.DomainStrategy, bool) {
var resolvedStrategy C.DomainStrategy
for _, strategy := range strategies {
if strategy == C.DomainStrategyAsIS {
continue
}
if resolvedStrategy == C.DomainStrategyAsIS {
resolvedStrategy = strategy
continue
}
if resolvedStrategy != strategy {
return C.DomainStrategyAsIS, true
}
}
return resolvedStrategy, false
}
func (r *Router) resolveLookupOutputStrategies(options adapter.DNSQueryOptions, explicitStrategies ...C.DomainStrategy) (C.DomainStrategy, C.DomainStrategy) {
inputStrategy := lookupInputStrategy(options)
if inputStrategy != C.DomainStrategyAsIS {
return inputStrategy, inputStrategy
}
explicitStrategy, explicitConflict := resolveExplicitLookupStrategy(explicitStrategies...)
sortStrategy := r.defaultDomainStrategy
if !explicitConflict && explicitStrategy != C.DomainStrategyAsIS {
sortStrategy = explicitStrategy
}
filterStrategy := C.DomainStrategyAsIS
if explicitConflict {
return sortStrategy, filterStrategy
}
if explicitStrategy != C.DomainStrategyAsIS {
if isSingleFamilyLookupStrategy(explicitStrategy) {
filterStrategy = explicitStrategy
}
return sortStrategy, filterStrategy
}
if isSingleFamilyLookupStrategy(sortStrategy) {
filterStrategy = sortStrategy
}
return sortStrategy, filterStrategy
}
func withLookupQueryMetadata(ctx context.Context, qType uint16) context.Context {
ctx, metadata := adapter.ExtendContext(ctx)
metadata.QueryType = qType
@@ -644,15 +568,16 @@ func filterAddressesByQueryType(addresses []netip.Addr, qType uint16) []netip.Ad
}
func (r *Router) lookupWithRules(ctx context.Context, domain string, options adapter.DNSQueryOptions) ([]netip.Addr, error) {
strategy := r.resolveLookupStrategy(options)
lookupOptions := options
if options.LookupStrategy != C.DomainStrategyAsIS {
lookupOptions.Strategy = options.LookupStrategy
if strategy != C.DomainStrategyAsIS {
lookupOptions.Strategy = strategy
}
if options.LookupStrategy == C.DomainStrategyIPv4Only {
if strategy == C.DomainStrategyIPv4Only {
response, err := r.lookupWithRulesType(ctx, domain, mDNS.TypeA, lookupOptions)
return response.addresses, err
}
if options.LookupStrategy == C.DomainStrategyIPv6Only {
if strategy == C.DomainStrategyIPv6Only {
response, err := r.lookupWithRulesType(ctx, domain, mDNS.TypeAAAA, lookupOptions)
return response.addresses, err
}
@@ -672,17 +597,10 @@ func (r *Router) lookupWithRules(ctx context.Context, domain string, options ada
return err
})
err := group.Run(ctx)
sortStrategy, filterStrategy := r.resolveLookupOutputStrategies(options, response4.explicitStrategy, response6.explicitStrategy)
if !lookupStrategyAllowsQueryType(filterStrategy, mDNS.TypeA) {
response4.addresses = nil
}
if !lookupStrategyAllowsQueryType(filterStrategy, mDNS.TypeAAAA) {
response6.addresses = nil
}
if len(response4.addresses) == 0 && len(response6.addresses) == 0 {
return nil, err
}
return sortAddresses(response4.addresses, response6.addresses, sortStrategy), nil
return sortAddresses(response4.addresses, response6.addresses, strategy), nil
}
func (r *Router) lookupWithRulesType(ctx context.Context, domain string, qType uint16, options adapter.DNSQueryOptions) (lookupWithRulesResponse, error) {
@@ -697,11 +615,7 @@ func (r *Router) lookupWithRulesType(ctx context.Context, domain string, qType u
}},
}
exchangeResult := r.exchangeWithRules(withLookupQueryMetadata(ctx, qType), request, options, false)
explicitStrategy := lookupStrategyOverride(exchangeResult.queryOptions, exchangeResult.strategyOverridden)
result := lookupWithRulesResponse{
strategy: r.resolveLookupStrategy(options, explicitStrategy),
explicitStrategy: explicitStrategy,
}
result := lookupWithRulesResponse{}
if exchangeResult.rejectAction != nil {
return result, exchangeResult.rejectAction.Error(ctx)
}
@@ -711,7 +625,7 @@ func (r *Router) lookupWithRulesType(ctx context.Context, domain string, qType u
if exchangeResult.response.Rcode != mDNS.RcodeSuccess {
return result, RcodeError(exchangeResult.response.Rcode)
}
if !lookupStrategyAllowsQueryType(result.strategy, qType) {
if !lookupStrategyAllowsQueryType(r.resolveLookupStrategy(options), qType) {
return result, nil
}
result.addresses = filterAddressesByQueryType(MessageToAddresses(exchangeResult.response), qType)
@@ -761,7 +675,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte
options.Strategy = r.defaultDomainStrategy
}
response, err = r.client.Exchange(ctx, transport, message, options, nil)
} else if !r.legacyAddressFilterMode {
} else if !r.legacyDNSMode {
exchangeResult := r.exchangeWithRules(ctx, message, options, true)
response, transport, err = exchangeResult.response, exchangeResult.transport, exchangeResult.err
} else {
@@ -878,7 +792,7 @@ func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQ
options.Strategy = r.defaultDomainStrategy
}
responseAddrs, err = r.client.Lookup(ctx, transport, domain, options, nil)
} else if !r.legacyAddressFilterMode {
} else if !r.legacyDNSMode {
responseAddrs, err = r.lookupWithRules(ctx, domain, options)
} else {
var (
@@ -975,7 +889,7 @@ func (r *Router) ResetNetwork() {
}
}
func hasDirectLegacyAddressFilterItemsInDefaultRule(rule option.DefaultDNSRule) bool {
func defaultRuleNeedsLegacyDNSModeFromAddressFilter(rule option.DefaultDNSRule) bool {
if rule.IPAcceptAny || rule.RuleSetIPCIDRAcceptEmpty {
return true
}
@@ -989,7 +903,7 @@ func hasResponseMatchFields(rule option.DefaultDNSRule) bool {
len(rule.ResponseExtra) > 0
}
func defaultRuleForcesNewDNSPath(rule option.DefaultDNSRule) bool {
func defaultRuleDisablesLegacyDNSMode(rule option.DefaultDNSRule) bool {
return rule.MatchResponse ||
hasResponseMatchFields(rule) ||
rule.Action == C.RuleActionTypeEvaluate ||
@@ -997,76 +911,84 @@ func defaultRuleForcesNewDNSPath(rule option.DefaultDNSRule) bool {
len(rule.QueryType) > 0
}
func resolveLegacyAddressFilterMode(router adapter.Router, rules []option.DNSRule) (bool, error) {
forceNew, needsLegacy, err := dnsRuleModeRequirements(router, rules)
func resolveLegacyDNSMode(router adapter.Router, rules []option.DNSRule) (bool, error) {
legacyDNSModeDisabled, needsLegacyDNSMode, needsLegacyDNSModeFromStrategy, err := dnsRuleModeRequirements(router, rules)
if err != nil {
return false, err
}
if forceNew {
if legacyDNSModeDisabled && needsLegacyDNSModeFromStrategy {
return false, E.New("DNS rule action strategy is only supported in legacyDNSMode")
}
if legacyDNSModeDisabled {
return false, nil
}
return needsLegacy, nil
return needsLegacyDNSMode, nil
}
func dnsRuleModeRequirements(router adapter.Router, rules []option.DNSRule) (bool, bool, error) {
var forceNew bool
var needsLegacy bool
func dnsRuleModeRequirements(router adapter.Router, rules []option.DNSRule) (bool, bool, bool, error) {
var legacyDNSModeDisabled bool
var needsLegacyDNSMode bool
var needsLegacyDNSModeFromStrategy bool
for i, rule := range rules {
ruleForceNew, ruleNeedsLegacy, err := dnsRuleModeRequirementsInRule(router, rule)
ruleLegacyDNSModeDisabled, ruleNeedsLegacyDNSMode, ruleNeedsLegacyDNSModeFromStrategy, err := dnsRuleModeRequirementsInRule(router, rule)
if err != nil {
return false, false, E.Cause(err, "dns rule[", i, "]")
return false, false, false, E.Cause(err, "dns rule[", i, "]")
}
forceNew = forceNew || ruleForceNew
needsLegacy = needsLegacy || ruleNeedsLegacy
legacyDNSModeDisabled = legacyDNSModeDisabled || ruleLegacyDNSModeDisabled
needsLegacyDNSMode = needsLegacyDNSMode || ruleNeedsLegacyDNSMode
needsLegacyDNSModeFromStrategy = needsLegacyDNSModeFromStrategy || ruleNeedsLegacyDNSModeFromStrategy
}
return forceNew, needsLegacy, nil
return legacyDNSModeDisabled, needsLegacyDNSMode, needsLegacyDNSModeFromStrategy, nil
}
func dnsRuleModeRequirementsInRule(router adapter.Router, rule option.DNSRule) (bool, bool, error) {
func dnsRuleModeRequirementsInRule(router adapter.Router, rule option.DNSRule) (bool, bool, bool, error) {
switch rule.Type {
case "", C.RuleTypeDefault:
return dnsRuleModeRequirementsInDefaultRule(router, rule.DefaultOptions)
case C.RuleTypeLogical:
forceNew := dnsRuleActionType(rule) == C.RuleActionTypeEvaluate
var needsLegacy bool
legacyDNSModeDisabled := dnsRuleActionType(rule) == C.RuleActionTypeEvaluate
needsLegacyDNSModeFromStrategy := dnsRuleActionHasStrategy(rule.LogicalOptions.DNSRuleAction)
needsLegacyDNSMode := needsLegacyDNSModeFromStrategy
for i, subRule := range rule.LogicalOptions.Rules {
subForceNew, subNeedsLegacy, err := dnsRuleModeRequirementsInRule(router, subRule)
subLegacyDNSModeDisabled, subNeedsLegacyDNSMode, subNeedsLegacyDNSModeFromStrategy, err := dnsRuleModeRequirementsInRule(router, subRule)
if err != nil {
return false, false, E.Cause(err, "sub rule[", i, "]")
return false, false, false, E.Cause(err, "sub rule[", i, "]")
}
forceNew = forceNew || subForceNew
needsLegacy = needsLegacy || subNeedsLegacy
legacyDNSModeDisabled = legacyDNSModeDisabled || subLegacyDNSModeDisabled
needsLegacyDNSMode = needsLegacyDNSMode || subNeedsLegacyDNSMode
needsLegacyDNSModeFromStrategy = needsLegacyDNSModeFromStrategy || subNeedsLegacyDNSModeFromStrategy
}
return forceNew, needsLegacy, nil
return legacyDNSModeDisabled, needsLegacyDNSMode, needsLegacyDNSModeFromStrategy, nil
default:
return false, false, nil
return false, false, false, nil
}
}
func dnsRuleModeRequirementsInDefaultRule(router adapter.Router, rule option.DefaultDNSRule) (bool, bool, error) {
forceNew := defaultRuleForcesNewDNSPath(rule)
needsLegacy := hasDirectLegacyAddressFilterItemsInDefaultRule(rule)
func dnsRuleModeRequirementsInDefaultRule(router adapter.Router, rule option.DefaultDNSRule) (bool, bool, bool, error) {
legacyDNSModeDisabled := defaultRuleDisablesLegacyDNSMode(rule)
needsLegacyDNSModeFromStrategy := dnsRuleActionHasStrategy(rule.DNSRuleAction)
needsLegacyDNSMode := defaultRuleNeedsLegacyDNSModeFromAddressFilter(rule) || needsLegacyDNSModeFromStrategy
if len(rule.RuleSet) == 0 {
return forceNew, needsLegacy, nil
return legacyDNSModeDisabled, needsLegacyDNSMode, needsLegacyDNSModeFromStrategy, nil
}
if router == nil {
return false, false, E.New("router service not found")
return false, false, false, E.New("router service not found")
}
for _, tag := range rule.RuleSet {
ruleSet, loaded := router.RuleSet(tag)
if !loaded {
return false, false, E.New("rule-set not found: ", tag)
return false, false, false, E.New("rule-set not found: ", tag)
}
metadata := ruleSet.Metadata()
// Rule sets are built from headless rules, so query_type is the only
// per-query DNS predicate they can contribute here. ip_version is not a
// headless-rule item and is therefore intentionally absent from metadata.
forceNew = forceNew || metadata.ContainsDNSQueryTypeRule
legacyDNSModeDisabled = legacyDNSModeDisabled || metadata.ContainsDNSQueryTypeRule
if !rule.RuleSetIPCIDRMatchSource && metadata.ContainsIPCIDRRule {
needsLegacy = true
needsLegacyDNSMode = true
}
}
return forceNew, needsLegacy, nil
return legacyDNSModeDisabled, needsLegacyDNSMode, needsLegacyDNSModeFromStrategy, nil
}
func referencedDNSRuleSetTags(rules []option.DNSRule) []string {
@@ -1096,9 +1018,9 @@ func referencedDNSRuleSetTags(rules []option.DNSRule) []string {
return tags
}
func validateNonLegacyAddressFilterRules(rules []option.DNSRule) error {
func validateLegacyDNSModeDisabledRules(rules []option.DNSRule) error {
for i, rule := range rules {
consumesResponse, err := validateNonLegacyAddressFilterRuleTree(rule)
consumesResponse, err := validateLegacyDNSModeDisabledRuleTree(rule)
if err != nil {
return E.Cause(err, "validate dns rule[", i, "]")
}
@@ -1110,14 +1032,14 @@ func validateNonLegacyAddressFilterRules(rules []option.DNSRule) error {
return nil
}
func validateNonLegacyAddressFilterRuleTree(rule option.DNSRule) (bool, error) {
func validateLegacyDNSModeDisabledRuleTree(rule option.DNSRule) (bool, error) {
switch rule.Type {
case "", C.RuleTypeDefault:
return validateNonLegacyAddressFilterDefaultRule(rule.DefaultOptions)
return validateLegacyDNSModeDisabledDefaultRule(rule.DefaultOptions)
case C.RuleTypeLogical:
var consumesResponse bool
for i, subRule := range rule.LogicalOptions.Rules {
subConsumesResponse, err := validateNonLegacyAddressFilterRuleTree(subRule)
subConsumesResponse, err := validateLegacyDNSModeDisabledRuleTree(subRule)
if err != nil {
return false, E.Cause(err, "sub rule[", i, "]")
}
@@ -1129,13 +1051,13 @@ func validateNonLegacyAddressFilterRuleTree(rule option.DNSRule) (bool, error) {
}
}
func validateNonLegacyAddressFilterDefaultRule(rule option.DefaultDNSRule) (bool, error) {
func validateLegacyDNSModeDisabledDefaultRule(rule option.DefaultDNSRule) (bool, error) {
hasResponseRecords := hasResponseMatchFields(rule)
if hasResponseRecords && !rule.MatchResponse {
return false, E.New("response_* items require match_response")
}
if (len(rule.IPCIDR) > 0 || rule.IPIsPrivate) && !rule.MatchResponse {
return false, E.New("ip_cidr and ip_is_private require match_response in DNS evaluate mode")
return false, E.New("ip_cidr and ip_is_private require match_response when legacyDNSMode is disabled")
}
// Intentionally do not reject rule_set here. A referenced rule set may mix
// destination-IP predicates with pre-response predicates such as domain items.
@@ -1143,14 +1065,48 @@ func validateNonLegacyAddressFilterDefaultRule(rule option.DefaultDNSRule) (bool
// pre-response evaluation instead of consuming DNS response state, while sibling
// non-response branches remain matchable.
if rule.IPAcceptAny {
return false, E.New("ip_accept_any is removed in DNS evaluate mode, use ip_cidr with match_response")
return false, E.New("ip_accept_any is removed when legacyDNSMode is disabled, use ip_cidr with match_response")
}
if rule.RuleSetIPCIDRAcceptEmpty {
return false, E.New("rule_set_ip_cidr_accept_empty is removed in DNS evaluate mode")
return false, E.New("rule_set_ip_cidr_accept_empty is removed when legacyDNSMode is disabled")
}
return rule.MatchResponse, nil
}
func hasDNSRuleActionStrategy(rules []option.DNSRule) bool {
for _, rule := range rules {
if dnsRuleHasActionStrategy(rule) {
return true
}
}
return false
}
func dnsRuleHasActionStrategy(rule option.DNSRule) bool {
switch rule.Type {
case "", C.RuleTypeDefault:
return dnsRuleActionHasStrategy(rule.DefaultOptions.DNSRuleAction)
case C.RuleTypeLogical:
if dnsRuleActionHasStrategy(rule.LogicalOptions.DNSRuleAction) {
return true
}
return hasDNSRuleActionStrategy(rule.LogicalOptions.Rules)
default:
return false
}
}
func dnsRuleActionHasStrategy(action option.DNSRuleAction) bool {
switch action.Action {
case "", C.RuleActionTypeRoute, C.RuleActionTypeEvaluate:
return C.DomainStrategy(action.RouteOptions.Strategy) != C.DomainStrategyAsIS
case C.RuleActionTypeRouteOptions:
return C.DomainStrategy(action.RouteOptionsOptions.Strategy) != C.DomainStrategyAsIS
default:
return false
}
}
func dnsRuleActionType(rule option.DNSRule) string {
switch rule.Type {
case "", C.RuleTypeDefault:

View File

@@ -296,10 +296,10 @@ func fixedHTTPSHintResponse(question mDNS.Question, addresses ...netip.Addr) *mD
return response
}
func TestValidateNewDNSRules_RequireMatchResponseForDirectIPCIDR(t *testing.T) {
func TestValidateLegacyDNSModeDisabledRules_RequireMatchResponseForDirectIPCIDR(t *testing.T) {
t.Parallel()
err := validateNonLegacyAddressFilterRules([]option.DNSRule{{
err := validateLegacyDNSModeDisabledRules([]option.DNSRule{{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
@@ -316,10 +316,10 @@ func TestValidateNewDNSRules_RequireMatchResponseForDirectIPCIDR(t *testing.T) {
require.ErrorContains(t, err, "ip_cidr and ip_is_private require match_response")
}
func TestValidateNewDNSRules_AllowMatchResponseWithoutEvaluate(t *testing.T) {
func TestValidateLegacyDNSModeDisabledRules_AllowMatchResponseWithoutEvaluate(t *testing.T) {
t.Parallel()
err := validateNonLegacyAddressFilterRules([]option.DNSRule{{
err := validateLegacyDNSModeDisabledRules([]option.DNSRule{{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
@@ -419,7 +419,7 @@ func TestInitializeRejectsDirectLegacyRuleWhenRuleSetForcesNew(t *testing.T) {
require.ErrorContains(t, err, "ip_cidr and ip_is_private require match_response")
}
func TestLookupLegacyModeDefersRuleSetDestinationIPMatch(t *testing.T) {
func TestLookupLegacyDNSModeDefersRuleSetDestinationIPMatch(t *testing.T) {
t.Parallel()
ctx := context.Background()
@@ -470,7 +470,7 @@ func TestLookupLegacyModeDefersRuleSetDestinationIPMatch(t *testing.T) {
},
})
require.True(t, router.legacyAddressFilterMode)
require.True(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{
LookupStrategy: C.DomainStrategyIPv4Only,
@@ -566,7 +566,7 @@ func TestRuleSetUpdateSetsRuntimeErrorWhenRebuildFails(t *testing.T) {
},
})
require.True(t, router.legacyAddressFilterMode)
require.True(t, router.legacyDNSMode)
fakeSet.updateMetadata(adapter.RuleSetMetadata{
ContainsDNSQueryTypeRule: true,
@@ -642,7 +642,7 @@ func TestCloseIgnoresSnapshottedRuleSetCallback(t *testing.T) {
require.NoError(t, router.runtimeRuleError)
}
func TestLookupLegacyModeDefersDirectDestinationIPMatch(t *testing.T) {
func TestLookupLegacyDNSModeDefersDirectDestinationIPMatch(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -680,7 +680,7 @@ func TestLookupLegacyModeDefersDirectDestinationIPMatch(t *testing.T) {
},
}, client)
require.True(t, router.legacyAddressFilterMode)
require.True(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{
LookupStrategy: C.DomainStrategyIPv4Only,
@@ -689,7 +689,7 @@ func TestLookupLegacyModeDefersDirectDestinationIPMatch(t *testing.T) {
require.Equal(t, []netip.Addr{netip.MustParseAddr("10.0.0.1")}, addresses)
}
func TestLookupLegacyModeFallsBackAfterRejectedAddressLimitResponse(t *testing.T) {
func TestLookupLegacyDNSModeFallsBackAfterRejectedAddressLimitResponse(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -738,7 +738,7 @@ func TestLookupLegacyModeFallsBackAfterRejectedAddressLimitResponse(t *testing.T
require.Equal(t, []string{"private", "default"}, lookups)
}
func TestLookupLegacyModeRuleSetAcceptEmptyDoesNotTreatMismatchAsEmpty(t *testing.T) {
func TestLookupLegacyDNSModeRuleSetAcceptEmptyDoesNotTreatMismatchAsEmpty(t *testing.T) {
t.Parallel()
ctx := context.Background()
@@ -810,7 +810,7 @@ func TestLookupLegacyModeRuleSetAcceptEmptyDoesNotTreatMismatchAsEmpty(t *testin
},
})
require.True(t, router.legacyAddressFilterMode)
require.True(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{
LookupStrategy: C.DomainStrategyIPv4Only,
@@ -831,7 +831,7 @@ func TestDNSResponseAddressesMatchesMessageToAddressesForHTTPSHints(t *testing.T
require.Equal(t, MessageToAddresses(response), adapter.DNSResponseAddresses(response))
}
func TestExchangeNewModeEvaluateMatchResponseRoute(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseRoute(t *testing.T) {
t.Parallel()
transportManager := &fakeDNSTransportManager{
@@ -890,7 +890,7 @@ func TestExchangeNewModeEvaluateMatchResponseRoute(t *testing.T) {
require.Equal(t, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, MessageToAddresses(response))
}
func TestExchangeNewModeEvaluateMatchResponseRouteIgnoresTTL(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseRouteIgnoresTTL(t *testing.T) {
t.Parallel()
transportManager := &fakeDNSTransportManager{
@@ -949,7 +949,7 @@ func TestExchangeNewModeEvaluateMatchResponseRouteIgnoresTTL(t *testing.T) {
require.Equal(t, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, MessageToAddresses(response))
}
func TestExchangeNewModeEvaluateMatchResponseRouteWithHTTPSHints(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseRouteWithHTTPSHints(t *testing.T) {
t.Parallel()
transportManager := &fakeDNSTransportManager{
@@ -1008,7 +1008,7 @@ func TestExchangeNewModeEvaluateMatchResponseRouteWithHTTPSHints(t *testing.T) {
require.Equal(t, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, MessageToAddresses(response))
}
func TestExchangeNewModeEvaluateDoesNotLeakAddressesToNextQuery(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledEvaluateDoesNotLeakAddressesToNextQuery(t *testing.T) {
t.Parallel()
transportManager := &fakeDNSTransportManager{
@@ -1079,7 +1079,7 @@ func TestExchangeNewModeEvaluateDoesNotLeakAddressesToNextQuery(t *testing.T) {
require.Equal(t, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, MessageToAddresses(response))
}
func TestExchangeNewModeEvaluateRouteResolutionFailureClearsResponse(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledEvaluateRouteResolutionFailureClearsResponse(t *testing.T) {
t.Parallel()
transportManager := &fakeDNSTransportManager{
@@ -1152,7 +1152,7 @@ func TestExchangeNewModeEvaluateRouteResolutionFailureClearsResponse(t *testing.
require.Equal(t, []netip.Addr{netip.MustParseAddr("4.4.4.4")}, MessageToAddresses(response))
}
func TestExchangeNewModeEvaluateExchangeFailureUsesMatchResponseBooleanSemantics(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledEvaluateExchangeFailureUsesMatchResponseBooleanSemantics(t *testing.T) {
t.Parallel()
testCases := []struct {
@@ -1235,7 +1235,7 @@ func TestExchangeNewModeEvaluateExchangeFailureUsesMatchResponseBooleanSemantics
}
}
func TestLookupNewModeAllowsPartialSuccess(t *testing.T) {
func TestLookupLegacyDNSModeDisabledAllowsPartialSuccess(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1257,14 +1257,14 @@ func TestLookupNewModeAllowsPartialSuccess(t *testing.T) {
}
},
})
router.legacyAddressFilterMode = false
router.legacyDNSMode = false
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("1.1.1.1")}, addresses)
}
func TestLookupNewModeSkipsFakeIPRule(t *testing.T) {
func TestLookupLegacyDNSModeDisabledSkipsFakeIPRule(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1294,14 +1294,14 @@ func TestLookupNewModeSkipsFakeIPRule(t *testing.T) {
return FixedResponse(0, message.Question[0], nil, 60), nil
},
})
router.legacyAddressFilterMode = false
router.legacyDNSMode = false
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses)
}
func TestLookupNewModeEvaluateSkipFakeIPPreservesResponse(t *testing.T) {
func TestLookupLegacyDNSModeDisabledEvaluateSkipFakeIPPreservesResponse(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1374,14 +1374,14 @@ func TestLookupNewModeEvaluateSkipFakeIPPreservesResponse(t *testing.T) {
}
},
})
router.legacyAddressFilterMode = false
router.legacyDNSMode = false
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses)
}
func TestLookupNewModeUsesQueryTypeRule(t *testing.T) {
func TestLookupLegacyDNSModeDisabledUsesQueryTypeRule(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1417,14 +1417,14 @@ func TestLookupNewModeUsesQueryTypeRule(t *testing.T) {
}
},
})
require.False(t, router.legacyAddressFilterMode)
require.False(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("9.9.9.9")}, addresses)
}
func TestLookupNewModeUsesRuleSetQueryTypeRule(t *testing.T) {
func TestLookupLegacyDNSModeDisabledUsesRuleSetQueryTypeRule(t *testing.T) {
t.Parallel()
ctx := context.Background()
@@ -1483,7 +1483,7 @@ func TestLookupNewModeUsesRuleSetQueryTypeRule(t *testing.T) {
}
},
})
require.False(t, router.legacyAddressFilterMode)
require.False(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
@@ -1493,7 +1493,7 @@ func TestLookupNewModeUsesRuleSetQueryTypeRule(t *testing.T) {
}, addresses)
}
func TestLookupNewModeUsesIPVersionRule(t *testing.T) {
func TestLookupLegacyDNSModeDisabledUsesIPVersionRule(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1532,73 +1532,113 @@ func TestLookupNewModeUsesIPVersionRule(t *testing.T) {
}
},
})
require.False(t, router.legacyAddressFilterMode)
require.False(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("3.3.3.3"), netip.MustParseAddr("2001:db8::9")}, addresses)
}
func TestLookupNewModeAppliesRouteStrategyAfterEvaluate(t *testing.T) {
func TestInitializeRejectsDNSRuleStrategyWhenLegacyDNSModeIsDisabledByEvaluate(t *testing.T) {
t.Parallel()
router := &Router{
ctx: context.Background(),
logger: log.NewNOPFactory().NewLogger("dns"),
transport: &fakeDNSTransportManager{},
client: &fakeDNSClient{},
rawRules: make([]option.DNSRule, 0, 1),
rules: make([]adapter.DNSRule, 0, 1),
defaultDomainStrategy: C.DomainStrategyAsIS,
}
err := router.Initialize([]option.DNSRule{{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeEvaluate,
RouteOptions: option.DNSRouteActionOptions{
Server: "default",
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
}})
require.ErrorContains(t, err, "legacyDNSMode")
}
func TestInitializeRejectsDNSRuleStrategyWhenLegacyDNSModeIsDisabledByMatchResponse(t *testing.T) {
t.Parallel()
router := &Router{
ctx: context.Background(),
logger: log.NewNOPFactory().NewLogger("dns"),
transport: &fakeDNSTransportManager{},
client: &fakeDNSClient{},
rawRules: make([]option.DNSRule, 0, 1),
rules: make([]adapter.DNSRule, 0, 1),
defaultDomainStrategy: C.DomainStrategyAsIS,
}
err := router.Initialize([]option.DNSRule{{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRouteOptions,
RouteOptionsOptions: option.DNSRouteOptionsActionOptions{
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
}})
require.ErrorContains(t, err, "legacyDNSMode")
}
func TestLookupLegacyDNSModeUsesRouteStrategy(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
router := newTestRouter(t, []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeEvaluate,
RouteOptions: option.DNSRouteActionOptions{Server: "default"},
selectedTransport := &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP}
router := newTestRouter(t, []option.DNSRule{{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected",
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected",
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
},
}, &fakeDNSTransportManager{
}}, &fakeDNSTransportManager{
defaultTransport: defaultTransport,
transports: map[string]adapter.DNSTransport{
"default": defaultTransport,
"selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP},
"selected": selectedTransport,
},
}, &fakeDNSClient{
exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) {
if transport.Tag() == "default" {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("1.1.1.1")}, 60), nil
}
switch message.Question[0].Qtype {
case mDNS.TypeA:
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2.2.2.2")}, 60), nil
case mDNS.TypeAAAA:
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::1")}, 60), nil
default:
return nil, errors.New("unexpected qtype")
}
lookup: func(transport adapter.DNSTransport, domain string, options adapter.DNSQueryOptions) ([]netip.Addr, *mDNS.Msg, error) {
require.Equal(t, "selected", transport.Tag())
require.Equal(t, C.DomainStrategyIPv4Only, options.Strategy)
return []netip.Addr{netip.MustParseAddr("2.2.2.2")}, nil, nil
},
})
require.True(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses)
}
func TestLookupNewModeReturnsRejectedErrorForRejectAction(t *testing.T) {
func TestLookupLegacyDNSModeDisabledReturnsRejectedErrorForRejectAction(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1623,7 +1663,7 @@ func TestLookupNewModeReturnsRejectedErrorForRejectAction(t *testing.T) {
"default": defaultTransport,
},
}, &fakeDNSClient{})
require.False(t, router.legacyAddressFilterMode)
require.False(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.Nil(t, addresses)
@@ -1631,7 +1671,7 @@ func TestLookupNewModeReturnsRejectedErrorForRejectAction(t *testing.T) {
require.True(t, rulepkg.IsRejected(err))
}
func TestExchangeNewModeReturnsRefusedResponseForRejectAction(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledReturnsRefusedResponseForRejectAction(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1656,7 +1696,7 @@ func TestExchangeNewModeReturnsRefusedResponseForRejectAction(t *testing.T) {
"default": defaultTransport,
},
}, &fakeDNSClient{})
require.False(t, router.legacyAddressFilterMode)
require.False(t, router.legacyDNSMode)
response, err := router.Exchange(context.Background(), &mDNS.Msg{
Question: []mDNS.Question{fixedQuestion("example.com", mDNS.TypeA)},
@@ -1666,7 +1706,7 @@ func TestExchangeNewModeReturnsRefusedResponseForRejectAction(t *testing.T) {
require.Equal(t, []mDNS.Question{fixedQuestion("example.com", mDNS.TypeA)}, response.Question)
}
func TestLookupNewModeFiltersPerQueryTypeAddressesBeforeMerging(t *testing.T) {
func TestLookupLegacyDNSModeDisabledFiltersPerQueryTypeAddressesBeforeMerging(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
@@ -1694,7 +1734,7 @@ func TestLookupNewModeFiltersPerQueryTypeAddressesBeforeMerging(t *testing.T) {
"default": defaultTransport,
},
}, &fakeDNSClient{})
require.False(t, router.legacyAddressFilterMode)
require.False(t, router.legacyDNSMode)
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
@@ -1704,241 +1744,64 @@ func TestLookupNewModeFiltersPerQueryTypeAddressesBeforeMerging(t *testing.T) {
}, addresses)
}
func TestLookupNewModePrefersExplicitBranchStrategyOverDefault(t *testing.T) {
func TestLookupLegacyDNSModeDisabledUsesInputStrategy(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
router := newTestRouter(t, []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeEvaluate,
RouteOptions: option.DNSRouteActionOptions{Server: "upstream"},
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
ResponseAnswer: badoption.Listable[option.DNSRecordOptions]{mustRecord(t, "example.com. IN AAAA 2001:db8::1")},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected",
Strategy: option.DomainStrategy(C.DomainStrategyIPv6Only),
},
},
},
},
}, &fakeDNSTransportManager{
var qTypes []uint16
router := newTestRouter(t, nil, &fakeDNSTransportManager{
defaultTransport: defaultTransport,
transports: map[string]adapter.DNSTransport{
"default": defaultTransport,
"upstream": &fakeDNSTransport{tag: "upstream", transportType: C.DNSTypeUDP},
"selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP},
"default": defaultTransport,
},
}, &fakeDNSClient{
exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) {
switch transport.Tag() {
case "upstream":
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("1.1.1.1")}, 60), nil
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::1")}, 60), nil
case "selected":
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2.2.2.2")}, 60), nil
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::2")}, 60), nil
case "default":
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("4.4.4.4")}, 60), nil
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::4")}, 60), nil
default:
return nil, errors.New("unexpected transport")
}
},
})
router.defaultDomainStrategy = C.DomainStrategyIPv4Only
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2001:db8::2")}, addresses)
}
func TestLookupNewModeKeepsExplicitBranchStrategyMatchingInput(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
router := newTestRouter(t, []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeEvaluate,
RouteOptions: option.DNSRouteActionOptions{Server: "upstream"},
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
ResponseAnswer: badoption.Listable[option.DNSRecordOptions]{mustRecord(t, "example.com. IN A 1.1.1.1")},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected4",
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
ResponseAnswer: badoption.Listable[option.DNSRecordOptions]{mustRecord(t, "example.com. IN AAAA 2001:db8::1")},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected6",
Strategy: option.DomainStrategy(C.DomainStrategyIPv6Only),
},
},
},
},
}, &fakeDNSTransportManager{
defaultTransport: defaultTransport,
transports: map[string]adapter.DNSTransport{
"default": defaultTransport,
"upstream": &fakeDNSTransport{tag: "upstream", transportType: C.DNSTypeUDP},
"selected4": &fakeDNSTransport{tag: "selected4", transportType: C.DNSTypeUDP},
"selected6": &fakeDNSTransport{tag: "selected6", transportType: C.DNSTypeUDP},
},
}, &fakeDNSClient{
exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) {
switch transport.Tag() {
case "upstream":
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("1.1.1.1")}, 60), nil
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::1")}, 60), nil
case "selected4":
qTypes = append(qTypes, message.Question[0].Qtype)
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2.2.2.2")}, 60), nil
case "selected6":
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::2")}, 60), nil
default:
return nil, errors.New("unexpected transport")
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::2")}, 60), nil
},
})
router.legacyAddressFilterMode = false
router.legacyDNSMode = false
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{
Strategy: C.DomainStrategyIPv4Only,
})
require.NoError(t, err)
require.Equal(t, []uint16{mDNS.TypeA}, qTypes)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses)
}
func TestLookupNewModeKeepsConflictingExplicitBranchStrategies(t *testing.T) {
func TestLookupLegacyDNSModeDisabledUsesDefaultStrategy(t *testing.T) {
t.Parallel()
defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}
router := newTestRouter(t, []option.DNSRule{
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeEvaluate,
RouteOptions: option.DNSRouteActionOptions{Server: "upstream"},
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
ResponseAnswer: badoption.Listable[option.DNSRecordOptions]{mustRecord(t, "example.com. IN A 1.1.1.1")},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected4",
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
},
{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
MatchResponse: true,
ResponseAnswer: badoption.Listable[option.DNSRecordOptions]{mustRecord(t, "example.com. IN AAAA 2001:db8::1")},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "selected6",
Strategy: option.DomainStrategy(C.DomainStrategyIPv6Only),
},
},
},
},
}, &fakeDNSTransportManager{
var qTypes []uint16
router := newTestRouter(t, nil, &fakeDNSTransportManager{
defaultTransport: defaultTransport,
transports: map[string]adapter.DNSTransport{
"default": defaultTransport,
"upstream": &fakeDNSTransport{tag: "upstream", transportType: C.DNSTypeUDP},
"selected4": &fakeDNSTransport{tag: "selected4", transportType: C.DNSTypeUDP},
"selected6": &fakeDNSTransport{tag: "selected6", transportType: C.DNSTypeUDP},
"default": defaultTransport,
},
}, &fakeDNSClient{
exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) {
switch transport.Tag() {
case "upstream":
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("1.1.1.1")}, 60), nil
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::1")}, 60), nil
case "selected4":
qTypes = append(qTypes, message.Question[0].Qtype)
if message.Question[0].Qtype == mDNS.TypeA {
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2.2.2.2")}, 60), nil
case "selected6":
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::2")}, 60), nil
default:
return nil, errors.New("unexpected transport")
}
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::2")}, 60), nil
},
})
router.legacyAddressFilterMode = false
router.defaultDomainStrategy = C.DomainStrategyIPv4Only
router.legacyDNSMode = false
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2"), netip.MustParseAddr("2001:db8::2")}, addresses)
require.Equal(t, []uint16{mDNS.TypeA}, qTypes)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses)
}
func TestExchangeNewModeLogicalMatchResponseIPCIDRFallsThrough(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledLogicalMatchResponseIPCIDRFallsThrough(t *testing.T) {
t.Parallel()
transportManager := &fakeDNSTransportManager{
@@ -2007,7 +1870,7 @@ func TestExchangeNewModeLogicalMatchResponseIPCIDRFallsThrough(t *testing.T) {
require.Equal(t, []netip.Addr{netip.MustParseAddr("4.4.4.4")}, MessageToAddresses(response))
}
func TestOldModeReportsLegacyAddressFilterDeprecation(t *testing.T) {
func TestLegacyDNSModeReportsLegacyAddressFilterDeprecation(t *testing.T) {
t.Parallel()
manager := &fakeDeprecatedManager{}
@@ -2038,3 +1901,38 @@ func TestOldModeReportsLegacyAddressFilterDeprecation(t *testing.T) {
require.Len(t, manager.features, 1)
require.Equal(t, deprecated.OptionLegacyDNSAddressFilter.Name, manager.features[0].Name)
}
func TestLegacyDNSModeReportsDNSRuleStrategyDeprecation(t *testing.T) {
t.Parallel()
manager := &fakeDeprecatedManager{}
ctx := service.ContextWith[deprecated.Manager](context.Background(), manager)
router := &Router{
ctx: ctx,
logger: log.NewNOPFactory().NewLogger("dns"),
client: &fakeDNSClient{},
rules: make([]adapter.DNSRule, 0, 1),
defaultDomainStrategy: C.DomainStrategyAsIS,
}
err := router.Initialize([]option.DNSRule{{
Type: C.RuleTypeDefault,
DefaultOptions: option.DefaultDNSRule{
RawDefaultDNSRule: option.RawDefaultDNSRule{
Domain: badoption.Listable[string]{"example.com"},
},
DNSRuleAction: option.DNSRuleAction{
Action: C.RuleActionTypeRoute,
RouteOptions: option.DNSRouteActionOptions{
Server: "default",
Strategy: option.DomainStrategy(C.DomainStrategyIPv4Only),
},
},
},
}})
require.NoError(t, err)
err = router.Start(adapter.StartStateStart)
require.NoError(t, err)
require.Len(t, manager.features, 1)
require.Equal(t, deprecated.OptionLegacyDNSRuleStrategy.Name, manager.features[0].Name)
}

View File

@@ -34,7 +34,11 @@ Tag of target server.
!!! question "Since sing-box 1.12.0"
Set domain strategy for this query.
!!! warning
`strategy` is deprecated and only supported in `legacyDNSMode`.
Set domain strategy for this query in `legacyDNSMode`.
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.

View File

@@ -34,7 +34,11 @@ icon: material/new-box
!!! question "自 sing-box 1.12.0 起"
为此查询设置域名策略。
!!! warning
`strategy` 已废弃,且仅在 `legacyDNSMode` 中可用。
`legacyDNSMode` 中为此查询设置域名策略。
可选项:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`

View File

@@ -14,6 +14,13 @@ check [Migration](../migration/#migrate-inline-acme-to-certificate-provider).
Old fields will be removed in sing-box 1.16.0.
#### `strategy` in DNS rule actions
`strategy` in DNS rule actions is deprecated
and only supported in `legacyDNSMode`.
Old fields will be removed in sing-box 1.16.0.
## 1.12.0
#### Legacy DNS server formats

View File

@@ -117,6 +117,14 @@ var OptionLegacyDNSAddressFilter = Note{
MigrationLink: "https://sing-box.sagernet.org/configuration/dns/rule/",
}
var OptionLegacyDNSRuleStrategy = Note{
Name: "legacy-dns-rule-strategy",
Description: "`strategy` in DNS rule actions",
DeprecatedVersion: "1.14.0",
ScheduledVersion: "1.16.0",
MigrationLink: "https://sing-box.sagernet.org/configuration/dns/rule_action/",
}
var Options = []Note{
OptionOutboundDNSRuleItem,
OptionMissingDomainResolver,
@@ -125,4 +133,5 @@ var Options = []Note{
OptionIPAcceptAny,
OptionRuleSetIPCIDRAcceptEmpty,
OptionLegacyDNSAddressFilter,
OptionLegacyDNSRuleStrategy,
}

View File

@@ -15,7 +15,7 @@ import (
"github.com/miekg/dns"
)
func NewDNSRule(ctx context.Context, logger log.ContextLogger, options option.DNSRule, checkServer bool, legacyAddressFilter bool) (adapter.DNSRule, error) {
func NewDNSRule(ctx context.Context, logger log.ContextLogger, options option.DNSRule, checkServer bool, legacyDNSMode bool) (adapter.DNSRule, error) {
switch options.Type {
case "", C.RuleTypeDefault:
if !options.DefaultOptions.IsValid() {
@@ -30,7 +30,7 @@ func NewDNSRule(ctx context.Context, logger log.ContextLogger, options option.DN
return nil, E.New("missing server field")
}
}
return NewDefaultDNSRule(ctx, logger, options.DefaultOptions, legacyAddressFilter)
return NewDefaultDNSRule(ctx, logger, options.DefaultOptions, legacyDNSMode)
case C.RuleTypeLogical:
if !options.LogicalOptions.IsValid() {
return nil, E.New("missing conditions")
@@ -44,7 +44,7 @@ func NewDNSRule(ctx context.Context, logger log.ContextLogger, options option.DN
return nil, E.New("missing server field")
}
}
return NewLogicalDNSRule(ctx, logger, options.LogicalOptions, legacyAddressFilter)
return NewLogicalDNSRule(ctx, logger, options.LogicalOptions, legacyDNSMode)
default:
return nil, E.New("unknown rule type: ", options.Type)
}
@@ -61,7 +61,7 @@ func (r *DefaultDNSRule) matchStates(metadata *adapter.InboundContext) ruleMatch
return r.abstractDefaultRule.matchStates(metadata)
}
func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options option.DefaultDNSRule, legacyAddressFilter bool) (*DefaultDNSRule, error) {
func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options option.DefaultDNSRule, legacyDNSMode bool) (*DefaultDNSRule, error) {
rule := &DefaultDNSRule{
abstractDefaultRule: abstractDefaultRule{
invert: options.Invert,
@@ -163,10 +163,10 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
rule.allItems = append(rule.allItems, item)
}
if options.IPAcceptAny {
if legacyAddressFilter {
if legacyDNSMode {
deprecated.Report(ctx, deprecated.OptionIPAcceptAny)
} else {
return nil, E.New("ip_accept_any is removed in DNS evaluate mode, use ip_cidr with match_response")
return nil, E.New("ip_accept_any is removed when legacyDNSMode is disabled, use ip_cidr with match_response")
}
item := NewIPAcceptAnyItem()
rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item)
@@ -321,10 +321,10 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
matchSource = true
}
if options.RuleSetIPCIDRAcceptEmpty {
if legacyAddressFilter {
if legacyDNSMode {
deprecated.Report(ctx, deprecated.OptionRuleSetIPCIDRAcceptEmpty)
} else {
return nil, E.New("rule_set_ip_cidr_accept_empty is removed in DNS evaluate mode")
return nil, E.New("rule_set_ip_cidr_accept_empty is removed when legacyDNSMode is disabled")
}
}
item := NewRuleSetItem(router, options.RuleSet, matchSource, options.RuleSetIPCIDRAcceptEmpty)
@@ -450,7 +450,7 @@ func (r *LogicalDNSRule) matchStatesForMatch(metadata *adapter.InboundContext) r
return stateSet
}
func NewLogicalDNSRule(ctx context.Context, logger log.ContextLogger, options option.LogicalDNSRule, legacyAddressFilter bool) (*LogicalDNSRule, error) {
func NewLogicalDNSRule(ctx context.Context, logger log.ContextLogger, options option.LogicalDNSRule, legacyDNSMode bool) (*LogicalDNSRule, error) {
r := &LogicalDNSRule{
abstractLogicalRule: abstractLogicalRule{
rules: make([]adapter.HeadlessRule, len(options.Rules)),
@@ -467,7 +467,7 @@ func NewLogicalDNSRule(ctx context.Context, logger log.ContextLogger, options op
return nil, E.New("unknown logical mode: ", options.Mode)
}
for i, subRule := range options.Rules {
rule, err := NewDNSRule(ctx, logger, subRule, false, legacyAddressFilter)
rule, err := NewDNSRule(ctx, logger, subRule, false, legacyDNSMode)
if err != nil {
return nil, E.Cause(err, "sub rule[", i, "]")
}