dnscrypt-proxy/dnscrypt-proxy/plugin_cache.go

160 lines
3.3 KiB
Go
Raw Normal View History

2018-01-16 18:21:17 +01:00
package main
import (
"crypto/sha512"
"encoding/binary"
"errors"
"sync"
"time"
lru "github.com/hashicorp/golang-lru"
"github.com/miekg/dns"
)
type CachedResponse struct {
expiration time.Time
msg dns.Msg
}
type CachedResponses struct {
sync.RWMutex
cache *lru.ARCCache
}
var cachedResponses CachedResponses
func computeCacheKey(pluginsState *PluginsState, msg *dns.Msg) ([32]byte, error) {
questions := msg.Question
if len(questions) != 1 {
return [32]byte{}, errors.New("No question present")
2018-01-16 18:21:17 +01:00
}
question := questions[0]
h := sha512.New512_256()
var tmp [5]byte
binary.LittleEndian.PutUint16(tmp[0:2], question.Qtype)
binary.LittleEndian.PutUint16(tmp[2:4], question.Qclass)
if pluginsState.dnssec {
tmp[4] = 1
2018-01-16 18:21:17 +01:00
}
h.Write(tmp[:])
normalizedName := []byte(question.Name)
NormalizeName(&normalizedName)
h.Write(normalizedName)
var sum [32]byte
h.Sum(sum[:0])
return sum, nil
2018-01-16 18:21:17 +01:00
}
// ---
2018-01-16 18:21:17 +01:00
type PluginCache struct {
}
func (plugin *PluginCache) Name() string {
return "cache"
}
func (plugin *PluginCache) Description() string {
return "DNS cache (reader)."
}
func (plugin *PluginCache) Init(proxy *Proxy) error {
return nil
}
func (plugin *PluginCache) Drop() error {
return nil
}
func (plugin *PluginCache) Reload() error {
return nil
}
func (plugin *PluginCache) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
cacheKey, err := computeCacheKey(pluginsState, msg)
if err != nil {
return nil
}
cachedResponses.RLock()
defer cachedResponses.RUnlock()
if cachedResponses.cache == nil {
2018-01-16 18:21:17 +01:00
return nil
}
cachedAny, ok := cachedResponses.cache.Get(cacheKey)
2018-01-16 18:21:17 +01:00
if !ok {
return nil
}
2018-01-31 08:38:22 +01:00
cached := cachedAny.(CachedResponse)
2018-01-16 18:21:17 +01:00
if time.Now().After(cached.expiration) {
return nil
}
updateTTL(&cached.msg, cached.expiration)
2018-01-16 18:21:17 +01:00
synth := cached.msg
synth.Id = msg.Id
synth.Response = true
synth.Compress = true
synth.Question = msg.Question
pluginsState.synthResponse = &synth
pluginsState.action = PluginsActionSynth
pluginsState.cacheHit = true
2018-01-16 18:21:17 +01:00
return nil
}
// ---
type PluginCacheResponse struct {
}
func (plugin *PluginCacheResponse) Name() string {
return "cache_response"
}
func (plugin *PluginCacheResponse) Description() string {
return "DNS cache (writer)."
}
func (plugin *PluginCacheResponse) Init(proxy *Proxy) error {
return nil
}
func (plugin *PluginCacheResponse) Drop() error {
return nil
}
func (plugin *PluginCacheResponse) Reload() error {
return nil
}
func (plugin *PluginCacheResponse) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
if msg.Rcode != dns.RcodeSuccess && msg.Rcode != dns.RcodeNameError && msg.Rcode != dns.RcodeNotAuth {
return nil
2018-01-16 18:21:17 +01:00
}
if msg.Truncated {
return nil
2018-01-16 18:21:17 +01:00
}
cacheKey, err := computeCacheKey(pluginsState, msg)
if err != nil {
return err
}
ttl := getMinTTL(msg, pluginsState.cacheMinTTL, pluginsState.cacheMaxTTL, pluginsState.cacheNegMinTTL, pluginsState.cacheNegMaxTTL)
cachedResponse := CachedResponse{
expiration: time.Now().Add(ttl),
msg: *msg,
}
cachedResponses.Lock()
if cachedResponses.cache == nil {
cachedResponses.cache, err = lru.NewARC(pluginsState.cacheSize)
if err != nil {
cachedResponses.Unlock()
return err
}
}
cachedResponses.cache.Add(cacheKey, cachedResponse)
cachedResponses.Unlock()
updateTTL(msg, cachedResponse.expiration)
return nil
2018-01-16 18:21:17 +01:00
}