middleware/cache: only cache query and responses (#397)

Extent typify to check the transfers, dynamic updates and notifies.
Extend *cache* to not put these in the cache.

Fixes #393
This commit is contained in:
Miek Gieben 2016-11-07 16:27:50 +00:00 committed by GitHub
parent 4318dfbf02
commit e89c4b5c28
2 changed files with 36 additions and 6 deletions

View file

@ -29,13 +29,16 @@ type Cache struct {
pttl time.Duration pttl time.Duration
} }
// Return key under which we store the item. // Return key under which we store the item. The empty string is returned
// when we don't want to cache the message. Currently we do not cache Truncated, errors
// zone transfers or dynamic update messages.
func key(m *dns.Msg, t response.Type, do bool) string { func key(m *dns.Msg, t response.Type, do bool) string {
// We don't store truncated responses.
if m.Truncated { if m.Truncated {
// TODO(miek): wise to store truncated responses?
return "" return ""
} }
if t == response.OtherError { // Nor errors or Meta or Update
if t == response.OtherError || t == response.Meta || t == response.Update {
return "" return ""
} }
@ -65,6 +68,7 @@ func (c *ResponseWriter) WriteMsg(res *dns.Msg) error {
do = opt.Do() do = opt.Do()
} }
// key returns empty string for anything we don't want to cache.
key := key(res, mt, do) key := key(res, mt, do)
duration := c.pttl duration := c.pttl

View file

@ -14,11 +14,15 @@ const (
NoError Type = iota NoError Type = iota
// NameError is a NXDOMAIN in header, SOA in auth. // NameError is a NXDOMAIN in header, SOA in auth.
NameError NameError
// NoData indicated name found, but not the type: NOERROR in header, SOA in auth. // NoData indicates name found, but not the type: NOERROR in header, SOA in auth.
NoData NoData
// Delegation is a msg with a pointer to another nameserver: NOERROR in header, NS in auth, optionally fluff in additional (not checked). // Delegation is a msg with a pointer to another nameserver: NOERROR in header, NS in auth, optionally fluff in additional (not checked).
Delegation Delegation
// OtherError indicated any other error: don't cache these. // Meta indicates a meta message, NOTIFY, or a transfer: qType is IXFR or AXFR.
Meta
// Update is an dynamic update message.
Update
// OtherError indicates any other error: don't cache these.
OtherError OtherError
) )
@ -32,6 +36,10 @@ func (t Type) String() string {
return "NODATA" return "NODATA"
case Delegation: case Delegation:
return "DELEGATION" return "DELEGATION"
case Meta:
return "META"
case Update:
return "UPDATE"
case OtherError: case OtherError:
return "OTHERERROR" return "OTHERERROR"
} }
@ -50,6 +58,10 @@ func TypeFromString(s string) (Type, error) {
return NoData, nil return NoData, nil
case "DELEGATION": case "DELEGATION":
return Delegation, nil return Delegation, nil
case "META":
return Meta, nil
case "UPDATE":
return Update, nil
case "OTHERERROR": case "OTHERERROR":
return OtherError, nil return OtherError, nil
} }
@ -61,9 +73,23 @@ func Typify(m *dns.Msg) (Type, *dns.OPT) {
if m == nil { if m == nil {
return OtherError, nil return OtherError, nil
} }
opt := m.IsEdns0() opt := m.IsEdns0()
if m.Opcode == dns.OpcodeUpdate {
return Update, opt
}
// Check transfer and update first
if m.Opcode == dns.OpcodeNotify {
return Meta, opt
}
if len(m.Question) > 0 {
if m.Question[0].Qtype == dns.TypeAXFR || m.Question[0].Qtype == dns.TypeIXFR {
return Meta, opt
}
}
if len(m.Answer) > 0 && m.Rcode == dns.RcodeSuccess { if len(m.Answer) > 0 && m.Rcode == dns.RcodeSuccess {
return NoError, opt return NoError, opt
} }