diff options
author | 2020-09-17 16:28:43 +0200 | |
---|---|---|
committer | 2020-09-17 07:28:43 -0700 | |
commit | acf9a0fa19928e605ac8ac3314890c9fef73e16b (patch) | |
tree | a442ad2a7894d86b462eade46c44db4572016333 /plugin/cache/handler.go | |
parent | 22b68466262219284a47063e7f7bf9a833d21b61 (diff) | |
download | coredns-acf9a0fa19928e605ac8ac3314890c9fef73e16b.tar.gz coredns-acf9a0fa19928e605ac8ac3314890c9fef73e16b.tar.zst coredns-acf9a0fa19928e605ac8ac3314890c9fef73e16b.zip |
cache: default to DNSSEC (#4085)
* cache: default to DNSSEC
This change does away with the DNS/DNSSEC distinction the cache
currently makes. Cache will always make coredns perform a DNSSEC query
and store that result. If a client just needs plain DNS, the DNSSEC
records are stripped from the response.
It should also be more memory efficient, because we store a reply once
and not one DNS and another for DNSSEC.
Fixes: #3836
Signed-off-by: Miek Gieben <miek@miek.nl>
* Change OPT RR when one is present in the msg.
Signed-off-by: Miek Gieben <miek@miek.nl>
* Fix comment for isDNSSEC
Signed-off-by: Miek Gieben <miek@miek.nl>
* Update plugin/cache/handler.go
Co-authored-by: Chris O'Haver <cohaver@infoblox.com>
* Update plugin/cache/item.go
Co-authored-by: Chris O'Haver <cohaver@infoblox.com>
* Code review; fix comment for isDNSSEC
Signed-off-by: Miek Gieben <miek@miek.nl>
* Update doc and set AD to false
Set Authenticated Data to false when DNSSEC was not wanted. Also update
the readme with the new behavior.
Signed-off-by: Miek Gieben <miek@miek.nl>
* Update plugin/cache/handler.go
Co-authored-by: Chris O'Haver <cohaver@infoblox.com>
Co-authored-by: Chris O'Haver <cohaver@infoblox.com>
Diffstat (limited to 'plugin/cache/handler.go')
-rw-r--r-- | plugin/cache/handler.go | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/plugin/cache/handler.go b/plugin/cache/handler.go index 20a058ed2..f079e6c51 100644 --- a/plugin/cache/handler.go +++ b/plugin/cache/handler.go @@ -15,6 +15,7 @@ import ( // ServeDNS implements the plugin.Handler interface. func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := request.Request{W: w, Req: r} + do := state.Do() zone := plugin.Zones(c.Zones).Matches(state.Name()) if zone == "" { @@ -22,15 +23,24 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) } now := c.now().UTC() - 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 + // set we will modify the request to _add_ one. This means we will always do DNSSEC lookups on cache misses. + // When writing to cache, any DNSSEC RRs in the response are written to cache with the response. + // When sending a response to a non-DNSSEC client, we remove DNSSEC RRs from the response. We use a 2048 buffer size, which is + // 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 i := c.getIgnoreTTL(now, state, server) if i != nil { ttl = i.ttl(now) } if i == nil { + if !do { + setDo(r) + } crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server} return plugin.NextOrFailure(c.Name(), c.Next, ctx, crr, r) } @@ -40,11 +50,14 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) now = now.Add(time.Duration(ttl) * time.Second) go func() { r := r.Copy() + if !do { + setDo(r) + } crr := &ResponseWriter{Cache: c, state: state, server: server, prefetch: true, remoteAddr: w.LocalAddr()} plugin.NextOrFailure(c.Name(), c.Next, ctx, crr, r) }() } - resp := i.toMsg(r, now) + resp := i.toMsg(r, now, do) w.WriteMsg(resp) if c.shouldPrefetch(i, now) { @@ -80,7 +93,7 @@ func (c *Cache) shouldPrefetch(i *item, now time.Time) bool { func (c *Cache) Name() string { return "cache" } func (c *Cache) get(now time.Time, state request.Request, server string) (*item, bool) { - k := hash(state.Name(), state.QType(), state.Do()) + k := hash(state.Name(), state.QType()) if i, ok := c.ncache.Get(k); ok && i.(*item).ttl(now) > 0 { cacheHits.WithLabelValues(server, Denial).Inc() @@ -97,7 +110,7 @@ func (c *Cache) get(now time.Time, state request.Request, server string) (*item, // getIgnoreTTL unconditionally returns an item if it exists in the cache. func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string) *item { - k := hash(state.Name(), state.QType(), state.Do()) + k := hash(state.Name(), state.QType()) if i, ok := c.ncache.Get(k); ok { ttl := i.(*item).ttl(now) @@ -118,7 +131,7 @@ func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string } func (c *Cache) exists(state request.Request) *item { - k := hash(state.Name(), state.QType(), state.Do()) + k := hash(state.Name(), state.QType()) if i, ok := c.ncache.Get(k); ok { return i.(*item) } @@ -127,3 +140,22 @@ func (c *Cache) exists(state request.Request) *item { } 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 |