ServeDNS implements the plugin.Handler interface.
(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
| 15 | |
| 16 | // ServeDNS implements the plugin.Handler interface. |
| 17 | func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { |
| 18 | rc := r.Copy() // We potentially modify r, to prevent other plugins from seeing this (r is a pointer), copy r into rc. |
| 19 | state := request.Request{W: w, Req: rc} |
| 20 | do := state.Do() |
| 21 | cd := r.CheckingDisabled |
| 22 | ad := r.AuthenticatedData |
| 23 | |
| 24 | zone := plugin.Zones(c.Zones).Matches(state.Name()) |
| 25 | if zone == "" { |
| 26 | return plugin.NextOrFailure(c.Name(), c.Next, ctx, w, rc) |
| 27 | } |
| 28 | |
| 29 | now := c.now().UTC() |
| 30 | server := metrics.WithServer(ctx) |
| 31 | |
| 32 | // On cache refresh, we will just use the DO bit from the incoming query for the refresh since we key our cache |
| 33 | // with the query DO bit. That means two separate cache items for the query DO bit true or false. In the situation |
| 34 | // in which upstream doesn't support DNSSEC, the two cache items will effectively be the same. Regardless, any |
| 35 | // DNSSEC RRs in the response are written to cache with the response. |
| 36 | |
| 37 | i := c.getIfNotStale(now, state, server) |
| 38 | if i == nil { |
| 39 | crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do, ad: ad, cd: cd, |
| 40 | nexcept: c.nexcept, pexcept: c.pexcept, wildcardFunc: wildcardFunc(ctx)} |
| 41 | return c.doRefresh(ctx, state, crr) |
| 42 | } |
| 43 | ttl := i.ttl(now) |
| 44 | if ttl < 0 { |
| 45 | // serve stale behavior |
| 46 | if c.verifyStale { |
| 47 | crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do, cd: cd} |
| 48 | if c.verifyStaleTimeout > 0 { |
| 49 | // Background verify: cache the response but do not write to the wire. |
| 50 | // On timeout, we serve the stale entry below and let the goroutine continue. |
| 51 | crr.prefetch = true |
| 52 | } |
| 53 | cw := newVerifyStaleResponseWriter(crr) |
| 54 | if c.verifyStaleTimeout == 0 { |
| 55 | ret, err := c.doRefresh(ctx, state, cw) |
| 56 | if cw.refreshed { |
| 57 | return ret, err |
| 58 | } |
| 59 | } else if served, ret, err := c.verifyWithTimeout(ctx, state, w, cw, r, do, ad); served { |
| 60 | return ret, err |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | // Adjust the time to get a 0 TTL in the reply built from a stale item. |
| 65 | now = now.Add(time.Duration(ttl) * time.Second) |
| 66 | if !c.verifyStale { |
| 67 | c.tryPrefetch(ctx, i, server, rc, do, cd, now) |
| 68 | } |
| 69 | servedStale.WithLabelValues(server, c.zonesMetricLabel, c.viewMetricLabel).Inc() |
| 70 | } else if c.shouldPrefetch(i, now) { |
| 71 | c.tryPrefetch(ctx, i, server, rc, do, cd, now) |
| 72 | } |
| 73 | |
| 74 | if i.wildcard != "" { |
nothing calls this directly
no test coverage detected