plugin/cache: Add cache disable option (#5540)
* add cache disable options Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
This commit is contained in:
parent
2fe5273cd1
commit
95fcf2c480
6 changed files with 158 additions and 3 deletions
13
plugin/cache/README.md
vendored
13
plugin/cache/README.md
vendored
|
@ -39,6 +39,7 @@ cache [TTL] [ZONES...] {
|
|||
prefetch AMOUNT [[DURATION] [PERCENTAGE%]]
|
||||
serve_stale [DURATION] [REFRESH_MODE]
|
||||
servfail DURATION
|
||||
disable success|denial [ZONES...]
|
||||
}
|
||||
~~~
|
||||
|
||||
|
@ -67,6 +68,8 @@ cache [TTL] [ZONES...] {
|
|||
* `servfail` cache SERVFAIL responses for **DURATION**. Setting **DURATION** to 0 will disable caching of SERVFAIL
|
||||
responses. If this option is not set, SERVFAIL responses will be cached for 5 seconds. **DURATION** may not be
|
||||
greater than 5 minutes.
|
||||
* `disable` disable the success or denial cache for the listed **ZONES**. If no **ZONES** are given, the specified
|
||||
cache will be disabled for all zones.
|
||||
|
||||
## Capacity and Eviction
|
||||
|
||||
|
@ -124,3 +127,13 @@ example.org {
|
|||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Enable caching for `example.org`, but do not cache denials in `sub.example.org`:
|
||||
|
||||
~~~ corefile
|
||||
example.org {
|
||||
cache {
|
||||
disable denial sub.example.org
|
||||
}
|
||||
}
|
||||
~~~
|
14
plugin/cache/cache.go
vendored
14
plugin/cache/cache.go
vendored
|
@ -43,6 +43,10 @@ type Cache struct {
|
|||
staleUpTo time.Duration
|
||||
verifyStale bool
|
||||
|
||||
// Positive/negative zone exceptions
|
||||
pexcept []string
|
||||
nexcept []string
|
||||
|
||||
// Testing.
|
||||
now func() time.Time
|
||||
}
|
||||
|
@ -117,6 +121,8 @@ type ResponseWriter struct {
|
|||
|
||||
wildcardFunc func() string // function to retrieve wildcard name that synthesized the result.
|
||||
|
||||
pexcept []string // positive zone exceptions
|
||||
nexcept []string // negative zone exceptions
|
||||
}
|
||||
|
||||
// newPrefetchResponseWriter returns a Cache ResponseWriter to be used in
|
||||
|
@ -204,6 +210,10 @@ func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration
|
|||
// and key is valid
|
||||
switch mt {
|
||||
case response.NoError, response.Delegation:
|
||||
if plugin.Zones(w.pexcept).Matches(m.Question[0].Name) != "" {
|
||||
// zone is in exception list, do not cache
|
||||
return
|
||||
}
|
||||
i := newItem(m, w.now(), duration)
|
||||
if w.wildcardFunc != nil {
|
||||
i.wildcard = w.wildcardFunc()
|
||||
|
@ -217,6 +227,10 @@ func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration
|
|||
}
|
||||
|
||||
case response.NameError, response.NoData, response.ServerError:
|
||||
if plugin.Zones(w.nexcept).Matches(m.Question[0].Name) != "" {
|
||||
// zone is in exception list, do not cache
|
||||
return
|
||||
}
|
||||
i := newItem(m, w.now(), duration)
|
||||
if w.wildcardFunc != nil {
|
||||
i.wildcard = w.wildcardFunc()
|
||||
|
|
63
plugin/cache/cache_test.go
vendored
63
plugin/cache/cache_test.go
vendored
|
@ -17,8 +17,8 @@ import (
|
|||
)
|
||||
|
||||
type cacheTestCase struct {
|
||||
test.Case
|
||||
in test.Case
|
||||
test.Case // the expected message coming "out" of cache
|
||||
in test.Case // the test message going "in" to cache
|
||||
AuthenticatedData bool
|
||||
RecursionAvailable bool
|
||||
Truncated bool
|
||||
|
@ -163,6 +163,62 @@ var cacheTestCases = []cacheTestCase{
|
|||
},
|
||||
shouldCache: true,
|
||||
},
|
||||
{
|
||||
in: test.Case{
|
||||
Rcode: dns.RcodeNameError,
|
||||
Qname: "neg-disabled.example.org.", Qtype: dns.TypeA,
|
||||
Ns: []dns.RR{
|
||||
test.SOA("example.org. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2016082540 7200 3600 1209600 3600"),
|
||||
},
|
||||
},
|
||||
Case: test.Case{},
|
||||
shouldCache: false,
|
||||
},
|
||||
{
|
||||
in: test.Case{
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Qname: "pos-disabled.example.org.", Qtype: dns.TypeA,
|
||||
Answer: []dns.RR{
|
||||
test.A("pos-disabled.example.org. 3600 IN A 127.0.0.1"),
|
||||
},
|
||||
},
|
||||
Case: test.Case{},
|
||||
shouldCache: false,
|
||||
},
|
||||
{
|
||||
in: test.Case{
|
||||
Rcode: dns.RcodeNameError,
|
||||
Qname: "pos-disabled.example.org.", Qtype: dns.TypeA,
|
||||
Ns: []dns.RR{
|
||||
test.SOA("example.org. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2016082540 7200 3600 1209600 3600"),
|
||||
},
|
||||
},
|
||||
Case: test.Case{
|
||||
Rcode: dns.RcodeNameError,
|
||||
Qname: "pos-disabled.example.org.", Qtype: dns.TypeA,
|
||||
Ns: []dns.RR{
|
||||
test.SOA("example.org. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2016082540 7200 3600 1209600 3600"),
|
||||
},
|
||||
},
|
||||
shouldCache: true,
|
||||
},
|
||||
{
|
||||
in: test.Case{
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Qname: "neg-disabled.example.org.", Qtype: dns.TypeA,
|
||||
Answer: []dns.RR{
|
||||
test.A("neg-disabled.example.org. 3600 IN A 127.0.0.1"),
|
||||
},
|
||||
},
|
||||
Case: test.Case{
|
||||
Rcode: dns.RcodeSuccess,
|
||||
Qname: "neg-disabled.example.org.", Qtype: dns.TypeA,
|
||||
Answer: []dns.RR{
|
||||
test.A("neg-disabled.example.org. 3600 IN A 127.0.0.1"),
|
||||
},
|
||||
},
|
||||
shouldCache: true,
|
||||
},
|
||||
}
|
||||
|
||||
func cacheMsg(m *dns.Msg, tc cacheTestCase) *dns.Msg {
|
||||
|
@ -183,6 +239,9 @@ func newTestCache(ttl time.Duration) (*Cache, *ResponseWriter) {
|
|||
c.nttl = ttl
|
||||
|
||||
crr := &ResponseWriter{ResponseWriter: nil, Cache: c}
|
||||
crr.nexcept = []string{"neg-disabled.example.org."}
|
||||
crr.pexcept = []string{"pos-disabled.example.org."}
|
||||
|
||||
return c, crr
|
||||
}
|
||||
|
||||
|
|
3
plugin/cache/handler.go
vendored
3
plugin/cache/handler.go
vendored
|
@ -38,7 +38,8 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
|
|||
ttl := 0
|
||||
i := c.getIgnoreTTL(now, state, server)
|
||||
if i == nil {
|
||||
crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do, ad: ad, wildcardFunc: wildcardFunc(ctx)}
|
||||
crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do, ad: ad,
|
||||
nexcept: c.nexcept, pexcept: c.pexcept, wildcardFunc: wildcardFunc(ctx)}
|
||||
return c.doRefresh(ctx, state, crr)
|
||||
}
|
||||
ttl = i.ttl(now)
|
||||
|
|
29
plugin/cache/setup.go
vendored
29
plugin/cache/setup.go
vendored
|
@ -205,6 +205,35 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
|
|||
return nil, errors.New("caching SERVFAIL responses over 5 minutes is not permitted")
|
||||
}
|
||||
ca.failttl = d
|
||||
case "disable":
|
||||
// disable [success|denial] [zones]...
|
||||
args := c.RemainingArgs()
|
||||
if len(args) < 1 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
||||
var zones []string
|
||||
if len(args) > 1 {
|
||||
for _, z := range args[1:] { // args[1:] define the list of zones to disable
|
||||
nz := plugin.Name(z).Normalize()
|
||||
if nz == "" {
|
||||
return nil, fmt.Errorf("invalid disabled zone: %s", z)
|
||||
}
|
||||
zones = append(zones, nz)
|
||||
}
|
||||
} else {
|
||||
// if no zones specified, default to root
|
||||
zones = []string{"."}
|
||||
}
|
||||
|
||||
switch args[0] { // args[0] defines which cache to disable
|
||||
case Denial:
|
||||
ca.nexcept = zones
|
||||
case Success:
|
||||
ca.pexcept = zones
|
||||
default:
|
||||
return nil, fmt.Errorf("cache type for disable must be %q or %q", Success, Denial)
|
||||
}
|
||||
default:
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
|
|
39
plugin/cache/setup_test.go
vendored
39
plugin/cache/setup_test.go
vendored
|
@ -192,3 +192,42 @@ func TestServfail(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisable(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
shouldErr bool
|
||||
nexcept []string
|
||||
pexcept []string
|
||||
}{
|
||||
// positive
|
||||
{"disable denial example.com example.org", false, []string{"example.com.", "example.org."}, nil},
|
||||
{"disable success example.com example.org", false, nil, []string{"example.com.", "example.org."}},
|
||||
{"disable denial", false, []string{"."}, nil},
|
||||
{"disable success", false, nil, []string{"."}},
|
||||
{"disable denial example.com example.org\ndisable success example.com example.org", false,
|
||||
[]string{"example.com.", "example.org."}, []string{"example.com.", "example.org."}},
|
||||
// negative
|
||||
{"disable invalid example.com example.org", true, nil, nil},
|
||||
}
|
||||
for i, test := range tests {
|
||||
c := caddy.NewTestController("dns", fmt.Sprintf("cache {\n%s\n}", test.input))
|
||||
ca, err := cacheParse(c)
|
||||
if test.shouldErr && err == nil {
|
||||
t.Errorf("Test %v: Expected error but found nil", i)
|
||||
continue
|
||||
} else if !test.shouldErr && err != nil {
|
||||
t.Errorf("Test %v: Expected no error but found error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if test.shouldErr {
|
||||
continue
|
||||
}
|
||||
if fmt.Sprintf("%v", test.nexcept) != fmt.Sprintf("%v", ca.nexcept) {
|
||||
t.Errorf("Test %v: Expected %v but got: %v", i, test.nexcept, ca.nexcept)
|
||||
}
|
||||
if fmt.Sprintf("%v", test.pexcept) != fmt.Sprintf("%v", ca.pexcept) {
|
||||
t.Errorf("Test %v: Expected %v but got: %v", i, test.pexcept, ca.pexcept)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue