|
|
|
|
@@ -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()
|
|
|
|
|
|
|
|
|
|
|