godns/handler.go

151 lines
3.2 KiB
Go
Raw Normal View History

2013-07-23 11:10:38 +00:00
package main
import (
"github.com/miekg/dns"
2013-07-26 10:54:19 +00:00
"net"
2013-12-12 12:31:26 +00:00
"sync"
2013-07-24 16:09:07 +00:00
"time"
2013-07-23 11:10:38 +00:00
)
2013-07-24 10:29:38 +00:00
type Question struct {
qname string
qtype string
qclass string
}
func (q *Question) String() string {
return q.qname + " " + q.qclass + " " + q.qtype
}
2013-07-23 11:10:38 +00:00
type GODNSHandler struct {
resolver *Resolver
2013-07-24 10:29:38 +00:00
cache Cache
2013-07-26 10:54:19 +00:00
hosts Hosts
2013-12-12 12:31:26 +00:00
mu *sync.Mutex
2013-07-23 11:10:38 +00:00
}
func NewHandler() *GODNSHandler {
var (
clientConfig *dns.ClientConfig
cacheConfig CacheSettings
2013-07-24 10:29:38 +00:00
resolver *Resolver
cache Cache
2013-07-23 11:10:38 +00:00
)
resolvConfig := settings.ResolvConfig
clientConfig, err := dns.ClientConfigFromFile(resolvConfig.ResolvFile)
if err != nil {
logger.Printf(":%s is not a valid resolv.conf file\n", resolvConfig.ResolvFile)
logger.Println(err)
panic(err)
}
clientConfig.Timeout = resolvConfig.Timeout
2013-07-24 10:29:38 +00:00
resolver = &Resolver{clientConfig}
2013-07-23 11:10:38 +00:00
cacheConfig = settings.Cache
2013-07-24 10:29:38 +00:00
switch cacheConfig.Backend {
case "memory":
cache = &MemoryCache{
2013-07-24 16:09:07 +00:00
Backend: make(map[string]Mesg),
Expire: time.Duration(cacheConfig.Expire) * time.Second,
Maxcount: cacheConfig.Maxcount,
2013-12-12 12:31:26 +00:00
mu: new(sync.RWMutex),
2013-07-24 10:29:38 +00:00
}
case "redis":
2013-07-24 14:40:18 +00:00
// cache = &MemoryCache{
2013-07-24 16:09:07 +00:00
// Backend: make(map[string]*dns.Msg),
// Expire: time.Duration(cacheConfig.Expire) * time.Second,
// Serializer: new(JsonSerializer),
// Maxcount: cacheConfig.Maxcount,
2013-07-24 14:40:18 +00:00
// }
panic("Redis cache backend not implement yet")
2013-07-24 10:29:38 +00:00
default:
logger.Printf("Invalid cache backend %s", cacheConfig.Backend)
panic("Invalid cache backend")
}
2013-07-26 10:54:19 +00:00
hosts := NewHosts(settings.Hosts, settings.Redis)
2013-12-12 12:31:26 +00:00
return &GODNSHandler{resolver, cache, hosts, new(sync.Mutex)}
2013-07-23 11:10:38 +00:00
}
2013-07-26 10:54:19 +00:00
func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) {
2013-07-23 16:37:38 +00:00
q := req.Question[0]
2013-07-26 10:54:19 +00:00
Q := Question{UnFqdn(q.Name), dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass]}
2013-07-23 11:10:38 +00:00
2013-07-23 16:37:38 +00:00
Debug("Question: %s", Q.String())
2013-07-23 11:10:38 +00:00
2013-07-26 10:54:19 +00:00
// Query hosts
if settings.Hosts.Enable && h.isIPQuery(q) {
if ip, ok := h.hosts.Get(Q.qname); ok {
m := new(dns.Msg)
m.SetReply(req)
rr_header := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: settings.Hosts.TTL}
a := &dns.A{rr_header, net.ParseIP(ip)}
m.Answer = append(m.Answer, a)
w.WriteMsg(m)
Debug("%s found in hosts", Q.qname)
return
}
}
2013-07-24 10:29:38 +00:00
// Only query cache when qtype == 'A' , qclass == 'IN'
2013-07-26 10:54:19 +00:00
key := KeyGen(Q)
2013-07-26 04:06:16 +00:00
if h.isIPQuery(q) {
2013-07-24 10:29:38 +00:00
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())
2013-12-12 12:31:26 +00:00
h.mu.Lock()
mesg.Id = req.Id
2013-07-24 10:48:43 +00:00
w.WriteMsg(mesg)
2013-12-12 12:31:26 +00:00
h.mu.Unlock()
2013-07-24 10:29:38 +00:00
return
}
}
2013-07-26 10:54:19 +00:00
mesg, err := h.resolver.Lookup(Net, req)
2013-07-23 11:10:38 +00:00
2013-07-24 02:52:59 +00:00
if err != nil {
Debug("%s", err)
dns.HandleFailed(w, req)
return
}
w.WriteMsg(mesg)
2013-07-26 04:06:16 +00:00
if h.isIPQuery(q) {
2013-07-24 10:29:38 +00:00
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())
}
2013-07-23 11:10:38 +00:00
}
func (h *GODNSHandler) DoTCP(w dns.ResponseWriter, req *dns.Msg) {
h.do("tcp", w, req)
}
func (h *GODNSHandler) DoUDP(w dns.ResponseWriter, req *dns.Msg) {
h.do("udp", w, req)
}
2013-07-26 04:06:16 +00:00
func (h *GODNSHandler) isIPQuery(q dns.Question) bool {
return q.Qtype == dns.TypeA && q.Qclass == dns.ClassINET
}
2013-07-26 10:54:19 +00:00
func UnFqdn(s string) string {
if dns.IsFqdn(s) {
return s[:len(s)-1]
}
return s
}