Memory cache implemented
This commit is contained in:
parent
2d49200a53
commit
57304bf910
17
README.MD
17
README.MD
|
@ -15,7 +15,13 @@ Similar as [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) ,but support
|
|||
* Cache records save in memory or redis configurable
|
||||
|
||||
|
||||
### Configuration
|
||||
## Install & Running
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
All the configuration on `godns.conf` a TOML formating config file.
|
||||
More about Toml :[https://github.com/mojombo/toml](https://github.com/mojombo/toml)
|
||||
|
@ -33,5 +39,14 @@ If multi `namerserver` set at resolv.conf, the upsteam server will try in order
|
|||
|
||||
|
||||
|
||||
#### hosts
|
||||
|
||||
|
||||
|
||||
|
||||
#### cache
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
139
cache.go
139
cache.go
|
@ -1,13 +1,144 @@
|
|||
package main
|
||||
|
||||
type Cache struct {
|
||||
config CacheSettings
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/miekg/dns"
|
||||
"time"
|
||||
)
|
||||
|
||||
type KeyNotFound struct {
|
||||
key string
|
||||
}
|
||||
|
||||
func (c *Cache) Get() {
|
||||
func (e KeyNotFound) Error() string {
|
||||
return e.key + " " + "not found"
|
||||
}
|
||||
|
||||
type KeyExpired struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func (e KeyExpired) Error() string {
|
||||
return e.Key + " " + "expired"
|
||||
}
|
||||
|
||||
type CacheIsFull struct {
|
||||
}
|
||||
|
||||
func (e CacheIsFull) Error() string {
|
||||
return "Cache is Full"
|
||||
}
|
||||
|
||||
type SerializerError struct {
|
||||
}
|
||||
|
||||
func (e SerializerError) Error() string {
|
||||
return "Serializer error"
|
||||
}
|
||||
|
||||
type Cache interface {
|
||||
Get(string) ([]byte, error)
|
||||
Set(string, *dns.Msg) error
|
||||
Exists(string) bool
|
||||
Remove()
|
||||
Length() int
|
||||
}
|
||||
|
||||
type MemoryCache struct {
|
||||
backend map[string]string
|
||||
serializer *JsonSerializer
|
||||
expire time.Duration
|
||||
maxcount int
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Get(key string) ([]byte, error) {
|
||||
fmt.Println(c.backend)
|
||||
data, ok := c.backend[key]
|
||||
if !ok {
|
||||
return nil, KeyNotFound{key}
|
||||
}
|
||||
return []byte(data), nil
|
||||
|
||||
// mesg := new(dns.Msg)
|
||||
// if err := c.serializer.Loads([]byte(data), &mesg); err != nil {
|
||||
// fmt.Println(err)
|
||||
// return nil, SerializerError{}
|
||||
// }
|
||||
// return mesg, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *Cache) Set() {
|
||||
func (c *MemoryCache) Set(key string, mesg *dns.Msg) error {
|
||||
if c.Full() && !c.Exists(key) {
|
||||
return CacheIsFull{}
|
||||
}
|
||||
// data, err := c.serializer.Dumps(mesg)
|
||||
|
||||
// if err != nil {
|
||||
// return SerializerError{}
|
||||
// }
|
||||
|
||||
c.backend[key] = mesg.String()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Remove() {
|
||||
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Exists(key string) bool {
|
||||
_, ok := c.backend[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Length() int {
|
||||
return len(c.backend)
|
||||
}
|
||||
|
||||
func (c *MemoryCache) Full() bool {
|
||||
// if maxcount is zero. the cache will never be full.
|
||||
if c.maxcount == 0 {
|
||||
return false
|
||||
}
|
||||
return c.Length() >= c.maxcount
|
||||
}
|
||||
|
||||
// type RedisCache struct{
|
||||
// backend redis.client
|
||||
// }
|
||||
|
||||
// func (c *RedisCache) Get(key string) {
|
||||
|
||||
// }
|
||||
|
||||
// func (c *RedisCache) Set() {
|
||||
|
||||
// }
|
||||
|
||||
// func (c &RedisCache) Remove(){
|
||||
|
||||
// }
|
||||
|
||||
func KeyGen(q Question) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(q.String()))
|
||||
x := h.Sum(nil)
|
||||
key := fmt.Sprintf("%x", x)
|
||||
return key
|
||||
}
|
||||
|
||||
type JsonSerializer struct {
|
||||
}
|
||||
|
||||
func (*JsonSerializer) Dumps(mesg *dns.Msg) (encoded []byte, err error) {
|
||||
encoded, err = json.Marshal(mesg)
|
||||
return
|
||||
}
|
||||
|
||||
func (*JsonSerializer) Loads(data []byte, mesg **dns.Msg) error {
|
||||
err := json.Unmarshal(data, mesg)
|
||||
return err
|
||||
|
||||
}
|
||||
|
|
75
handler.go
75
handler.go
|
@ -3,12 +3,22 @@ package main
|
|||
import (
|
||||
"github.com/miekg/dns"
|
||||
// "log"
|
||||
// "fmt"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Question struct {
|
||||
qname string
|
||||
qtype string
|
||||
qclass string
|
||||
}
|
||||
|
||||
func (q *Question) String() string {
|
||||
return q.qname + " " + q.qclass + " " + q.qtype
|
||||
}
|
||||
|
||||
type GODNSHandler struct {
|
||||
resolver *Resolver
|
||||
cache *Cache
|
||||
cache Cache
|
||||
}
|
||||
|
||||
func NewHandler() *GODNSHandler {
|
||||
|
@ -16,6 +26,8 @@ func NewHandler() *GODNSHandler {
|
|||
var (
|
||||
clientConfig *dns.ClientConfig
|
||||
cacheConfig CacheSettings
|
||||
resolver *Resolver
|
||||
cache Cache
|
||||
)
|
||||
|
||||
resolvConfig := settings.ResolvConfig
|
||||
|
@ -26,11 +38,28 @@ func NewHandler() *GODNSHandler {
|
|||
panic(err)
|
||||
}
|
||||
clientConfig.Timeout = resolvConfig.Timeout
|
||||
resolver := &Resolver{clientConfig}
|
||||
resolver = &Resolver{clientConfig}
|
||||
|
||||
cacheConfig = settings.Cache
|
||||
cache := &Cache{cacheConfig}
|
||||
|
||||
switch cacheConfig.Backend {
|
||||
case "memory":
|
||||
cache = &MemoryCache{
|
||||
backend: make(map[string]string),
|
||||
serializer: new(JsonSerializer),
|
||||
expire: cacheConfig.Expire,
|
||||
maxcount: cacheConfig.Maxcount,
|
||||
}
|
||||
case "redis":
|
||||
cache = &MemoryCache{
|
||||
backend: make(map[string]string),
|
||||
serializer: new(JsonSerializer),
|
||||
expire: cacheConfig.Expire,
|
||||
maxcount: cacheConfig.Maxcount,
|
||||
}
|
||||
default:
|
||||
logger.Printf("Invalid cache backend %s", cacheConfig.Backend)
|
||||
panic("Invalid cache backend")
|
||||
}
|
||||
return &GODNSHandler{resolver, cache}
|
||||
}
|
||||
|
||||
|
@ -41,6 +70,22 @@ func (h *GODNSHandler) do(net string, w dns.ResponseWriter, req *dns.Msg) {
|
|||
|
||||
Debug("Question: %s", Q.String())
|
||||
|
||||
key := KeyGen(Q)
|
||||
fmt.Println(key)
|
||||
// Only query cache when qtype == 'A' , qclass == 'IN'
|
||||
if q.Qtype == dns.TypeA && q.Qclass == dns.ClassINET {
|
||||
mesg, err := h.cache.Get(key)
|
||||
if err != nil {
|
||||
Debug("%s didn't hit cache: %s", Q.String(), err)
|
||||
} else {
|
||||
Debug("%s hit cache", Q.String())
|
||||
fmt.Println(string(mesg))
|
||||
w.Write(mesg)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mesg, err := h.resolver.Lookup(net, req)
|
||||
|
||||
if err != nil {
|
||||
|
@ -51,6 +96,16 @@ func (h *GODNSHandler) do(net string, w dns.ResponseWriter, req *dns.Msg) {
|
|||
|
||||
w.WriteMsg(mesg)
|
||||
|
||||
if q.Qtype == dns.TypeA && q.Qclass == dns.ClassINET {
|
||||
err = h.cache.Set(key, mesg)
|
||||
|
||||
if err != nil {
|
||||
Debug("Set %s cache failed: %s", Q.String(), err.Error())
|
||||
}
|
||||
|
||||
Debug("Insert %s into cache", Q.String())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (h *GODNSHandler) DoTCP(w dns.ResponseWriter, req *dns.Msg) {
|
||||
|
@ -60,13 +115,3 @@ func (h *GODNSHandler) DoTCP(w dns.ResponseWriter, req *dns.Msg) {
|
|||
func (h *GODNSHandler) DoUDP(w dns.ResponseWriter, req *dns.Msg) {
|
||||
h.do("udp", w, req)
|
||||
}
|
||||
|
||||
type Question struct {
|
||||
qname string
|
||||
qtype string
|
||||
qclass string
|
||||
}
|
||||
|
||||
func (q *Question) String() string {
|
||||
return q.qname + " " + q.qclass + " " + q.qtype
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ type LogSettings struct {
|
|||
type CacheSettings struct {
|
||||
Backend string
|
||||
Expire time.Duration
|
||||
Maxcount uint32
|
||||
Maxcount int
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
Loading…
Reference in New Issue