vendor-ed skydns
This commit is contained in:
167
vendor/github.com/skynetservices/skydns/cache/cache.go
generated
vendored
Normal file
167
vendor/github.com/skynetservices/skydns/cache/cache.go
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package cache
|
||||
|
||||
// Cache that holds RRs and for DNSSEC an RRSIG.
|
||||
|
||||
// TODO(miek): there is a lot of copying going on to copy myself out of data
|
||||
// races. This should be optimized.
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Elem hold an answer and additional section that returned from the cache.
|
||||
// The signature is put in answer, extra is empty there. This wastes some memory.
|
||||
type elem struct {
|
||||
expiration time.Time // time added + TTL, after this the elem is invalid
|
||||
msg *dns.Msg
|
||||
}
|
||||
|
||||
// Cache is a cache that holds on the a number of RRs or DNS messages. The cache
|
||||
// eviction is randomized.
|
||||
type Cache struct {
|
||||
sync.RWMutex
|
||||
|
||||
capacity int
|
||||
m map[string]*elem
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
// New returns a new cache with the capacity and the ttl specified.
|
||||
func New(capacity, ttl int) *Cache {
|
||||
c := new(Cache)
|
||||
c.m = make(map[string]*elem)
|
||||
c.capacity = capacity
|
||||
c.ttl = time.Duration(ttl) * time.Second
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cache) Capacity() int { return c.capacity }
|
||||
|
||||
func (c *Cache) Remove(s string) {
|
||||
c.Lock()
|
||||
delete(c.m, s)
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// EvictRandom removes a random member a the cache.
|
||||
// Must be called under a write lock.
|
||||
func (c *Cache) EvictRandom() {
|
||||
clen := len(c.m)
|
||||
if clen < c.capacity {
|
||||
return
|
||||
}
|
||||
i := c.capacity - clen
|
||||
for k, _ := range c.m {
|
||||
delete(c.m, k)
|
||||
i--
|
||||
if i == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InsertMessage inserts a message in the Cache. We will cache it for ttl seconds, which
|
||||
// should be a small (60...300) integer.
|
||||
func (c *Cache) InsertMessage(s string, msg *dns.Msg) {
|
||||
if c.capacity <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
if _, ok := c.m[s]; !ok {
|
||||
c.m[s] = &elem{time.Now().UTC().Add(c.ttl), msg.Copy()}
|
||||
|
||||
}
|
||||
c.EvictRandom()
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// InsertSignature inserts a signature, the expiration time is used as the cache ttl.
|
||||
func (c *Cache) InsertSignature(s string, sig *dns.RRSIG) {
|
||||
if c.capacity <= 0 {
|
||||
return
|
||||
}
|
||||
c.Lock()
|
||||
|
||||
if _, ok := c.m[s]; !ok {
|
||||
m := ((int64(sig.Expiration) - time.Now().Unix()) / (1 << 31)) - 1
|
||||
if m < 0 {
|
||||
m = 0
|
||||
}
|
||||
t := time.Unix(int64(sig.Expiration)-(m*(1<<31)), 0).UTC()
|
||||
c.m[s] = &elem{t, &dns.Msg{Answer: []dns.RR{dns.Copy(sig)}}}
|
||||
}
|
||||
c.EvictRandom()
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// Search returns a dns.Msg, the expiration time and a boolean indicating if we found something
|
||||
// in the cache.
|
||||
func (c *Cache) Search(s string) (*dns.Msg, time.Time, bool) {
|
||||
if c.capacity <= 0 {
|
||||
return nil, time.Time{}, false
|
||||
}
|
||||
c.RLock()
|
||||
if e, ok := c.m[s]; ok {
|
||||
e1 := e.msg.Copy()
|
||||
c.RUnlock()
|
||||
return e1, e.expiration, true
|
||||
}
|
||||
c.RUnlock()
|
||||
return nil, time.Time{}, false
|
||||
}
|
||||
|
||||
// Key creates a hash key from a question section. It creates a different key
|
||||
// for requests with DNSSEC.
|
||||
func Key(q dns.Question, dnssec, tcp bool) string {
|
||||
h := sha1.New()
|
||||
i := append([]byte(q.Name), packUint16(q.Qtype)...)
|
||||
if dnssec {
|
||||
i = append(i, byte(255))
|
||||
}
|
||||
if tcp {
|
||||
i = append(i, byte(254))
|
||||
}
|
||||
return string(h.Sum(i))
|
||||
}
|
||||
|
||||
// Key uses the name, type and rdata, which is serialized and then hashed as the key for the lookup.
|
||||
func KeyRRset(rrs []dns.RR) string {
|
||||
h := sha1.New()
|
||||
i := []byte(rrs[0].Header().Name)
|
||||
i = append(i, packUint16(rrs[0].Header().Rrtype)...)
|
||||
for _, r := range rrs {
|
||||
switch t := r.(type) { // we only do a few type, serialize these manually
|
||||
case *dns.SOA:
|
||||
// We only fiddle with the serial so store that.
|
||||
i = append(i, packUint32(t.Serial)...)
|
||||
case *dns.SRV:
|
||||
i = append(i, packUint16(t.Priority)...)
|
||||
i = append(i, packUint16(t.Weight)...)
|
||||
i = append(i, packUint16(t.Weight)...)
|
||||
i = append(i, []byte(t.Target)...)
|
||||
case *dns.A:
|
||||
i = append(i, []byte(t.A)...)
|
||||
case *dns.AAAA:
|
||||
i = append(i, []byte(t.AAAA)...)
|
||||
case *dns.NSEC3:
|
||||
i = append(i, []byte(t.NextDomain)...)
|
||||
// Bitmap does not differentiate in SkyDNS.
|
||||
case *dns.DNSKEY:
|
||||
case *dns.NS:
|
||||
case *dns.TXT:
|
||||
}
|
||||
}
|
||||
return string(h.Sum(i))
|
||||
}
|
||||
|
||||
func packUint16(i uint16) []byte { return []byte{byte(i >> 8), byte(i)} }
|
||||
func packUint32(i uint32) []byte { return []byte{byte(i >> 24), byte(i >> 16), byte(i >> 8), byte(i)} }
|
||||
31
vendor/github.com/skynetservices/skydns/cache/hit.go
generated
vendored
Normal file
31
vendor/github.com/skynetservices/skydns/cache/hit.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2014 The SkyDNS Authors. All rights reserved.
|
||||
// Use of this source code is governed by The MIT License (MIT) that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Hit returns a dns message from the cache. If the message's TTL is expired nil
|
||||
// is returned and the message is removed from the cache.
|
||||
func (c *Cache) Hit(question dns.Question, dnssec, tcp bool, msgid uint16) *dns.Msg {
|
||||
key := Key(question, dnssec, tcp)
|
||||
m1, exp, hit := c.Search(key)
|
||||
if hit {
|
||||
// Cache hit! \o/
|
||||
if time.Since(exp) < 0 {
|
||||
m1.Id = msgid
|
||||
m1.Compress = true
|
||||
// Even if something ended up with the TC bit *in* the cache, set it to off
|
||||
m1.Truncated = false
|
||||
return m1
|
||||
}
|
||||
// Expired! /o\
|
||||
c.Remove(key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user