plugin/cache: Fix filtering (#4148)

The filtering of DNSSEC records in the cache plugin was not done
correctly. Also the change to introduced this bug didn't take into
account that the cache - by virtue of differentiating between DNSSEC and
no-DNSSEC - relied on not copying the data from the cache.

This change copies and then filters the data and factors the filtering
into a function that is used in two places (albeit with on ugly boolean
parameters to prevent copying things twice).

Add tests, do_test.go is moved to test/cache_test.go because the OPT
handing is done outside of the cache plugin. The core server re-attaches
the correct OPT when replying, so that makes for a better e2e test.

Added small unit test for filterRRslice and an explicit test that asks
for DNSSEC first and then plain, and vice versa to test cache behavior.

Fixes: #4146

Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
Miek Gieben
2020-09-28 16:53:00 +02:00
committed by GitHub
parent 1a1ce9a9c8
commit 35b40a84f2
7 changed files with 220 additions and 163 deletions

54
plugin/cache/item.go vendored
View File

@@ -75,37 +75,10 @@ func (i *item) toMsg(m *dns.Msg, now time.Time, do bool) *dns.Msg {
m1.Extra = make([]dns.RR, len(i.Extra))
ttl := uint32(i.ttl(now))
j := 0
for _, r := range i.Answer {
if !do && isDNSSEC(r) {
continue
}
m1.Answer[j] = dns.Copy(r)
m1.Answer[j].Header().Ttl = ttl
j++
}
m1.Answer = m1.Answer[:j]
j = 0
for _, r := range i.Ns {
if !do && isDNSSEC(r) {
continue
}
m1.Ns[j] = dns.Copy(r)
m1.Ns[j].Header().Ttl = ttl
j++
}
m1.Ns = m1.Ns[:j]
// newItem skips OPT records, so we can just use i.Extra as is.
j = 0
for _, r := range i.Extra {
if !do && isDNSSEC(r) {
continue
}
m1.Extra[j] = dns.Copy(r)
m1.Extra[j].Header().Ttl = ttl
j++
}
m1.Extra = m1.Extra[:j]
m1.Answer = filterRRSlice(i.Answer, ttl, do, true)
m1.Ns = filterRRSlice(i.Ns, ttl, do, true)
m1.Extra = filterRRSlice(i.Extra, ttl, do, true)
return m1
}
@@ -113,22 +86,3 @@ func (i *item) ttl(now time.Time) int {
ttl := int(i.origTTL) - int(now.UTC().Sub(i.stored).Seconds())
return ttl
}
// isDNSSEC returns true if r is a DNSSEC record. NSEC,NSEC3,DS and RRSIG/SIG
// are DNSSEC records. DNSKEYs is not in this list on the assumption that the
// client explictly asked for it.
func isDNSSEC(r dns.RR) bool {
switch r.Header().Rrtype {
case dns.TypeNSEC:
return true
case dns.TypeNSEC3:
return true
case dns.TypeDS:
return true
case dns.TypeRRSIG:
return true
case dns.TypeSIG:
return true
}
return false
}