fix(auto/file): return REFUSED when no next plugin is available (#7381)

This commit is contained in:
Cameron Steel 2025-07-04 19:39:19 +10:00 committed by GitHub
parent 1449cb660e
commit 0aee758833
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 33 deletions

View File

@ -51,6 +51,10 @@ func (a Auto) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
// Now the real zone.
zone = plugin.Zones(a.Zones.Names()).Matches(qname)
if zone == "" {
// If no next plugin is configured, it's more correct to return REFUSED as auto acts as an authoritative server
if a.Next == nil {
return dns.RcodeRefused, nil
}
return plugin.NextOrFailure(a.Name(), a.Next, ctx, w, r)
}

View File

@ -104,39 +104,44 @@ func TestAutoServeDNSZoneMatching(t *testing.T) {
t.Parallel()
tests := []struct {
name string
origins []string
names []string
qname string
hasZone bool
name string
origins []string
names []string
qname string
hasZone bool
shouldRefuse bool
}{
{
name: "exact zone match",
origins: []string{"example.org."},
names: []string{"example.org."},
qname: "test.example.org.",
hasZone: true,
name: "exact zone match",
origins: []string{"example.org."},
names: []string{"example.org."},
qname: "test.example.org.",
hasZone: true,
shouldRefuse: false,
},
{
name: "subdomain zone match",
origins: []string{"example.org."},
names: []string{"example.org."},
qname: "sub.test.example.org.",
hasZone: true,
name: "subdomain zone match",
origins: []string{"example.org."},
names: []string{"example.org."},
qname: "sub.test.example.org.",
hasZone: true,
shouldRefuse: false,
},
{
name: "no origin match",
origins: []string{"other.org."},
names: []string{"example.org."},
qname: "test.example.org.",
hasZone: false,
name: "no origin match",
origins: []string{"other.org."},
names: []string{"example.org."},
qname: "test.example.org.",
hasZone: false,
shouldRefuse: false,
},
{
name: "origin match but no name match",
origins: []string{"example.org."},
names: []string{"other.org."},
qname: "test.example.org.",
hasZone: false,
name: "origin match but no name match",
origins: []string{"example.org."},
names: []string{"other.org."},
qname: "test.example.org.",
hasZone: false,
shouldRefuse: true,
},
}
@ -163,14 +168,18 @@ func TestAutoServeDNSZoneMatching(t *testing.T) {
rec := dnstest.NewRecorder(&test.ResponseWriter{})
ctx := context.Background()
_, err := a.ServeDNS(ctx, rec, m)
code, err := a.ServeDNS(ctx, rec, m)
if tt.hasZone {
if err != nil {
t.Errorf("Expected no error for zone match, got: %v", err)
}
} else {
if err == nil {
if tt.shouldRefuse {
if code != dns.RcodeRefused {
t.Errorf("Expected code %d, got %d", dns.RcodeRefused, code)
}
} else if err == nil {
t.Errorf("Expected error for no zone match, got nil")
}
}

View File

@ -42,6 +42,10 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
// TODO(miek): match the qname better in the map
zone := plugin.Zones(f.Zones.Names).Matches(qname)
if zone == "" {
// If no next plugin is configured, it's more correct to return REFUSED as file acts as an authoritative server
if f.Next == nil {
return dns.RcodeRefused, nil
}
return plugin.NextOrFailure(f.Name(), f.Next, ctx, w, r)
}

View File

@ -32,8 +32,8 @@ func TestAuto(t *testing.T) {
if err != nil {
t.Fatal("Expected to receive reply, but didn't")
}
if resp.Rcode != dns.RcodeServerFailure {
t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode)
if resp.Rcode != dns.RcodeRefused {
t.Fatalf("Expected reply to be REFUSED, got %d", resp.Rcode)
}
// Write db.example.org to get example.org.
@ -59,8 +59,8 @@ func TestAuto(t *testing.T) {
if err != nil {
t.Fatal("Expected to receive reply, but didn't")
}
if resp.Rcode != dns.RcodeServerFailure {
t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode)
if resp.Rcode != dns.RcodeRefused {
t.Fatalf("Expected reply to be REFUSED, got %d", resp.Rcode)
}
}
@ -93,8 +93,8 @@ func TestAutoNonExistentZone(t *testing.T) {
if err != nil {
t.Fatal("Expected to receive reply, but didn't")
}
if resp.Rcode != dns.RcodeServerFailure {
t.Fatalf("Expected reply to be a SERVFAIL, got %d", resp.Rcode)
if resp.Rcode != dns.RcodeRefused {
t.Fatalf("Expected reply to be REFUSED, got %d", resp.Rcode)
}
}