dns: reject evaluate fakeip servers

This commit is contained in:
世界
2026-04-01 21:28:34 +08:00
parent 40e40ea7a6
commit bbccdbcc92
2 changed files with 121 additions and 66 deletions

View File

@@ -272,6 +272,10 @@ func (r *Router) buildRules(startRules bool) ([]adapter.DNSRule, bool, dnsRuleMo
return nil, false, dnsRuleModeFlags{}, err
}
}
err = validateEvaluateFakeIPRules(r.rawRules, r.transport)
if err != nil {
return nil, false, dnsRuleModeFlags{}, err
}
newRules := make([]adapter.DNSRule, 0, len(r.rawRules))
for i, ruleOptions := range r.rawRules {
var dnsRule adapter.DNSRule
@@ -1078,6 +1082,27 @@ func validateLegacyDNSModeDisabledRules(rules []option.DNSRule) error {
return nil
}
func validateEvaluateFakeIPRules(rules []option.DNSRule, transportManager adapter.DNSTransportManager) error {
if transportManager == nil {
return nil
}
for i, rule := range rules {
if dnsRuleActionType(rule) != C.RuleActionTypeEvaluate {
continue
}
server := dnsRuleActionServer(rule)
if server == "" {
continue
}
transport, loaded := transportManager.Transport(server)
if !loaded || transport.Type() != C.DNSTypeFakeIP {
continue
}
return E.New("dns rule[", i, "]: evaluate action cannot use fakeip server: ", server)
}
return nil
}
func validateLegacyDNSModeDisabledRuleTree(rule option.DNSRule) (bool, error) {
switch rule.Type {
case "", C.RuleTypeDefault:
@@ -1146,3 +1171,14 @@ func dnsRuleActionType(rule option.DNSRule) string {
return ""
}
}
func dnsRuleActionServer(rule option.DNSRule) string {
switch rule.Type {
case "", C.RuleTypeDefault:
return rule.DefaultOptions.RouteOptions.Server
case C.RuleTypeLogical:
return rule.LogicalOptions.RouteOptions.Server
default:
return ""
}
}

View File

@@ -2022,84 +2022,39 @@ func TestLookupLegacyDNSModeDisabledSkipsFakeIPRule(t *testing.T) {
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses)
}
func TestLookupLegacyDNSModeDisabledEvaluateSkipFakeIPPreservesResponse(t *testing.T) {
func TestExchangeLegacyDNSModeDisabledAllowsRouteFakeIPRule(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"},
},
fakeTransport := &fakeDNSTransport{tag: "fake", transportType: C.DNSTypeFakeIP}
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: "fake"},
},
},
{
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: "fake"},
},
},
},
{
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: "selected"},
},
},
},
}, &fakeDNSTransportManager{
defaultTransport: defaultTransport,
}}, &fakeDNSTransportManager{
defaultTransport: &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP},
transports: map[string]adapter.DNSTransport{
"default": defaultTransport,
"upstream": &fakeDNSTransport{tag: "upstream", transportType: C.DNSTypeUDP},
"fake": &fakeDNSTransport{tag: "fake", transportType: C.DNSTypeFakeIP},
"selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP},
"default": &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP},
"fake": fakeTransport,
},
}, &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], nil, 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], nil, 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], nil, 60), nil
default:
return nil, E.New("unexpected transport")
}
require.Same(t, fakeTransport, transport)
return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("198.18.0.1")}, 60), nil
},
})
router.currentRules.Load().legacyDNSMode = false
addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{})
response, err := router.Exchange(context.Background(), &mDNS.Msg{
Question: []mDNS.Question{fixedQuestion("example.com", mDNS.TypeA)},
}, adapter.DNSQueryOptions{})
require.NoError(t, err)
require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses)
require.Equal(t, []netip.Addr{netip.MustParseAddr("198.18.0.1")}, MessageToAddresses(response))
}
func TestInitializeRejectsDNSRuleStrategyWhenLegacyDNSModeIsDisabledByEvaluate(t *testing.T) {
@@ -2133,6 +2088,70 @@ func TestInitializeRejectsDNSRuleStrategyWhenLegacyDNSModeIsDisabledByEvaluate(t
require.ErrorContains(t, err, "deprecated")
}
func TestInitializeRejectsEvaluateFakeIPServerInDefaultRule(t *testing.T) {
t.Parallel()
router := &Router{
ctx: context.Background(),
logger: log.NewNOPFactory().NewLogger("dns"),
transport: &fakeDNSTransportManager{transports: map[string]adapter.DNSTransport{"fake": &fakeDNSTransport{tag: "fake", transportType: C.DNSTypeFakeIP}}},
client: &fakeDNSClient{},
rawRules: make([]option.DNSRule, 0, 1),
defaultDomainStrategy: C.DomainStrategyAsIS,
}
router.currentRules.Store(newRulesSnapshot(make([]adapter.DNSRule, 0, 1), false))
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: "fake"},
},
},
}})
require.ErrorContains(t, err, "evaluate action cannot use fakeip server")
require.ErrorContains(t, err, "fake")
}
func TestInitializeRejectsEvaluateFakeIPServerInLogicalRule(t *testing.T) {
t.Parallel()
router := &Router{
ctx: context.Background(),
logger: log.NewNOPFactory().NewLogger("dns"),
transport: &fakeDNSTransportManager{transports: map[string]adapter.DNSTransport{"fake": &fakeDNSTransport{tag: "fake", transportType: C.DNSTypeFakeIP}}},
client: &fakeDNSClient{},
rawRules: make([]option.DNSRule, 0, 1),
defaultDomainStrategy: C.DomainStrategyAsIS,
}
router.currentRules.Store(newRulesSnapshot(make([]adapter.DNSRule, 0, 1), false))
err := router.Initialize([]option.DNSRule{{
Type: C.RuleTypeLogical,
LogicalOptions: option.LogicalDNSRule{
RawLogicalDNSRule: option.RawLogicalDNSRule{
Mode: C.LogicalTypeOr,
Rules: []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: "fake"},
},
},
}})
require.ErrorContains(t, err, "evaluate action cannot use fakeip server")
require.ErrorContains(t, err, "fake")
}
func TestInitializeRejectsDNSRuleStrategyWhenLegacyDNSModeIsDisabledByMatchResponse(t *testing.T) {
t.Parallel()