From aaa11fbdf1c18a2e79c336a481c8b54a22b238f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 1 Apr 2026 16:39:12 +0800 Subject: [PATCH] test: remove low-value DNS WHAT tests --- dns/router_test.go | 697 -------------------------- option/dns_record_test.go | 12 - option/dns_test.go | 37 -- option/rule_nested_test.go | 203 -------- route/rule/rule_nested_action_test.go | 69 --- 5 files changed, 1018 deletions(-) diff --git a/dns/router_test.go b/dns/router_test.go index 5f7814430..55d7311df 100644 --- a/dns/router_test.go +++ b/dns/router_test.go @@ -78,11 +78,6 @@ type fakeDNSClient struct { lookup func(transport adapter.DNSTransport, domain string, options adapter.DNSQueryOptions) ([]netip.Addr, *mDNS.Msg, error) } -type recordingExchangeDNSClient struct { - beforeExchange func(ctx context.Context, transport adapter.DNSTransport, message *mDNS.Msg, options adapter.DNSQueryOptions) - exchange func(transport adapter.DNSTransport, message *mDNS.Msg, options adapter.DNSQueryOptions) (*mDNS.Msg, error) -} - type fakeDeprecatedManager struct { features []deprecated.Note } @@ -261,26 +256,8 @@ func (c *fakeDNSClient) Lookup(_ context.Context, transport adapter.DNSTransport return MessageToAddresses(response), nil } -func (c *recordingExchangeDNSClient) Start() {} - -func (c *recordingExchangeDNSClient) Exchange(ctx context.Context, transport adapter.DNSTransport, message *mDNS.Msg, options adapter.DNSQueryOptions, _ func(*mDNS.Msg) bool) (*mDNS.Msg, error) { - if c.beforeExchange != nil { - c.beforeExchange(ctx, transport, message, options) - } - if c.exchange == nil { - return nil, E.New("unused client exchange") - } - return c.exchange(transport, message, options) -} - -func (c *recordingExchangeDNSClient) Lookup(context.Context, adapter.DNSTransport, string, adapter.DNSQueryOptions, func(*mDNS.Msg) bool) ([]netip.Addr, error) { - return nil, E.New("unused client lookup") -} - func (c *fakeDNSClient) ClearCache() {} -func (c *recordingExchangeDNSClient) ClearCache() {} - func newTestRouter(t *testing.T, rules []option.DNSRule, transportManager *fakeDNSTransportManager, client *fakeDNSClient) *Router { router := newTestRouterWithContext(t, context.Background(), rules, transportManager, client) t.Cleanup(func() { @@ -289,28 +266,6 @@ func newTestRouter(t *testing.T, rules []option.DNSRule, transportManager *fakeD return router } -func newTestRouterWithDNSClient(t *testing.T, rules []option.DNSRule, transportManager *fakeDNSTransportManager, client adapter.DNSClient) *Router { - router := &Router{ - ctx: context.Background(), - logger: log.NewNOPFactory().NewLogger("dns"), - transport: transportManager, - client: client, - rawRules: make([]option.DNSRule, 0, len(rules)), - defaultDomainStrategy: C.DomainStrategyAsIS, - } - router.currentRules.Store(newRulesSnapshot(make([]adapter.DNSRule, 0, len(rules)), false)) - if rules != nil { - err := router.Initialize(rules) - require.NoError(t, err) - err = router.Start(adapter.StartStateStart) - require.NoError(t, err) - } - t.Cleanup(func() { - router.Close() - }) - return router -} - func newTestRouterWithContext(t *testing.T, ctx context.Context, rules []option.DNSRule, transportManager *fakeDNSTransportManager, client *fakeDNSClient) *Router { return newTestRouterWithContextAndLogger(t, ctx, rules, transportManager, client, log.NewNOPFactory().NewLogger("dns")) } @@ -370,131 +325,6 @@ func mustRecord(t *testing.T, record string) option.DNSRecordOptions { return value } -func fixedHTTPSHintResponse(question mDNS.Question, addresses ...netip.Addr) *mDNS.Msg { - response := &mDNS.Msg{ - MsgHdr: mDNS.MsgHdr{ - Response: true, - Rcode: mDNS.RcodeSuccess, - }, - Question: []mDNS.Question{question}, - Answer: []mDNS.RR{ - &mDNS.HTTPS{ - SVCB: mDNS.SVCB{ - Hdr: mDNS.RR_Header{ - Name: question.Name, - Rrtype: mDNS.TypeHTTPS, - Class: mDNS.ClassINET, - Ttl: 60, - }, - Priority: 1, - Target: ".", - }, - }, - }, - } - https := response.Answer[0].(*mDNS.HTTPS) - var ( - hints4 []net.IP - hints6 []net.IP - ) - for _, address := range addresses { - if address.Is4() { - hints4 = append(hints4, net.IP(append([]byte(nil), address.AsSlice()...))) - } else { - hints6 = append(hints6, net.IP(append([]byte(nil), address.AsSlice()...))) - } - } - if len(hints4) > 0 { - https.SVCB.Value = append(https.SVCB.Value, &mDNS.SVCBIPv4Hint{Hint: hints4}) - } - if len(hints6) > 0 { - https.SVCB.Value = append(https.SVCB.Value, &mDNS.SVCBIPv6Hint{Hint: hints6}) - } - return response -} - -func fixedHTTPSHintResponseWithRawHints(question mDNS.Question, ipv4Hints []net.IP, ipv6Hints []net.IP) *mDNS.Msg { - response := fixedHTTPSHintResponse(question) - https := response.Answer[0].(*mDNS.HTTPS) - if len(ipv4Hints) > 0 { - hints := make([]net.IP, 0, len(ipv4Hints)) - for _, ip := range ipv4Hints { - hints = append(hints, net.IP(append([]byte(nil), ip...))) - } - https.SVCB.Value = append(https.SVCB.Value, &mDNS.SVCBIPv4Hint{Hint: hints}) - } - if len(ipv6Hints) > 0 { - hints := make([]net.IP, 0, len(ipv6Hints)) - for _, ip := range ipv6Hints { - hints = append(hints, net.IP(append([]byte(nil), ip...))) - } - https.SVCB.Value = append(https.SVCB.Value, &mDNS.SVCBIPv6Hint{Hint: hints}) - } - return response -} - -func TestValidateLegacyDNSModeDisabledRules_RequireMatchResponseForDirectIPCIDR(t *testing.T) { - t.Parallel() - - err := validateLegacyDNSModeDisabledRules([]option.DNSRule{{ - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultDNSRule{ - RawDefaultDNSRule: option.RawDefaultDNSRule{ - IPCIDR: badoption.Listable[string]{"1.1.1.0/24"}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{ - Server: "default", - }, - }, - }, - }}) - require.ErrorContains(t, err, "ip_cidr and ip_is_private require match_response") -} - -func TestValidateLegacyDNSModeDisabledRules_AllowMatchResponseWithoutEvaluate(t *testing.T) { - t.Parallel() - - err := validateLegacyDNSModeDisabledRules([]option.DNSRule{{ - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultDNSRule{ - RawDefaultDNSRule: option.RawDefaultDNSRule{ - MatchResponse: true, - IPCIDR: badoption.Listable[string]{"1.1.1.0/24"}, - }, - }, - }}) - require.NoError(t, err) -} - -func TestInitializeRejectsInvalidDNSRuleParseError(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), - 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{ - DomainRegex: badoption.Listable[string]{"("}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{Server: "default"}, - }, - }, - }}) - require.ErrorContains(t, err, "domain_regex") -} - func TestInitializeRejectsDirectLegacyRuleWhenRuleSetForcesNew(t *testing.T) { t.Parallel() @@ -1561,17 +1391,6 @@ func TestLookupLegacyDNSModeRuleSetAcceptEmptyDoesNotTreatMismatchAsEmpty(t *tes require.Equal(t, []string{"private", "default"}, currentLookupTags()) } -func TestDNSResponseAddressesMatchesMessageToAddressesForHTTPSHints(t *testing.T) { - t.Parallel() - - response := fixedHTTPSHintResponse(fixedQuestion("example.com", mDNS.TypeHTTPS), - netip.MustParseAddr("1.1.1.1"), - netip.MustParseAddr("2001:db8::1"), - ) - - require.Equal(t, MessageToAddresses(response), adapter.DNSResponseAddresses(response)) -} - func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseRoute(t *testing.T) { t.Parallel() @@ -1831,183 +1650,6 @@ func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseExtraRoute(t *testing require.Equal(t, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, MessageToAddresses(response)) } -func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseRouteIgnoresTTL(t *testing.T) { - t.Parallel() - - transportManager := &fakeDNSTransportManager{ - defaultTransport: &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}, - transports: map[string]adapter.DNSTransport{ - "upstream": &fakeDNSTransport{tag: "upstream", transportType: C.DNSTypeUDP}, - "selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP}, - "default": &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}, - }, - } - client := &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - switch transport.Tag() { - case "upstream": - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("1.1.1.1")}, 30), nil - case "selected": - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("8.8.8.8")}, 60), nil - default: - return nil, E.New("unexpected transport") - } - }, - } - 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: "upstream"}, - }, - }, - }, - { - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultDNSRule{ - RawDefaultDNSRule: option.RawDefaultDNSRule{ - MatchResponse: true, - ResponseAnswer: badoption.Listable[option.DNSRecordOptions]{mustRecord(t, "example.com. 60 IN A 1.1.1.1")}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{Server: "selected"}, - }, - }, - }, - } - router := newTestRouter(t, rules, transportManager, client) - - 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("8.8.8.8")}, MessageToAddresses(response)) -} - -func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseRouteWithHTTPSHints(t *testing.T) { - t.Parallel() - - transportManager := &fakeDNSTransportManager{ - defaultTransport: &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}, - transports: map[string]adapter.DNSTransport{ - "upstream": &fakeDNSTransport{tag: "upstream", transportType: C.DNSTypeUDP}, - "selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP}, - "default": &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}, - }, - } - client := &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - switch transport.Tag() { - case "upstream": - return fixedHTTPSHintResponse(message.Question[0], netip.MustParseAddr("1.1.1.1")), nil - case "selected": - return fixedHTTPSHintResponse(message.Question[0], netip.MustParseAddr("8.8.8.8")), nil - default: - return nil, E.New("unexpected transport") - } - }, - } - 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: "upstream"}, - }, - }, - }, - { - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultDNSRule{ - RawDefaultDNSRule: option.RawDefaultDNSRule{ - MatchResponse: true, - IPCIDR: badoption.Listable[string]{"1.1.1.0/24"}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{Server: "selected"}, - }, - }, - }, - } - router := newTestRouter(t, rules, transportManager, client) - - response, err := router.Exchange(context.Background(), &mDNS.Msg{ - Question: []mDNS.Question{fixedQuestion("example.com", mDNS.TypeHTTPS)}, - }, adapter.DNSQueryOptions{}) - require.NoError(t, err) - require.Equal(t, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, MessageToAddresses(response)) -} - -func TestExchangeLegacyDNSModeDisabledEvaluateMatchResponseRouteWithMappedHTTPSIPv4Hints(t *testing.T) { - t.Parallel() - - transportManager := &fakeDNSTransportManager{ - defaultTransport: &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}, - transports: map[string]adapter.DNSTransport{ - "upstream": &fakeDNSTransport{tag: "upstream", transportType: C.DNSTypeUDP}, - "selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP}, - "default": &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP}, - }, - } - client := &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - switch transport.Tag() { - case "upstream": - return fixedHTTPSHintResponseWithRawHints(message.Question[0], []net.IP{net.ParseIP("1.1.1.1")}, nil), nil - case "selected": - return fixedHTTPSHintResponse(message.Question[0], netip.MustParseAddr("8.8.8.8")), nil - default: - return nil, E.New("unexpected transport") - } - }, - } - 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: "upstream"}, - }, - }, - }, - { - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultDNSRule{ - RawDefaultDNSRule: option.RawDefaultDNSRule{ - MatchResponse: true, - IPCIDR: badoption.Listable[string]{"1.1.1.0/24"}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{Server: "selected"}, - }, - }, - }, - } - router := newTestRouter(t, rules, transportManager, client) - - response, err := router.Exchange(context.Background(), &mDNS.Msg{ - Question: []mDNS.Question{fixedQuestion("example.com", mDNS.TypeHTTPS)}, - }, adapter.DNSQueryOptions{}) - require.NoError(t, err) - require.Equal(t, []netip.Addr{netip.MustParseAddr("8.8.8.8")}, MessageToAddresses(response)) -} - func TestExchangeLegacyDNSModeDisabledEvaluateDoesNotLeakAddressesToNextQuery(t *testing.T) { t.Parallel() @@ -2472,164 +2114,6 @@ func TestLookupLegacyDNSModeDisabledEvaluateSkipFakeIPPreservesResponse(t *testi require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses) } -func TestLookupLegacyDNSModeDisabledUsesQueryTypeRule(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{ - QueryType: badoption.Listable[option.DNSQueryType]{option.DNSQueryType(mDNS.TypeA)}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{Server: "only-a"}, - }, - }, - }}, &fakeDNSTransportManager{ - defaultTransport: defaultTransport, - transports: map[string]adapter.DNSTransport{ - "default": defaultTransport, - "only-a": &fakeDNSTransport{tag: "only-a", transportType: C.DNSTypeUDP}, - }, - }, &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - switch transport.Tag() { - case "default": - if message.Question[0].Qtype == mDNS.TypeA { - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("3.3.3.3")}, 60), nil - } - return FixedResponse(0, message.Question[0], nil, 60), nil - case "only-a": - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("9.9.9.9")}, 60), nil - default: - return nil, E.New("unexpected transport") - } - }, - }) - require.False(t, router.currentRules.Load().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 TestLookupLegacyDNSModeDisabledUsesRuleSetQueryTypeRule(t *testing.T) { - t.Parallel() - - ctx := context.Background() - ruleSet, err := rulepkg.NewRuleSet(ctx, log.NewNOPFactory().NewLogger("router"), option.RuleSet{ - Type: C.RuleSetTypeInline, - Tag: "query-set", - InlineOptions: option.PlainRuleSet{ - Rules: []option.HeadlessRule{{ - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultHeadlessRule{ - QueryType: badoption.Listable[option.DNSQueryType]{option.DNSQueryType(mDNS.TypeA)}, - }, - }}, - }, - }) - require.NoError(t, err) - ctx = service.ContextWith[adapter.Router](ctx, &fakeRouter{ - ruleSets: map[string]adapter.RuleSet{ - "query-set": ruleSet, - }, - }) - - defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP} - router := newTestRouterWithContext(t, ctx, []option.DNSRule{{ - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultDNSRule{ - RawDefaultDNSRule: option.RawDefaultDNSRule{ - RuleSet: badoption.Listable[string]{"query-set"}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{Server: "only-a"}, - }, - }, - }}, &fakeDNSTransportManager{ - defaultTransport: defaultTransport, - transports: map[string]adapter.DNSTransport{ - "default": defaultTransport, - "only-a": &fakeDNSTransport{tag: "only-a", transportType: C.DNSTypeUDP}, - }, - }, &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - switch transport.Tag() { - case "default": - if message.Question[0].Qtype == mDNS.TypeA { - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("3.3.3.3")}, 60), nil - } - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::4")}, 60), nil - case "only-a": - if message.Question[0].Qtype == mDNS.TypeA { - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("9.9.9.9")}, 60), nil - } - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::9")}, 60), nil - default: - return nil, E.New("unexpected transport") - } - }, - }) - require.False(t, router.currentRules.Load().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"), - netip.MustParseAddr("2001:db8::4"), - }, addresses) -} - -func TestLookupLegacyDNSModeDisabledUsesIPVersionRule(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{ - IPVersion: 6, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRoute, - RouteOptions: option.DNSRouteActionOptions{Server: "only-v6"}, - }, - }, - }}, &fakeDNSTransportManager{ - defaultTransport: defaultTransport, - transports: map[string]adapter.DNSTransport{ - "default": defaultTransport, - "only-v6": &fakeDNSTransport{tag: "only-v6", transportType: C.DNSTypeUDP}, - }, - }, &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - switch transport.Tag() { - case "default": - if message.Question[0].Qtype == mDNS.TypeA { - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("3.3.3.3")}, 60), nil - } - return FixedResponse(0, message.Question[0], nil, 60), nil - case "only-v6": - if message.Question[0].Qtype == mDNS.TypeAAAA { - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::9")}, 60), nil - } - return FixedResponse(0, message.Question[0], nil, 60), nil - default: - return nil, E.New("unexpected transport") - } - }, - }) - require.False(t, router.currentRules.Load().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 TestInitializeRejectsDNSRuleStrategyWhenLegacyDNSModeIsDisabledByEvaluate(t *testing.T) { t.Parallel() @@ -2689,108 +2173,6 @@ func TestInitializeRejectsDNSRuleStrategyWhenLegacyDNSModeIsDisabledByMatchRespo require.ErrorContains(t, err, "legacyDNSMode") } -func TestExchangeLegacyDNSModeDisabledRouteOptionsApplyQueryOptions(t *testing.T) { - t.Parallel() - - defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP} - rewriteTTL := uint32(30) - var capturedOptions adapter.DNSQueryOptions - router := newTestRouterWithDNSClient(t, []option.DNSRule{ - { - Type: C.RuleTypeDefault, - DefaultOptions: option.DefaultDNSRule{ - RawDefaultDNSRule: option.RawDefaultDNSRule{ - QueryType: badoption.Listable[option.DNSQueryType]{option.DNSQueryType(mDNS.TypeA)}, - }, - DNSRuleAction: option.DNSRuleAction{ - Action: C.RuleActionTypeRouteOptions, - RouteOptionsOptions: option.DNSRouteOptionsActionOptions{ - DisableCache: true, - RewriteTTL: &rewriteTTL, - }, - }, - }, - }, - { - 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"}, - }, - }, - }, - }, &fakeDNSTransportManager{ - defaultTransport: defaultTransport, - transports: map[string]adapter.DNSTransport{ - "default": defaultTransport, - "selected": &fakeDNSTransport{tag: "selected", transportType: C.DNSTypeUDP}, - }, - }, &recordingExchangeDNSClient{ - beforeExchange: func(ctx context.Context, transport adapter.DNSTransport, message *mDNS.Msg, options adapter.DNSQueryOptions) { - require.Equal(t, "selected", transport.Tag()) - require.Equal(t, []mDNS.Question{fixedQuestion("example.com", mDNS.TypeA)}, message.Question) - capturedOptions = options - }, - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg, options adapter.DNSQueryOptions) (*mDNS.Msg, error) { - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2.2.2.2")}, 60), nil - }, - }) - require.False(t, router.currentRules.Load().legacyDNSMode) - - 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")}, MessageToAddresses(response)) - require.True(t, capturedOptions.DisableCache) - require.NotNil(t, capturedOptions.RewriteTTL) - require.Equal(t, rewriteTTL, *capturedOptions.RewriteTTL) -} - -func TestLookupLegacyDNSModeUsesRouteStrategy(t *testing.T) { - t.Parallel() - - defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP} - 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), - }, - }, - }, - }}, &fakeDNSTransportManager{ - defaultTransport: defaultTransport, - transports: map[string]adapter.DNSTransport{ - "default": defaultTransport, - "selected": selectedTransport, - }, - }, &fakeDNSClient{ - 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.currentRules.Load().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 TestLookupLegacyDNSModeDisabledReturnsRejectedErrorForRejectAction(t *testing.T) { t.Parallel() @@ -2931,85 +2313,6 @@ func TestLookupLegacyDNSModeDisabledFiltersPerQueryTypeAddressesBeforeMerging(t }, addresses) } -func TestLookupLegacyDNSModeDisabledUsesInputStrategy(t *testing.T) { - t.Parallel() - - defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP} - var queryTypeAccess sync.Mutex - var queryTypes []uint16 - recordQueryType := func(queryType uint16) { - queryTypeAccess.Lock() - queryTypes = append(queryTypes, queryType) - queryTypeAccess.Unlock() - } - currentQueryTypes := func() []uint16 { - queryTypeAccess.Lock() - defer queryTypeAccess.Unlock() - return append([]uint16(nil), queryTypes...) - } - router := newTestRouter(t, nil, &fakeDNSTransportManager{ - defaultTransport: defaultTransport, - transports: map[string]adapter.DNSTransport{ - "default": defaultTransport, - }, - }, &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - recordQueryType(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 - } - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::2")}, 60), nil - }, - }) - router.currentRules.Load().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}, currentQueryTypes()) - require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses) -} - -func TestLookupLegacyDNSModeDisabledUsesDefaultStrategy(t *testing.T) { - t.Parallel() - - defaultTransport := &fakeDNSTransport{tag: "default", transportType: C.DNSTypeUDP} - var queryTypeAccess sync.Mutex - var queryTypes []uint16 - recordQueryType := func(queryType uint16) { - queryTypeAccess.Lock() - queryTypes = append(queryTypes, queryType) - queryTypeAccess.Unlock() - } - currentQueryTypes := func() []uint16 { - queryTypeAccess.Lock() - defer queryTypeAccess.Unlock() - return append([]uint16(nil), queryTypes...) - } - router := newTestRouter(t, nil, &fakeDNSTransportManager{ - defaultTransport: defaultTransport, - transports: map[string]adapter.DNSTransport{ - "default": defaultTransport, - }, - }, &fakeDNSClient{ - exchange: func(transport adapter.DNSTransport, message *mDNS.Msg) (*mDNS.Msg, error) { - recordQueryType(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 - } - return FixedResponse(0, message.Question[0], []netip.Addr{netip.MustParseAddr("2001:db8::2")}, 60), nil - }, - }) - router.defaultDomainStrategy = C.DomainStrategyIPv4Only - router.currentRules.Load().legacyDNSMode = false - - addresses, err := router.Lookup(context.Background(), "example.com", adapter.DNSQueryOptions{}) - require.NoError(t, err) - require.Equal(t, []uint16{mDNS.TypeA}, currentQueryTypes()) - require.Equal(t, []netip.Addr{netip.MustParseAddr("2.2.2.2")}, addresses) -} - func TestExchangeLegacyDNSModeDisabledLogicalMatchResponseIPCIDRFallsThrough(t *testing.T) { t.Parallel() diff --git a/option/dns_record_test.go b/option/dns_record_test.go index cb26f9b01..759ef5fc5 100644 --- a/option/dns_record_test.go +++ b/option/dns_record_test.go @@ -14,18 +14,6 @@ func mustRecordOptions(t *testing.T, record string) DNSRecordOptions { return value } -func TestDNSRecordOptionsUnmarshalJSONAcceptsFullyQualifiedNames(t *testing.T) { - t.Parallel() - - for _, record := range []string{ - "example.com. A 1.1.1.1", - "www.example.com. IN CNAME example.com.", - } { - value := mustRecordOptions(t, record) - require.NotNil(t, value.RR) - } -} - func TestDNSRecordOptionsUnmarshalJSONRejectsRelativeNames(t *testing.T) { t.Parallel() diff --git a/option/dns_test.go b/option/dns_test.go index 1f26dc77d..4e7bf9a92 100644 --- a/option/dns_test.go +++ b/option/dns_test.go @@ -52,40 +52,3 @@ func TestDNSServerOptionsRejectsLegacyFormats(t *testing.T) { require.EqualError(t, err, legacyDNSServerRemovedMessage) } } - -func TestDNSOptionsAcceptsTypedServers(t *testing.T) { - t.Parallel() - - ctx := service.ContextWith[DNSTransportOptionsRegistry](context.Background(), stubDNSTransportOptionsRegistry{}) - var options DNSOptions - err := json.UnmarshalContext(ctx, []byte(`{ - "servers": [ - {"type": "udp", "tag": "default", "server": "1.1.1.1"}, - {"type": "fakeip", "tag": "fake", "inet4_range": "198.18.0.0/15"} - ] - }`), &options) - require.NoError(t, err) - require.Len(t, options.Servers, 2) - require.Equal(t, C.DNSTypeUDP, options.Servers[0].Type) - require.Equal(t, "1.1.1.1", options.Servers[0].Options.(*RemoteDNSServerOptions).Server) - require.Equal(t, C.DNSTypeFakeIP, options.Servers[1].Type) -} - -func TestDNSRuleActionEvaluateRoundTrip(t *testing.T) { - t.Parallel() - - action := DNSRuleAction{ - Action: C.RuleActionTypeEvaluate, - RouteOptions: DNSRouteActionOptions{ - Server: "default", - }, - } - - content, err := json.Marshal(action) - require.NoError(t, err) - - var decoded DNSRuleAction - err = json.UnmarshalContext(context.Background(), content, &decoded) - require.NoError(t, err) - require.Equal(t, action, decoded) -} diff --git a/option/rule_nested_test.go b/option/rule_nested_test.go index d5035891b..3b2ef2e5f 100644 --- a/option/rule_nested_test.go +++ b/option/rule_nested_test.go @@ -4,7 +4,6 @@ import ( "context" "testing" - C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing/common/json" "github.com/stretchr/testify/require" @@ -24,107 +23,6 @@ func TestRuleRejectsNestedDefaultRuleAction(t *testing.T) { require.ErrorContains(t, err, RouteRuleActionNestedUnsupportedMessage) } -func TestRuleRejectsNestedLogicalRuleAction(t *testing.T) { - t.Parallel() - - var rule Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - { - "type": "logical", - "mode": "or", - "action": "route", - "outbound": "direct", - "rules": [{"domain": "example.com"}] - } - ] - }`), &rule) - require.ErrorContains(t, err, RouteRuleActionNestedUnsupportedMessage) -} - -func TestRuleRejectsNestedDefaultRuleZeroValueOutbound(t *testing.T) { - t.Parallel() - - var rule Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - {"domain": "example.com", "outbound": ""} - ] - }`), &rule) - require.ErrorContains(t, err, RouteRuleActionNestedUnsupportedMessage) -} - -func TestRuleRejectsNestedDefaultRuleZeroValueRouteOption(t *testing.T) { - t.Parallel() - - var rule Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - {"domain": "example.com", "udp_connect": false} - ] - }`), &rule) - require.ErrorContains(t, err, RouteRuleActionNestedUnsupportedMessage) -} - -func TestRuleRejectsNestedLogicalRuleZeroValueAction(t *testing.T) { - t.Parallel() - - var rule Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - { - "type": "logical", - "mode": "or", - "action": "", - "rules": [{"domain": "example.com"}] - } - ] - }`), &rule) - require.ErrorContains(t, err, RouteRuleActionNestedUnsupportedMessage) -} - -func TestRuleRejectsNestedLogicalRuleZeroValueRouteOption(t *testing.T) { - t.Parallel() - - var rule Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - { - "type": "logical", - "mode": "or", - "override_port": 0, - "rules": [{"domain": "example.com"}] - } - ] - }`), &rule) - require.ErrorContains(t, err, RouteRuleActionNestedUnsupportedMessage) -} - -func TestRuleAllowsTopLevelLogicalAction(t *testing.T) { - t.Parallel() - - var rule Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "outbound": "direct", - "rules": [{"domain": "example.com"}] - }`), &rule) - require.NoError(t, err) - require.Equal(t, C.RuleActionTypeRoute, rule.LogicalOptions.Action) - require.Equal(t, "direct", rule.LogicalOptions.RouteOptions.Outbound) -} - func TestRuleLeavesUnknownNestedKeysToNormalValidation(t *testing.T) { t.Parallel() @@ -154,107 +52,6 @@ func TestDNSRuleRejectsNestedDefaultRuleAction(t *testing.T) { require.ErrorContains(t, err, DNSRuleActionNestedUnsupportedMessage) } -func TestDNSRuleRejectsNestedLogicalRuleAction(t *testing.T) { - t.Parallel() - - var rule DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - { - "type": "logical", - "mode": "or", - "action": "route", - "server": "default", - "rules": [{"domain": "example.com"}] - } - ] - }`), &rule) - require.ErrorContains(t, err, DNSRuleActionNestedUnsupportedMessage) -} - -func TestDNSRuleRejectsNestedDefaultRuleZeroValueServer(t *testing.T) { - t.Parallel() - - var rule DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - {"domain": "example.com", "server": ""} - ] - }`), &rule) - require.ErrorContains(t, err, DNSRuleActionNestedUnsupportedMessage) -} - -func TestDNSRuleRejectsNestedDefaultRuleZeroValueRouteOption(t *testing.T) { - t.Parallel() - - var rule DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - {"domain": "example.com", "disable_cache": false} - ] - }`), &rule) - require.ErrorContains(t, err, DNSRuleActionNestedUnsupportedMessage) -} - -func TestDNSRuleRejectsNestedLogicalRuleZeroValueAction(t *testing.T) { - t.Parallel() - - var rule DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - { - "type": "logical", - "mode": "or", - "action": "", - "rules": [{"domain": "example.com"}] - } - ] - }`), &rule) - require.ErrorContains(t, err, DNSRuleActionNestedUnsupportedMessage) -} - -func TestDNSRuleRejectsNestedLogicalRuleZeroValueRouteOption(t *testing.T) { - t.Parallel() - - var rule DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - { - "type": "logical", - "mode": "or", - "disable_cache": false, - "rules": [{"domain": "example.com"}] - } - ] - }`), &rule) - require.ErrorContains(t, err, DNSRuleActionNestedUnsupportedMessage) -} - -func TestDNSRuleAllowsTopLevelLogicalAction(t *testing.T) { - t.Parallel() - - var rule DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "server": "default", - "rules": [{"domain": "example.com"}] - }`), &rule) - require.NoError(t, err) - require.Equal(t, C.RuleActionTypeRoute, rule.LogicalOptions.Action) - require.Equal(t, "default", rule.LogicalOptions.RouteOptions.Server) -} - func TestDNSRuleLeavesUnknownNestedKeysToNormalValidation(t *testing.T) { t.Parallel() diff --git a/route/rule/rule_nested_action_test.go b/route/rule/rule_nested_action_test.go index 6923b3510..f895b8928 100644 --- a/route/rule/rule_nested_action_test.go +++ b/route/rule/rule_nested_action_test.go @@ -7,45 +7,10 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing/common/json" "github.com/stretchr/testify/require" ) -func TestNewRulePreservesImplicitTopLevelDefaultAction(t *testing.T) { - t.Parallel() - - var options option.Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "domain": "example.com" - }`), &options) - require.NoError(t, err) - - rule, err := NewRule(context.Background(), log.NewNOPFactory().NewLogger("router"), options, false) - require.NoError(t, err) - require.NotNil(t, rule.Action()) - require.Equal(t, C.RuleActionTypeRoute, rule.Action().Type()) -} - -func TestNewRuleAllowsNestedRuleWithoutAction(t *testing.T) { - t.Parallel() - - var options option.Rule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - {"domain": "example.com"} - ] - }`), &options) - require.NoError(t, err) - - rule, err := NewRule(context.Background(), log.NewNOPFactory().NewLogger("router"), options, false) - require.NoError(t, err) - require.NotNil(t, rule.Action()) - require.Equal(t, C.RuleActionTypeRoute, rule.Action().Type()) -} - func TestNewRuleRejectsNestedRuleAction(t *testing.T) { t.Parallel() @@ -71,40 +36,6 @@ func TestNewRuleRejectsNestedRuleAction(t *testing.T) { require.ErrorContains(t, err, option.RouteRuleActionNestedUnsupportedMessage) } -func TestNewDNSRulePreservesImplicitTopLevelDefaultAction(t *testing.T) { - t.Parallel() - - var options option.DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "domain": "example.com" - }`), &options) - require.NoError(t, err) - - rule, err := NewDNSRule(context.Background(), log.NewNOPFactory().NewLogger("dns"), options, false, false) - require.NoError(t, err) - require.NotNil(t, rule.Action()) - require.Equal(t, C.RuleActionTypeRoute, rule.Action().Type()) -} - -func TestNewDNSRuleAllowsNestedRuleWithoutAction(t *testing.T) { - t.Parallel() - - var options option.DNSRule - err := json.UnmarshalContext(context.Background(), []byte(`{ - "type": "logical", - "mode": "and", - "rules": [ - {"domain": "example.com"} - ] - }`), &options) - require.NoError(t, err) - - rule, err := NewDNSRule(context.Background(), log.NewNOPFactory().NewLogger("dns"), options, false, false) - require.NoError(t, err) - require.NotNil(t, rule.Action()) - require.Equal(t, C.RuleActionTypeRoute, rule.Action().Type()) -} - func TestNewDNSRuleRejectsNestedRuleAction(t *testing.T) { t.Parallel()