middleware/secondary: fix crash with no zone (#680)

When CoreDNS starts up and can't get a zone transfer going the Apex is
empty. This `nil` is then transformed into wireformat, which fails with
a nil pointer dereference in Go DNS.

In this case we should just return SERVFAIL, because we don't have any
info (yet). Note the lookup code returned NXDOMAIN, which is correct
from a lookup standpoint, but also invalidates every name in the future
loaded zone.

Anyway, look for an apex before doing the lookup and return SERVFAIL if
nothing is found.

Fixes #679
This commit is contained in:
Miek Gieben 2017-06-01 12:33:40 +01:00 committed by GitHub
parent e261ac1a6e
commit 30ecb83dce
2 changed files with 55 additions and 0 deletions

View file

@ -39,6 +39,14 @@ func (z *Zone) Lookup(state request.Request, qname string) ([]dns.RR, []dns.RR,
} }
}() }()
// If z is a secondary zone we might not have transfered it, meaning we have
// all zone context setup, except the actual record. This means (for one thing) the apex
// is empty and we don't have a SOA record.
soa := z.Apex.SOA
if soa == nil {
return nil, nil, nil, ServerFailure
}
if qtype == dns.TypeSOA { if qtype == dns.TypeSOA {
return z.soa(do), z.ns(do), nil, Success return z.soa(do), z.ns(do), nil, Success
} }

47
test/secondary_test.go Normal file
View file

@ -0,0 +1,47 @@
package test
import (
"io/ioutil"
"log"
"testing"
"github.com/coredns/coredns/middleware/proxy"
"github.com/coredns/coredns/middleware/test"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
func TestEmptySecondaryZone(t *testing.T) {
// Corefile that fails to transfer example.org.
corefile := `example.org:0 {
secondary {
transfer from 127.0.0.1:1717
}
}
`
i, err := CoreDNSServer(corefile)
if err != nil {
t.Fatalf("Could not get CoreDNS serving instance: %s", err)
}
udp, _ := CoreDNSServerPorts(i, 0)
if udp == "" {
t.Fatal("Could not get UDP listening port")
}
defer i.Stop()
log.SetOutput(ioutil.Discard)
p := proxy.NewLookup([]string{udp})
state := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
resp, err := p.Lookup(state, "www.example.org.", dns.TypeA)
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)
}
}