godns/handler.go

196 lines
4.5 KiB
Go
Raw Normal View History

2013-07-23 11:10:38 +00:00
package main
import (
2020-01-25 17:43:02 +00:00
"crypto/md5"
"fmt"
"meow.tf/joker/godns/cache"
"meow.tf/joker/godns/hosts"
"meow.tf/joker/godns/log"
"meow.tf/joker/godns/resolver"
"meow.tf/joker/godns/settings"
"meow.tf/joker/godns/utils"
2015-10-13 17:00:28 +00:00
"net"
2013-07-24 16:09:07 +00:00
"time"
2015-02-03 12:32:18 +00:00
"github.com/miekg/dns"
2013-07-23 11:10:38 +00:00
)
2015-02-03 12:32:18 +00:00
const (
notIPQuery = 0
_IP4Query = 4
_IP6Query = 6
)
2013-07-23 11:10:38 +00:00
type GODNSHandler struct {
2020-01-25 17:43:02 +00:00
resolver *resolver.Resolver
cache, negCache cache.Cache
hosts hosts.Hosts
2013-07-23 11:10:38 +00:00
}
func NewHandler() *GODNSHandler {
var (
2020-01-25 17:43:02 +00:00
cacheConfig settings.CacheSettings
r *resolver.Resolver
resolverCache, negCache cache.Cache
2013-07-23 11:10:38 +00:00
)
2020-01-25 17:43:02 +00:00
r = resolver.NewResolver(settings.Resolver())
2013-07-23 11:10:38 +00:00
2020-01-25 17:43:02 +00:00
cacheConfig = settings.Cache()
2013-07-24 10:29:38 +00:00
switch cacheConfig.Backend {
case "memory":
2020-01-25 17:43:02 +00:00
cacheDuration := time.Duration(cacheConfig.Expire) * time.Second
negCache = cache.NewMemoryCache(cacheDuration/2, cacheConfig.Maxcount)
resolverCache = cache.NewMemoryCache(time.Duration(cacheConfig.Expire)*time.Second, cacheConfig.Maxcount)
case "memcache":
2020-01-25 17:43:02 +00:00
resolverCache = cache.NewMemcachedCache(
settings.Memcache().Servers,
int32(cacheConfig.Expire))
2020-01-25 17:43:02 +00:00
negCache = cache.NewMemcachedCache(
settings.Memcache().Servers,
int32(cacheConfig.Expire/2))
2013-07-24 10:29:38 +00:00
case "redis":
2020-01-25 17:43:02 +00:00
resolverCache = cache.NewRedisCache(
settings.Redis(),
2018-07-01 15:49:24 +00:00
int32(cacheConfig.Expire))
2020-01-25 17:43:02 +00:00
negCache = cache.NewRedisCache(
settings.Redis(),
2018-07-01 15:49:24 +00:00
int32(cacheConfig.Expire/2))
2013-07-24 10:29:38 +00:00
default:
2020-01-25 17:43:02 +00:00
log.Error("Invalid cache backend %s", cacheConfig.Backend)
2013-07-24 10:29:38 +00:00
panic("Invalid cache backend")
}
2013-07-26 10:54:19 +00:00
2020-01-25 17:43:02 +00:00
h := hosts.NewHosts(settings.Hosts(), settings.Redis())
2013-07-26 10:54:19 +00:00
2020-01-25 17:43:02 +00:00
return &GODNSHandler{r, resolverCache, negCache, h}
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]
2020-01-25 17:43:02 +00:00
question := resolver.Question{Name: utils.UnFqdn(q.Name), Type: dns.TypeToString[q.Qtype], Class: dns.ClassToString[q.Qclass]}
2013-07-23 11:10:38 +00:00
2015-10-13 17:00:28 +00:00
var remote net.IP
if Net == "tcp" {
remote = w.RemoteAddr().(*net.TCPAddr).IP
} else {
remote = w.RemoteAddr().(*net.UDPAddr).IP
}
2020-01-25 17:43:02 +00:00
log.Info("%s lookup %s", remote, question.String())
2013-07-23 11:10:38 +00:00
2015-02-03 12:32:18 +00:00
IPQuery := h.isIPQuery(q)
2013-07-26 10:54:19 +00:00
// Query hosts
2020-01-25 17:43:02 +00:00
if h.hosts != nil && IPQuery > 0 {
if ips, ok := h.hosts.Get(question.Name, IPQuery); ok {
2013-07-26 10:54:19 +00:00
m := new(dns.Msg)
m.SetReply(req)
2015-02-03 12:32:18 +00:00
switch IPQuery {
case _IP4Query:
2020-01-25 17:43:02 +00:00
hdr := dns.RR_Header{
2015-02-03 12:32:18 +00:00
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
2020-01-25 17:43:02 +00:00
Ttl: h.hosts.TTL(),
2015-02-03 12:32:18 +00:00
}
2015-10-14 17:08:25 +00:00
for _, ip := range ips {
2020-01-25 17:43:02 +00:00
m.Answer = append(m.Answer, &dns.A{Hdr: hdr, A: ip})
2015-10-14 17:08:25 +00:00
}
2015-02-03 12:32:18 +00:00
case _IP6Query:
2020-01-25 17:43:02 +00:00
hdr := dns.RR_Header{
2015-02-03 12:32:18 +00:00
Name: q.Name,
Rrtype: dns.TypeAAAA,
Class: dns.ClassINET,
2020-01-25 17:43:02 +00:00
Ttl: h.hosts.TTL(),
2015-02-03 12:32:18 +00:00
}
2015-10-14 17:08:25 +00:00
for _, ip := range ips {
2020-01-25 17:43:02 +00:00
m.Answer = append(m.Answer, &dns.AAAA{Hdr: hdr, AAAA: ip})
2015-10-14 17:08:25 +00:00
}
2015-02-03 12:32:18 +00:00
}
2013-07-26 10:54:19 +00:00
w.WriteMsg(m)
2020-01-25 17:43:02 +00:00
log.Debug("%s found in hosts file", question.Name)
2013-07-26 10:54:19 +00:00
return
2015-02-04 06:37:48 +00:00
} else {
2020-01-25 17:43:02 +00:00
log.Debug("%s didn't found in hosts file", question.Name)
2013-07-26 10:54:19 +00:00
}
}
2015-02-11 09:11:32 +00:00
// Only query cache when qtype == 'A'|'AAAA' , qclass == 'IN'
2020-01-25 17:43:02 +00:00
key := KeyGen(question)
2015-02-03 12:32:18 +00:00
if IPQuery > 0 {
2013-07-24 10:29:38 +00:00
mesg, err := h.cache.Get(key)
if err != nil {
if mesg, err = h.negCache.Get(key); err != nil {
2020-01-25 17:43:02 +00:00
log.Debug("%s didn't hit cache", question.String())
} else {
2020-01-25 17:43:02 +00:00
log.Debug("%s hit negative cache", question.String())
dns.HandleFailed(w, req)
return
}
2013-07-24 10:29:38 +00:00
} else {
2020-01-25 17:43:02 +00:00
log.Debug("%s hit cache", question.String())
// we need this copy against concurrent modification of Id
msg := *mesg
msg.Id = req.Id
w.WriteMsg(&msg)
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 {
2020-01-25 17:43:02 +00:00
log.Warn("Resolve query error %s", err)
2013-07-24 02:52:59 +00:00
dns.HandleFailed(w, req)
// cache the failure, too!
if err = h.negCache.Set(key, nil); err != nil {
2020-01-25 17:43:02 +00:00
log.Warn("Set %s negative cache failed: %v", question.String(), err)
}
2013-07-24 02:52:59 +00:00
return
}
w.WriteMsg(mesg)
2015-02-03 15:20:36 +00:00
if IPQuery > 0 && len(mesg.Answer) > 0 {
2013-07-24 10:29:38 +00:00
err = h.cache.Set(key, mesg)
if err != nil {
2020-01-25 17:43:02 +00:00
log.Warn("Set %s cache failed: %s", question.String(), err.Error())
2013-07-24 10:29:38 +00:00
}
2020-01-25 17:43:02 +00:00
log.Debug("Insert %s into cache", question.String())
2013-07-24 10:29:38 +00:00
}
2013-07-23 11:10:38 +00:00
}
2020-01-25 17:43:02 +00:00
func (h *GODNSHandler) Bind(net string) func(w dns.ResponseWriter, req *dns.Msg) {
return func(w dns.ResponseWriter, req *dns.Msg) {
h.do(net, w, req)
}
2013-07-23 11:10:38 +00:00
}
2013-07-26 04:06:16 +00:00
2015-02-03 12:32:18 +00:00
func (h *GODNSHandler) isIPQuery(q dns.Question) int {
if q.Qclass != dns.ClassINET {
return notIPQuery
}
switch q.Qtype {
case dns.TypeA:
return _IP4Query
case dns.TypeAAAA:
return _IP6Query
default:
return notIPQuery
}
2013-07-26 04:06:16 +00:00
}
2013-07-26 10:54:19 +00:00
2020-01-25 17:43:02 +00:00
func KeyGen(q resolver.Question) string {
h := md5.New()
h.Write([]byte(q.String()))
x := h.Sum(nil)
key := fmt.Sprintf("%x", x)
return key
2013-07-26 10:54:19 +00:00
}