mirror of
				https://github.com/miekg/dns.git
				synced 2025-11-04 04:31:01 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			118 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
// Keep a local cache of DNS packets. Match incoming
 | 
						|
// qname,qclass,qtype and return the saved packet.
 | 
						|
// On a cache miss consult the nameserver
 | 
						|
 | 
						|
import (
 | 
						|
	"dns"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// Keep everything in the cache for 60 seconds
 | 
						|
const (
 | 
						|
	CACHETTL = 1
 | 
						|
	_CLASS   = 2 << 16
 | 
						|
 | 
						|
	INSERT = iota
 | 
						|
	DELETE
 | 
						|
)
 | 
						|
 | 
						|
var cache Cache
 | 
						|
 | 
						|
type item struct {
 | 
						|
	epoch int64
 | 
						|
	msg   []byte
 | 
						|
}
 | 
						|
 | 
						|
// Number in the second map denotes the class + type.
 | 
						|
func intval(c, t uint16) int {
 | 
						|
	return int(c)*_CLASS + int(t)
 | 
						|
}
 | 
						|
 | 
						|
// Mutex entry in the cache, if non-nill take the lock
 | 
						|
// Ala Zone in zone.go, but slightly different
 | 
						|
type Cache struct {
 | 
						|
	data map[string]map[int]*item
 | 
						|
	rw   *sync.RWMutex
 | 
						|
}
 | 
						|
 | 
						|
func NewCache() Cache {
 | 
						|
	c := new(Cache)
 | 
						|
	c.data = make(map[string]map[int]*item)
 | 
						|
	c.rw = new(sync.RWMutex)
 | 
						|
	return *c
 | 
						|
}
 | 
						|
 | 
						|
// Add an entry to the cache. The old entry (if any) gets overwritten
 | 
						|
func (c Cache) add(q *dns.Msg) {
 | 
						|
	c.rw.Lock()
 | 
						|
	defer c.rw.Unlock()
 | 
						|
	qname := q.Question[0].Name
 | 
						|
	i := intval(q.Question[0].Qclass, q.Question[0].Qtype)
 | 
						|
	if c.data[qname] == nil {
 | 
						|
		im := make(map[int]*item)
 | 
						|
		c.data[qname] = im
 | 
						|
	}
 | 
						|
	buf, _ := q.Pack()
 | 
						|
	im := c.data[qname]
 | 
						|
	im[i] = &item{time.Seconds(), buf}
 | 
						|
}
 | 
						|
 | 
						|
// Lookup an entry in the cache. Returns nil
 | 
						|
// when nothing found.
 | 
						|
func (c Cache) lookup(q *dns.Msg) []byte {
 | 
						|
	// Use the question section for looking up
 | 
						|
	c.rw.RLock()
 | 
						|
	defer c.rw.RUnlock()
 | 
						|
	i := intval(q.Question[0].Qclass, q.Question[0].Qtype)
 | 
						|
	if im, ok := c.data[q.Question[0].Name]; ok {
 | 
						|
		// we have the name
 | 
						|
		if d, ok := im[i]; ok {
 | 
						|
			// We even have the entry, check cache time
 | 
						|
			if time.Seconds()-d.epoch > CACHETTL {
 | 
						|
				// Too olds means we get a new one
 | 
						|
				return nil
 | 
						|
			}
 | 
						|
			e := make([]byte, len(d.msg))
 | 
						|
			copy(e, d.msg)
 | 
						|
			return e
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func checkcache(m *dns.Msg) (o []byte) {
 | 
						|
	// Check if we have the packet in Cache
 | 
						|
	// if so, return it. Otherwise ask the
 | 
						|
	// server, return that answer and put it
 | 
						|
	// in the cache.
 | 
						|
	o = cache.lookup(m)
 | 
						|
	if o != nil {
 | 
						|
		// octet 1 and 2 contain the Id, set the one for the current pkt
 | 
						|
		dns.RawSetId(o, 0, m.MsgHdr.Id)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	println("Cache miss")
 | 
						|
	var p *dns.Msg
 | 
						|
	for _, c := range qr {
 | 
						|
		p, _ = c.Client.Exchange(m, c.Addr)
 | 
						|
	}
 | 
						|
	cache.add(p)
 | 
						|
	o, _ = p.Pack()
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Return the configration
 | 
						|
func NewFunkenSturm() *FunkenSturm {
 | 
						|
	f := new(FunkenSturm)
 | 
						|
	f.Funk = make([]*Funk, 1)
 | 
						|
	f.Setup = func() bool { cache = NewCache(); return true }
 | 
						|
	f.Funk[0] = new(Funk)
 | 
						|
	f.Funk[0].Match = func(m *dns.Msg) (*dns.Msg, bool) { return m, true }
 | 
						|
	f.Funk[0].Action = checkcache
 | 
						|
	return f
 | 
						|
}
 |