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
|
* Cache records save in memory or redis configurable
|
||||||
|
|
||||||
|
|
||||||
### Configuration
|
## Install & Running
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
All the configuration on `godns.conf` a TOML formating config file.
|
All the configuration on `godns.conf` a TOML formating config file.
|
||||||
More about Toml :[https://github.com/mojombo/toml](https://github.com/mojombo/toml)
|
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
|
package main
|
||||||
|
|
||||||
type Cache struct {
|
import (
|
||||||
config CacheSettings
|
"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 (
|
import (
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
// "log"
|
// "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 {
|
type GODNSHandler struct {
|
||||||
resolver *Resolver
|
resolver *Resolver
|
||||||
cache *Cache
|
cache Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler() *GODNSHandler {
|
func NewHandler() *GODNSHandler {
|
||||||
|
@ -16,6 +26,8 @@ func NewHandler() *GODNSHandler {
|
||||||
var (
|
var (
|
||||||
clientConfig *dns.ClientConfig
|
clientConfig *dns.ClientConfig
|
||||||
cacheConfig CacheSettings
|
cacheConfig CacheSettings
|
||||||
|
resolver *Resolver
|
||||||
|
cache Cache
|
||||||
)
|
)
|
||||||
|
|
||||||
resolvConfig := settings.ResolvConfig
|
resolvConfig := settings.ResolvConfig
|
||||||
|
@ -26,11 +38,28 @@ func NewHandler() *GODNSHandler {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
clientConfig.Timeout = resolvConfig.Timeout
|
clientConfig.Timeout = resolvConfig.Timeout
|
||||||
resolver := &Resolver{clientConfig}
|
resolver = &Resolver{clientConfig}
|
||||||
|
|
||||||
cacheConfig = settings.Cache
|
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}
|
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())
|
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)
|
mesg, err := h.resolver.Lookup(net, req)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -51,6 +96,16 @@ func (h *GODNSHandler) do(net string, w dns.ResponseWriter, req *dns.Msg) {
|
||||||
|
|
||||||
w.WriteMsg(mesg)
|
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) {
|
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) {
|
func (h *GODNSHandler) DoUDP(w dns.ResponseWriter, req *dns.Msg) {
|
||||||
h.do("udp", w, req)
|
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 {
|
type CacheSettings struct {
|
||||||
Backend string
|
Backend string
|
||||||
Expire time.Duration
|
Expire time.Duration
|
||||||
Maxcount uint32
|
Maxcount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
Loading…
Reference in New Issue