mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 10:13:14 -04:00 
			
		
		
		
	Add the rcode to the cached item and use this when we synthesize the answer again. We could also infer the rcode from the reassembled message, but this seems easier and is only an integer. Also set the autoritative bit to 0 for all from-cache answers. Fixes 357
		
			
				
	
	
		
			114 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package cache
 | |
| 
 | |
| import (
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/miekg/coredns/middleware/pkg/response"
 | |
| 	"github.com/miekg/dns"
 | |
| )
 | |
| 
 | |
| type item struct {
 | |
| 	Rcode              int
 | |
| 	Authoritative      bool
 | |
| 	AuthenticatedData  bool
 | |
| 	RecursionAvailable bool
 | |
| 	Answer             []dns.RR
 | |
| 	Ns                 []dns.RR
 | |
| 	Extra              []dns.RR
 | |
| 
 | |
| 	origTTL uint32
 | |
| 	stored  time.Time
 | |
| }
 | |
| 
 | |
| func newItem(m *dns.Msg, d time.Duration) *item {
 | |
| 	i := new(item)
 | |
| 	i.Rcode = m.Rcode
 | |
| 	i.Authoritative = m.Authoritative
 | |
| 	i.AuthenticatedData = m.AuthenticatedData
 | |
| 	i.RecursionAvailable = m.RecursionAvailable
 | |
| 	i.Answer = m.Answer
 | |
| 	i.Ns = m.Ns
 | |
| 	i.Extra = make([]dns.RR, len(m.Extra))
 | |
| 	// Don't copy OPT record as these are hop-by-hop.
 | |
| 	j := 0
 | |
| 	for _, e := range m.Extra {
 | |
| 		if e.Header().Rrtype == dns.TypeOPT {
 | |
| 			continue
 | |
| 		}
 | |
| 		i.Extra[j] = e
 | |
| 		j++
 | |
| 	}
 | |
| 	i.Extra = i.Extra[:j]
 | |
| 
 | |
| 	i.origTTL = uint32(d.Seconds())
 | |
| 	i.stored = time.Now().UTC()
 | |
| 
 | |
| 	return i
 | |
| }
 | |
| 
 | |
| // toMsg turns i into a message, it tailers the reply to m.
 | |
| // The Autoritative bit is always set to 0, because the answer is from the cache.
 | |
| func (i *item) toMsg(m *dns.Msg) *dns.Msg {
 | |
| 	m1 := new(dns.Msg)
 | |
| 	m1.SetReply(m)
 | |
| 
 | |
| 	m1.Authoritative = false
 | |
| 	m1.AuthenticatedData = i.AuthenticatedData
 | |
| 	m1.RecursionAvailable = i.RecursionAvailable
 | |
| 	m1.Rcode = i.Rcode
 | |
| 	m1.Compress = true
 | |
| 
 | |
| 	m1.Answer = i.Answer
 | |
| 	m1.Ns = i.Ns
 | |
| 	m1.Extra = i.Extra
 | |
| 
 | |
| 	ttl := int(i.origTTL) - int(time.Now().UTC().Sub(i.stored).Seconds())
 | |
| 	if ttl < int(minTTL.Seconds()) {
 | |
| 		ttl = int(minTTL.Seconds())
 | |
| 	}
 | |
| 	setMsgTTL(m1, uint32(ttl))
 | |
| 	return m1
 | |
| }
 | |
| 
 | |
| func (i *item) expired(now time.Time) bool {
 | |
| 	ttl := int(i.origTTL) - int(now.UTC().Sub(i.stored).Seconds())
 | |
| 	return ttl < 0
 | |
| }
 | |
| 
 | |
| // setMsgTTL sets the ttl on all RRs in all sections.
 | |
| func setMsgTTL(m *dns.Msg, ttl uint32) {
 | |
| 	for _, r := range m.Answer {
 | |
| 		r.Header().Ttl = ttl
 | |
| 	}
 | |
| 	for _, r := range m.Ns {
 | |
| 		r.Header().Ttl = ttl
 | |
| 	}
 | |
| 	for _, r := range m.Extra {
 | |
| 		if r.Header().Rrtype == dns.TypeOPT {
 | |
| 			continue
 | |
| 		}
 | |
| 		r.Header().Ttl = ttl
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func minMsgTTL(m *dns.Msg, mt response.Type) time.Duration {
 | |
| 	if mt != response.NoError && mt != response.NameError && mt != response.NoData {
 | |
| 		return 0
 | |
| 	}
 | |
| 
 | |
| 	minTTL := maxTTL
 | |
| 	for _, r := range append(m.Answer, m.Ns...) {
 | |
| 		switch mt {
 | |
| 		case response.NameError, response.NoData:
 | |
| 			if r.Header().Rrtype == dns.TypeSOA {
 | |
| 				return time.Duration(r.(*dns.SOA).Minttl) * time.Second
 | |
| 			}
 | |
| 		case response.NoError, response.Delegation:
 | |
| 			if r.Header().Ttl < uint32(minTTL.Seconds()) {
 | |
| 				minTTL = time.Duration(r.Header().Ttl) * time.Second
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return minTTL
 | |
| }
 |