diff --git a/plugin/file/lookup.go b/plugin/file/lookup.go index 64ff45c5a..6bee545c7 100644 --- a/plugin/file/lookup.go +++ b/plugin/file/lookup.go @@ -226,6 +226,11 @@ func (z *Zone) Lookup(ctx context.Context, state request.Request, qname string) return nil, ret, nil, NoData } + // Additional section processing for MX, SRV, SVCB, HTTPS. Check response + // and see if any of the names are in bailiwick - if so add IP addresses + // to the additional section. This mirrors the non-wildcard path above. + additional := z.additionalProcessing(rrs, do) + auth := ap.ns(do) if do { // An NSEC is needed to say no longer name exists under this wildcard. @@ -238,7 +243,7 @@ func (z *Zone) Lookup(ctx context.Context, state request.Request, qname string) sigs = rrutil.SubTypeSignature(sigs, qtype) rrs = append(rrs, sigs...) } - return rrs, auth, nil, Success + return rrs, auth, additional, Success } rcode := NameError diff --git a/plugin/file/svcb_test.go b/plugin/file/svcb_test.go index 7041b5b88..f2845f529 100644 --- a/plugin/file/svcb_test.go +++ b/plugin/file/svcb_test.go @@ -53,12 +53,17 @@ var svcbTestCases = []test.Case{ }, }, { - // Wildcard SVCB expansion (no additional section — wildcards don't run additionalProcessing) + // Wildcard SVCB expansion — glue for the in-bailiwick target is added to + // the additional section, same as for non-wildcard answers (issue #6629). Qname: "_http._tcp.example.com.", Qtype: dns.TypeSVCB, Answer: []dns.RR{ test.SVCB("_http._tcp.example.com. 1800 IN SVCB 1 svc-target.example.com. port=\"443\""), }, Ns: svcbAuth, + Extra: []dns.RR{ + test.A("svc-target.example.com. 1800 IN A 192.0.2.10"), + test.AAAA("svc-target.example.com. 1800 IN AAAA 2001:db8::10"), + }, }, { // NoData: existing name, no SVCB record diff --git a/plugin/file/wildcard_test.go b/plugin/file/wildcard_test.go index fc6ad120c..b944576db 100644 --- a/plugin/file/wildcard_test.go +++ b/plugin/file/wildcard_test.go @@ -296,3 +296,61 @@ example.org. IN NS b.iana-servers.net. *.intern.example.org. IN A 127.0.1.52 foo.example.org. IN A 127.0.0.54 ` + +// Wildcard-synthesized answers must run additional-section processing for +// MX/SRV/SVCB/HTTPS targets, just like non-wildcard answers do. +// See https://github.com/coredns/coredns/issues/6629. +const dbWildcardAdditional = ` +$TTL 30M +$ORIGIN example.org. +@ IN SOA ns.example.org. admin.example.org. 2024010100 14400 3600 604800 14400 + IN NS ns.example.org. +ns IN A 192.0.2.1 +mail IN A 192.0.2.10 + IN AAAA 2001:db8::10 +*.wild IN MX 10 mail.example.org. +` + +const testWildcardAdditionalOrigin = "example.org." + +var wildcardAdditionalTestCases = []test.Case{ + { + // Wildcard-synthesized MX answer includes glue (A/AAAA) for the + // in-bailiwick target in the additional section. + Qname: "foo.wild.example.org.", Qtype: dns.TypeMX, + Answer: []dns.RR{ + test.MX("foo.wild.example.org. 1800 IN MX 10 mail.example.org."), + }, + Ns: []dns.RR{ + test.NS("example.org. 1800 IN NS ns.example.org."), + }, + Extra: []dns.RR{ + test.A("mail.example.org. 1800 IN A 192.0.2.10"), + test.AAAA("mail.example.org. 1800 IN AAAA 2001:db8::10"), + }, + }, +} + +func TestLookupWildcardAdditional(t *testing.T) { + zone, err := Parse(strings.NewReader(dbWildcardAdditional), testWildcardAdditionalOrigin, "stdin", 0) + if err != nil { + t.Fatalf("Expected no error when reading zone, got %q", err) + } + + fm := File{Next: test.ErrorHandler(), Zones: Zones{Z: map[string]*Zone{testWildcardAdditionalOrigin: zone}, Names: []string{testWildcardAdditionalOrigin}}} + ctx := context.TODO() + + for _, tc := range wildcardAdditionalTestCases { + m := tc.Msg() + + rec := dnstest.NewRecorder(&test.ResponseWriter{}) + if _, err := fm.ServeDNS(ctx, rec, m); err != nil { + t.Errorf("Expected no error for %q/%d, got %v", tc.Qname, tc.Qtype, err) + continue + } + + if err := test.SortAndCheck(rec.Msg, tc); err != nil { + t.Errorf("Test %q/%d: %v", tc.Qname, tc.Qtype, err) + } + } +}