mirror of
https://github.com/coredns/coredns.git
synced 2025-10-27 08:14:18 -04:00
plugin/cache: cache now uses source query DNSSEC option for upstream refresh (#5671)
Signed-off-by: Grant Spence <gspence@redhat.com> Signed-off-by: Grant Spence <gspence@redhat.com>
This commit is contained in:
3
plugin/cache/README.md
vendored
3
plugin/cache/README.md
vendored
@@ -10,8 +10,7 @@ With *cache* enabled, all records except zone transfers and metadata records wil
|
|||||||
3600s. Caching is mostly useful in a scenario when fetching data from the backend (upstream,
|
3600s. Caching is mostly useful in a scenario when fetching data from the backend (upstream,
|
||||||
database, etc.) is expensive.
|
database, etc.) is expensive.
|
||||||
|
|
||||||
*Cache* will change the query to enable DNSSEC (DNSSEC OK; DO) if it passes through the plugin. If
|
*Cache* will pass DNSSEC (DNSSEC OK; DO) options through the plugin for upstream queries.
|
||||||
the client didn't request any DNSSEC (records), these are filtered out when replying.
|
|
||||||
|
|
||||||
This plugin can only be used once per Server Block.
|
This plugin can only be used once per Server Block.
|
||||||
|
|
||||||
|
|||||||
26
plugin/cache/cache.go
vendored
26
plugin/cache/cache.go
vendored
@@ -76,7 +76,7 @@ func New() *Cache {
|
|||||||
// key returns key under which we store the item, -1 will be returned if we don't store the message.
|
// key returns key under which we store the item, -1 will be returned if we don't store the message.
|
||||||
// Currently we do not cache Truncated, errors zone transfers or dynamic update messages.
|
// Currently we do not cache Truncated, errors zone transfers or dynamic update messages.
|
||||||
// qname holds the already lowercased qname.
|
// qname holds the already lowercased qname.
|
||||||
func key(qname string, m *dns.Msg, t response.Type) (bool, uint64) {
|
func key(qname string, m *dns.Msg, t response.Type, do bool) (bool, uint64) {
|
||||||
// We don't store truncated responses.
|
// We don't store truncated responses.
|
||||||
if m.Truncated {
|
if m.Truncated {
|
||||||
return false, 0
|
return false, 0
|
||||||
@@ -86,11 +86,21 @@ func key(qname string, m *dns.Msg, t response.Type) (bool, uint64) {
|
|||||||
return false, 0
|
return false, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, hash(qname, m.Question[0].Qtype)
|
return true, hash(qname, m.Question[0].Qtype, do)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hash(qname string, qtype uint16) uint64 {
|
var one = []byte("1")
|
||||||
|
var zero = []byte("0")
|
||||||
|
|
||||||
|
func hash(qname string, qtype uint16, do bool) uint64 {
|
||||||
h := fnv.New64()
|
h := fnv.New64()
|
||||||
|
|
||||||
|
if do {
|
||||||
|
h.Write(one)
|
||||||
|
} else {
|
||||||
|
h.Write(zero)
|
||||||
|
}
|
||||||
|
|
||||||
h.Write([]byte{byte(qtype >> 8)})
|
h.Write([]byte{byte(qtype >> 8)})
|
||||||
h.Write([]byte{byte(qtype)})
|
h.Write([]byte{byte(qtype)})
|
||||||
h.Write([]byte(qname))
|
h.Write([]byte(qname))
|
||||||
@@ -145,6 +155,7 @@ func newPrefetchResponseWriter(server string, state request.Request, c *Cache) *
|
|||||||
Cache: c,
|
Cache: c,
|
||||||
state: state,
|
state: state,
|
||||||
server: server,
|
server: server,
|
||||||
|
do: state.Do(),
|
||||||
prefetch: true,
|
prefetch: true,
|
||||||
remoteAddr: addr,
|
remoteAddr: addr,
|
||||||
}
|
}
|
||||||
@@ -163,7 +174,7 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
|||||||
mt, _ := response.Typify(res, w.now().UTC())
|
mt, _ := response.Typify(res, w.now().UTC())
|
||||||
|
|
||||||
// key returns empty string for anything we don't want to cache.
|
// key returns empty string for anything we don't want to cache.
|
||||||
hasKey, key := key(w.state.Name(), res, mt)
|
hasKey, key := key(w.state.Name(), res, mt, w.do)
|
||||||
|
|
||||||
msgTTL := dnsutil.MinimalTTL(res, mt)
|
msgTTL := dnsutil.MinimalTTL(res, mt)
|
||||||
var duration time.Duration
|
var duration time.Duration
|
||||||
@@ -191,11 +202,10 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply capped TTL to this reply to avoid jarring TTL experience 1799 -> 8 (e.g.)
|
// Apply capped TTL to this reply to avoid jarring TTL experience 1799 -> 8 (e.g.)
|
||||||
// We also may need to filter out DNSSEC records, see toMsg() for similar code.
|
|
||||||
ttl := uint32(duration.Seconds())
|
ttl := uint32(duration.Seconds())
|
||||||
res.Answer = filterRRSlice(res.Answer, ttl, w.do, false)
|
res.Answer = filterRRSlice(res.Answer, ttl, false)
|
||||||
res.Ns = filterRRSlice(res.Ns, ttl, w.do, false)
|
res.Ns = filterRRSlice(res.Ns, ttl, false)
|
||||||
res.Extra = filterRRSlice(res.Extra, ttl, w.do, false)
|
res.Extra = filterRRSlice(res.Extra, ttl, false)
|
||||||
|
|
||||||
if !w.do && !w.ad {
|
if !w.do && !w.ad {
|
||||||
// unset AD bit if requester is not OK with DNSSEC
|
// unset AD bit if requester is not OK with DNSSEC
|
||||||
|
|||||||
22
plugin/cache/cache_test.go
vendored
22
plugin/cache/cache_test.go
vendored
@@ -27,6 +27,7 @@ type cacheTestCase struct {
|
|||||||
|
|
||||||
var cacheTestCases = []cacheTestCase{
|
var cacheTestCases = []cacheTestCase{
|
||||||
{
|
{
|
||||||
|
// Test with Authenticated Data bit
|
||||||
RecursionAvailable: true, AuthenticatedData: true,
|
RecursionAvailable: true, AuthenticatedData: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
||||||
@@ -45,6 +46,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: true,
|
shouldCache: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test case sensitivity
|
||||||
RecursionAvailable: true, AuthenticatedData: true,
|
RecursionAvailable: true, AuthenticatedData: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
||||||
@@ -58,13 +60,12 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
Answer: []dns.RR{
|
Answer: []dns.RR{
|
||||||
test.MX("miek.nl. 3601 IN MX 1 aspmx.l.google.com."),
|
test.MX("miek.nl. 3601 IN MX 1 aspmx.l.google.com."),
|
||||||
test.MX("miek.nl. 3601 IN MX 10 aspmx2.googlemail.com."),
|
test.MX("miek.nl. 3601 IN MX 10 aspmx2.googlemail.com."),
|
||||||
// RRSIG must be here, because we are always doing DNSSEC lookups, and miek.nl MX is tested later in this list as well.
|
|
||||||
test.RRSIG("miek.nl. 3600 IN RRSIG MX 8 2 1800 20160521031301 20160421031301 12051 miek.nl. lAaEzB5teQLLKyDenatmyhca7blLRg9DoGNrhe3NReBZN5C5/pMQk8Jc u25hv2fW23/SLm5IC2zaDpp2Fzgm6Jf7e90/yLcwQPuE7JjS55WMF+HE LEh7Z6AEb+Iq4BWmNhUz6gPxD4d9eRMs7EAzk13o1NYi5/JhfL6IlaYy qkc="),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shouldCache: true,
|
shouldCache: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test truncated responses don't get cached
|
||||||
Truncated: true,
|
Truncated: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
||||||
@@ -74,6 +75,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: false,
|
shouldCache: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test dns.RcodeNameError cache
|
||||||
RecursionAvailable: true,
|
RecursionAvailable: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Rcode: dns.RcodeNameError,
|
Rcode: dns.RcodeNameError,
|
||||||
@@ -92,6 +94,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: true,
|
shouldCache: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test dns.RcodeServerFailure cache
|
||||||
RecursionAvailable: true,
|
RecursionAvailable: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Rcode: dns.RcodeServerFailure,
|
Rcode: dns.RcodeServerFailure,
|
||||||
@@ -106,6 +109,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: true,
|
shouldCache: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test dns.RcodeNotImplemented cache
|
||||||
RecursionAvailable: true,
|
RecursionAvailable: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Rcode: dns.RcodeNotImplemented,
|
Rcode: dns.RcodeNotImplemented,
|
||||||
@@ -120,6 +124,8 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: true,
|
shouldCache: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test cache has separate items for query DO Bit value
|
||||||
|
// This doesn't cache because this RRSIG is expired and previous tests used DO Bit false
|
||||||
RecursionAvailable: true,
|
RecursionAvailable: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
Qname: "miek.nl.", Qtype: dns.TypeMX,
|
||||||
@@ -139,9 +145,10 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
test.RRSIG("miek.nl. 1800 IN RRSIG MX 8 2 1800 20160521031301 20160421031301 12051 miek.nl. lAaEzB5teQLLKyDenatmyhca7blLRg9DoGNrhe3NReBZN5C5/pMQk8Jc u25hv2fW23/SLm5IC2zaDpp2Fzgm6Jf7e90/yLcwQPuE7JjS55WMF+HE LEh7Z6AEb+Iq4BWmNhUz6gPxD4d9eRMs7EAzk13o1NYi5/JhfL6IlaYy qkc="),
|
test.RRSIG("miek.nl. 1800 IN RRSIG MX 8 2 1800 20160521031301 20160421031301 12051 miek.nl. lAaEzB5teQLLKyDenatmyhca7blLRg9DoGNrhe3NReBZN5C5/pMQk8Jc u25hv2fW23/SLm5IC2zaDpp2Fzgm6Jf7e90/yLcwQPuE7JjS55WMF+HE LEh7Z6AEb+Iq4BWmNhUz6gPxD4d9eRMs7EAzk13o1NYi5/JhfL6IlaYy qkc="),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shouldCache: true,
|
shouldCache: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test DO Bit with a RRSIG that is not expired
|
||||||
RecursionAvailable: true,
|
RecursionAvailable: true,
|
||||||
Case: test.Case{
|
Case: test.Case{
|
||||||
Qname: "example.org.", Qtype: dns.TypeMX,
|
Qname: "example.org.", Qtype: dns.TypeMX,
|
||||||
@@ -164,6 +171,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: true,
|
shouldCache: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test negative zone exception
|
||||||
in: test.Case{
|
in: test.Case{
|
||||||
Rcode: dns.RcodeNameError,
|
Rcode: dns.RcodeNameError,
|
||||||
Qname: "neg-disabled.example.org.", Qtype: dns.TypeA,
|
Qname: "neg-disabled.example.org.", Qtype: dns.TypeA,
|
||||||
@@ -175,6 +183,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: false,
|
shouldCache: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test positive zone exception
|
||||||
in: test.Case{
|
in: test.Case{
|
||||||
Rcode: dns.RcodeSuccess,
|
Rcode: dns.RcodeSuccess,
|
||||||
Qname: "pos-disabled.example.org.", Qtype: dns.TypeA,
|
Qname: "pos-disabled.example.org.", Qtype: dns.TypeA,
|
||||||
@@ -186,6 +195,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: false,
|
shouldCache: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test positive zone exception with negative answer
|
||||||
in: test.Case{
|
in: test.Case{
|
||||||
Rcode: dns.RcodeNameError,
|
Rcode: dns.RcodeNameError,
|
||||||
Qname: "pos-disabled.example.org.", Qtype: dns.TypeA,
|
Qname: "pos-disabled.example.org.", Qtype: dns.TypeA,
|
||||||
@@ -203,6 +213,7 @@ var cacheTestCases = []cacheTestCase{
|
|||||||
shouldCache: true,
|
shouldCache: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// Test negative zone exception with positive answer
|
||||||
in: test.Case{
|
in: test.Case{
|
||||||
Rcode: dns.RcodeSuccess,
|
Rcode: dns.RcodeSuccess,
|
||||||
Qname: "neg-disabled.example.org.", Qtype: dns.TypeA,
|
Qname: "neg-disabled.example.org.", Qtype: dns.TypeA,
|
||||||
@@ -258,7 +269,7 @@ func TestCache(t *testing.T) {
|
|||||||
state := request.Request{W: &test.ResponseWriter{}, Req: m}
|
state := request.Request{W: &test.ResponseWriter{}, Req: m}
|
||||||
|
|
||||||
mt, _ := response.Typify(m, utc)
|
mt, _ := response.Typify(m, utc)
|
||||||
valid, k := key(state.Name(), m, mt)
|
valid, k := key(state.Name(), m, mt, state.Do())
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
crr.set(m, k, mt, c.pttl)
|
crr.set(m, k, mt, c.pttl)
|
||||||
@@ -647,6 +658,7 @@ func TestCacheWildcardMetadata(t *testing.T) {
|
|||||||
|
|
||||||
req := new(dns.Msg)
|
req := new(dns.Msg)
|
||||||
req.SetQuestion(qname, dns.TypeA)
|
req.SetQuestion(qname, dns.TypeA)
|
||||||
|
state := request.Request{W: &test.ResponseWriter{}, Req: req}
|
||||||
|
|
||||||
// 1. Test writing wildcard metadata retrieved from backend to the cache
|
// 1. Test writing wildcard metadata retrieved from backend to the cache
|
||||||
|
|
||||||
@@ -656,7 +668,7 @@ func TestCacheWildcardMetadata(t *testing.T) {
|
|||||||
if c.pcache.Len() != 1 {
|
if c.pcache.Len() != 1 {
|
||||||
t.Errorf("Msg should have been cached")
|
t.Errorf("Msg should have been cached")
|
||||||
}
|
}
|
||||||
_, k := key(qname, w.Msg, response.NoError)
|
_, k := key(qname, w.Msg, response.NoError, state.Do())
|
||||||
i, _ := c.pcache.Get(k)
|
i, _ := c.pcache.Get(k)
|
||||||
if i.(*item).wildcard != wildcard {
|
if i.(*item).wildcard != wildcard {
|
||||||
t.Errorf("expected wildcard reponse to enter cache with cache item's wildcard = %q, got %q", wildcard, i.(*item).wildcard)
|
t.Errorf("expected wildcard reponse to enter cache with cache item's wildcard = %q, got %q", wildcard, i.(*item).wildcard)
|
||||||
|
|||||||
28
plugin/cache/dnssec.go
vendored
28
plugin/cache/dnssec.go
vendored
@@ -2,35 +2,13 @@ package cache
|
|||||||
|
|
||||||
import "github.com/miekg/dns"
|
import "github.com/miekg/dns"
|
||||||
|
|
||||||
// isDNSSEC returns true if r is a DNSSEC record. NSEC,NSEC3,DS and RRSIG/SIG
|
// filterRRSlice filters out OPT RRs, and sets all RR TTLs to ttl.
|
||||||
// are DNSSEC records. DNSKEYs is not in this list on the assumption that the
|
// If dup is true the RRs in rrs are _copied_ into the slice that is
|
||||||
// client explicitly 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// filterRRSlice filters rrs and removes DNSSEC RRs when do is false. In the returned slice
|
|
||||||
// the TTLs are set to ttl. If dup is true the RRs in rrs are _copied_ into the slice that is
|
|
||||||
// returned.
|
// returned.
|
||||||
func filterRRSlice(rrs []dns.RR, ttl uint32, do, dup bool) []dns.RR {
|
func filterRRSlice(rrs []dns.RR, ttl uint32, dup bool) []dns.RR {
|
||||||
j := 0
|
j := 0
|
||||||
rs := make([]dns.RR, len(rrs))
|
rs := make([]dns.RR, len(rrs))
|
||||||
for _, r := range rrs {
|
for _, r := range rrs {
|
||||||
if !do && isDNSSEC(r) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if r.Header().Rrtype == dns.TypeOPT {
|
if r.Header().Rrtype == dns.TypeOPT {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
33
plugin/cache/dnssec_test.go
vendored
33
plugin/cache/dnssec_test.go
vendored
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/coredns/coredns/plugin"
|
"github.com/coredns/coredns/plugin"
|
||||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||||
"github.com/coredns/coredns/plugin/test"
|
"github.com/coredns/coredns/plugin/test"
|
||||||
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
@@ -67,19 +68,27 @@ func dnssecHandler() plugin.Handler {
|
|||||||
return plugin.HandlerFunc(func(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
return plugin.HandlerFunc(func(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetQuestion("example.org.", dns.TypeA)
|
m.SetQuestion("example.org.", dns.TypeA)
|
||||||
|
state := request.Request{W: &test.ResponseWriter{}, Req: r}
|
||||||
|
|
||||||
m.AuthenticatedData = true
|
m.AuthenticatedData = true
|
||||||
m.Answer = make([]dns.RR, 4)
|
// If query has the DO bit, then send DNSSEC responses (RRSIGs)
|
||||||
m.Answer[0] = test.CNAME("invent.example.org. 1781 IN CNAME leptone.example.org.")
|
if state.Do() {
|
||||||
m.Answer[1] = test.RRSIG("invent.example.org. 1781 IN RRSIG CNAME 8 3 1800 20201012085750 20200912082613 57411 example.org. ijSv5FmsNjFviBcOFwQgqjt073lttxTTNqkno6oMa3DD3kC+")
|
m.Answer = make([]dns.RR, 4)
|
||||||
m.Answer[2] = test.A("leptone.example.org. 1781 IN A 195.201.182.103")
|
m.Answer[0] = test.CNAME("invent.example.org. 1781 IN CNAME leptone.example.org.")
|
||||||
m.Answer[3] = test.RRSIG("leptone.example.org. 1781 IN RRSIG A 8 3 1800 20201012093630 20200912083827 57411 example.org. eLuSOkLAzm/WIOpaZD3/4TfvKP1HAFzjkis9LIJSRVpQt307dm9WY9")
|
m.Answer[1] = test.RRSIG("invent.example.org. 1781 IN RRSIG CNAME 8 3 1800 20201012085750 20200912082613 57411 example.org. ijSv5FmsNjFviBcOFwQgqjt073lttxTTNqkno6oMa3DD3kC+")
|
||||||
|
m.Answer[2] = test.A("leptone.example.org. 1781 IN A 195.201.182.103")
|
||||||
|
m.Answer[3] = test.RRSIG("leptone.example.org. 1781 IN RRSIG A 8 3 1800 20201012093630 20200912083827 57411 example.org. eLuSOkLAzm/WIOpaZD3/4TfvKP1HAFzjkis9LIJSRVpQt307dm9WY9")
|
||||||
|
} else {
|
||||||
|
m.Answer = make([]dns.RR, 2)
|
||||||
|
m.Answer[0] = test.CNAME("invent.example.org. 1781 IN CNAME leptone.example.org.")
|
||||||
|
m.Answer[1] = test.A("leptone.example.org. 1781 IN A 195.201.182.103")
|
||||||
|
}
|
||||||
w.WriteMsg(m)
|
w.WriteMsg(m)
|
||||||
return dns.RcodeSuccess, nil
|
return dns.RcodeSuccess, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFliterRRSlice(t *testing.T) {
|
func TestFilterRRSlice(t *testing.T) {
|
||||||
rrs := []dns.RR{
|
rrs := []dns.RR{
|
||||||
test.CNAME("invent.example.org. 1781 IN CNAME leptone.example.org."),
|
test.CNAME("invent.example.org. 1781 IN CNAME leptone.example.org."),
|
||||||
test.RRSIG("invent.example.org. 1781 IN RRSIG CNAME 8 3 1800 20201012085750 20200912082613 57411 example.org. ijSv5FmsNjFviBcOFwQgqjt073lttxTTNqkno6oMa3DD3kC+"),
|
test.RRSIG("invent.example.org. 1781 IN RRSIG CNAME 8 3 1800 20201012085750 20200912082613 57411 example.org. ijSv5FmsNjFviBcOFwQgqjt073lttxTTNqkno6oMa3DD3kC+"),
|
||||||
@@ -87,7 +96,7 @@ func TestFliterRRSlice(t *testing.T) {
|
|||||||
test.RRSIG("leptone.example.org. 1781 IN RRSIG A 8 3 1800 20201012093630 20200912083827 57411 example.org. eLuSOkLAzm/WIOpaZD3/4TfvKP1HAFzjkis9LIJSRVpQt307dm9WY9"),
|
test.RRSIG("leptone.example.org. 1781 IN RRSIG A 8 3 1800 20201012093630 20200912083827 57411 example.org. eLuSOkLAzm/WIOpaZD3/4TfvKP1HAFzjkis9LIJSRVpQt307dm9WY9"),
|
||||||
}
|
}
|
||||||
|
|
||||||
filter1 := filterRRSlice(rrs, 0, true, false)
|
filter1 := filterRRSlice(rrs, 0, false)
|
||||||
if len(filter1) != 4 {
|
if len(filter1) != 4 {
|
||||||
t.Errorf("Expected 4 RRs after filtering, got %d", len(filter1))
|
t.Errorf("Expected 4 RRs after filtering, got %d", len(filter1))
|
||||||
}
|
}
|
||||||
@@ -101,9 +110,9 @@ func TestFliterRRSlice(t *testing.T) {
|
|||||||
t.Errorf("Expected 2 RRSIGs after filtering, got %d", rrsig)
|
t.Errorf("Expected 2 RRSIGs after filtering, got %d", rrsig)
|
||||||
}
|
}
|
||||||
|
|
||||||
filter2 := filterRRSlice(rrs, 0, false, false)
|
filter2 := filterRRSlice(rrs, 0, false)
|
||||||
if len(filter2) != 2 {
|
if len(filter2) != 4 {
|
||||||
t.Errorf("Expected 2 RRs after filtering, got %d", len(filter2))
|
t.Errorf("Expected 4 RRs after filtering, got %d", len(filter2))
|
||||||
}
|
}
|
||||||
rrsig = 0
|
rrsig = 0
|
||||||
for _, f := range filter2 {
|
for _, f := range filter2 {
|
||||||
@@ -111,7 +120,7 @@ func TestFliterRRSlice(t *testing.T) {
|
|||||||
rrsig++
|
rrsig++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rrsig != 0 {
|
if rrsig != 2 {
|
||||||
t.Errorf("Expected 0 RRSIGs after filtering, got %d", rrsig)
|
t.Errorf("Expected 2 RRSIGs after filtering, got %d", rrsig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
plugin/cache/handler.go
vendored
36
plugin/cache/handler.go
vendored
@@ -28,12 +28,10 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||||||
now := c.now().UTC()
|
now := c.now().UTC()
|
||||||
server := metrics.WithServer(ctx)
|
server := metrics.WithServer(ctx)
|
||||||
|
|
||||||
// On cache miss, if the request has the OPT record and the DO bit set we leave the message as-is. If there isn't a DO bit
|
// On cache refresh, we will just use the DO bit from the incoming query for the refresh since we key our cache
|
||||||
// set we will modify the request to _add_ one. This means we will always do DNSSEC lookups on cache misses.
|
// with the query DO bit. That means two separate cache items for the query DO bit true or false. In the situation
|
||||||
// When writing to cache, any DNSSEC RRs in the response are written to cache with the response.
|
// in which upstream doesn't support DNSSEC, the two cache items will effectively be the same. Regardless, any
|
||||||
// When sending a response to a non-DNSSEC client, we remove DNSSEC RRs from the response. We use a 2048 buffer size, which is
|
// DNSSEC RRs in the response are written to cache with the response.
|
||||||
// less than 4096 (and older default) and more than 1024 which may be too small. We might need to tweaks this
|
|
||||||
// value to be smaller still to prevent UDP fragmentation?
|
|
||||||
|
|
||||||
ttl := 0
|
ttl := 0
|
||||||
i := c.getIgnoreTTL(now, state, server)
|
i := c.getIgnoreTTL(now, state, server)
|
||||||
@@ -101,9 +99,6 @@ func (c *Cache) doPrefetch(ctx context.Context, state request.Request, cw *Respo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) doRefresh(ctx context.Context, state request.Request, cw dns.ResponseWriter) (int, error) {
|
func (c *Cache) doRefresh(ctx context.Context, state request.Request, cw dns.ResponseWriter) (int, error) {
|
||||||
if !state.Do() {
|
|
||||||
setDo(state.Req)
|
|
||||||
}
|
|
||||||
return plugin.NextOrFailure(c.Name(), c.Next, ctx, cw, state.Req)
|
return plugin.NextOrFailure(c.Name(), c.Next, ctx, cw, state.Req)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +116,7 @@ func (c *Cache) Name() string { return "cache" }
|
|||||||
|
|
||||||
// getIgnoreTTL unconditionally returns an item if it exists in the cache.
|
// getIgnoreTTL unconditionally returns an item if it exists in the cache.
|
||||||
func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string) *item {
|
func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string) *item {
|
||||||
k := hash(state.Name(), state.QType())
|
k := hash(state.Name(), state.QType(), state.Do())
|
||||||
cacheRequests.WithLabelValues(server, c.zonesMetricLabel, c.viewMetricLabel).Inc()
|
cacheRequests.WithLabelValues(server, c.zonesMetricLabel, c.viewMetricLabel).Inc()
|
||||||
|
|
||||||
if i, ok := c.ncache.Get(k); ok {
|
if i, ok := c.ncache.Get(k); ok {
|
||||||
@@ -145,7 +140,7 @@ func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) exists(state request.Request) *item {
|
func (c *Cache) exists(state request.Request) *item {
|
||||||
k := hash(state.Name(), state.QType())
|
k := hash(state.Name(), state.QType(), state.Do())
|
||||||
if i, ok := c.ncache.Get(k); ok {
|
if i, ok := c.ncache.Get(k); ok {
|
||||||
return i.(*item)
|
return i.(*item)
|
||||||
}
|
}
|
||||||
@@ -154,22 +149,3 @@ func (c *Cache) exists(state request.Request) *item {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setDo sets the DO bit and UDP buffer size in the message m.
|
|
||||||
func setDo(m *dns.Msg) {
|
|
||||||
o := m.IsEdns0()
|
|
||||||
if o != nil {
|
|
||||||
o.SetDo()
|
|
||||||
o.SetUDPSize(defaultUDPBufSize)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
o = &dns.OPT{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeOPT}}
|
|
||||||
o.SetDo()
|
|
||||||
o.SetUDPSize(defaultUDPBufSize)
|
|
||||||
m.Extra = append(m.Extra, o)
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultUDPBufsize is the bufsize the cache plugin uses on outgoing requests that don't
|
|
||||||
// have an OPT RR.
|
|
||||||
const defaultUDPBufSize = 2048
|
|
||||||
|
|||||||
6
plugin/cache/item.go
vendored
6
plugin/cache/item.go
vendored
@@ -87,9 +87,9 @@ func (i *item) toMsg(m *dns.Msg, now time.Time, do bool, ad bool) *dns.Msg {
|
|||||||
m1.Extra = make([]dns.RR, len(i.Extra))
|
m1.Extra = make([]dns.RR, len(i.Extra))
|
||||||
|
|
||||||
ttl := uint32(i.ttl(now))
|
ttl := uint32(i.ttl(now))
|
||||||
m1.Answer = filterRRSlice(i.Answer, ttl, do, true)
|
m1.Answer = filterRRSlice(i.Answer, ttl, true)
|
||||||
m1.Ns = filterRRSlice(i.Ns, ttl, do, true)
|
m1.Ns = filterRRSlice(i.Ns, ttl, true)
|
||||||
m1.Extra = filterRRSlice(i.Extra, ttl, do, true)
|
m1.Extra = filterRRSlice(i.Extra, ttl, true)
|
||||||
|
|
||||||
return m1
|
return m1
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user