first commit
This commit is contained in:
commit
5349b53416
|
@ -0,0 +1,16 @@
|
||||||
|
GODNS
|
||||||
|
====
|
||||||
|
|
||||||
|
A tiny dns cache server written by go.
|
||||||
|
|
||||||
|
|
||||||
|
Similar as [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) ,but support some difference features:
|
||||||
|
|
||||||
|
|
||||||
|
* Keep hosts configuration in redis instead of local file /etc/hosts
|
||||||
|
So can be updated from remote server
|
||||||
|
|
||||||
|
* Atuo-Reload when hosts configuration changed. (Yes,dnsmasq need restart)
|
||||||
|
|
||||||
|
* Cache records save in memory or redis configurable
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Cache struct {
|
||||||
|
config CacheSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) Get() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) Set() {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#Toml config file
|
||||||
|
|
||||||
|
|
||||||
|
Title = "GODNS"
|
||||||
|
Version = "0.1.1"
|
||||||
|
Author = "kenshin"
|
||||||
|
|
||||||
|
Debug = true
|
||||||
|
|
||||||
|
[server]
|
||||||
|
host = "127.0.0.1"
|
||||||
|
port = 53
|
||||||
|
|
||||||
|
[resolv]
|
||||||
|
resolv-file = "/etc/resolv.conf"
|
||||||
|
timeout = 30 # 30 seconds
|
||||||
|
|
||||||
|
[redis]
|
||||||
|
host = "kenshinx.me"
|
||||||
|
port = 6379
|
||||||
|
db = 0
|
||||||
|
password =""
|
||||||
|
|
||||||
|
[log]
|
||||||
|
#If didn't set the log file,log will be redirected to console.
|
||||||
|
file = ""
|
||||||
|
|
||||||
|
|
||||||
|
[cache]
|
||||||
|
# backend option [memory|redis]
|
||||||
|
backend = "memory"
|
||||||
|
expire = 600 # 10 minutes
|
||||||
|
maxcount = 100000
|
|
@ -0,0 +1,54 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
// "log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GODNSHandler struct {
|
||||||
|
resolver *Resolver
|
||||||
|
cache *Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler() *GODNSHandler {
|
||||||
|
|
||||||
|
var (
|
||||||
|
clientConfig *dns.ClientConfig
|
||||||
|
cacheConfig CacheSettings
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
resolver := &Resolver{clientConfig}
|
||||||
|
|
||||||
|
cacheConfig = settings.Cache
|
||||||
|
cache := &Cache{cacheConfig}
|
||||||
|
|
||||||
|
return &GODNSHandler{resolver, cache}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *GODNSHandler) do(net string, w dns.ResponseWriter, req *dns.Msg) {
|
||||||
|
|
||||||
|
qname := req.Question[0].Name
|
||||||
|
qtype := req.Question[0].Qtype
|
||||||
|
qclass := req.Question[0].Qclass
|
||||||
|
|
||||||
|
Debug("Question: %s %s %s", qname, dns.ClassToString[qclass], dns.TypeToString[qtype])
|
||||||
|
|
||||||
|
h.resolver.Lookup(net, req)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
logger *log.Logger
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
logger = initLogger(settings.Log.File)
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
host: settings.Server.Host,
|
||||||
|
port: settings.Server.Port,
|
||||||
|
rTimeout: 5 * time.Second,
|
||||||
|
wTimeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
server.Run()
|
||||||
|
|
||||||
|
sig := make(chan os.Signal)
|
||||||
|
signal.Notify(sig, os.Interrupt)
|
||||||
|
|
||||||
|
forever:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-sig:
|
||||||
|
logger.Printf("signal received, stopping")
|
||||||
|
break forever
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Debug(format string, v ...interface{}) {
|
||||||
|
if settings.Debug {
|
||||||
|
logger.Printf(format, v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initLogger(log_file string) (logger *log.Logger) {
|
||||||
|
if log_file != "" {
|
||||||
|
f, err := os.Create(log_file)
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
logger = log.New(f, "[godns]", log.Ldate|log.Ltime)
|
||||||
|
} else {
|
||||||
|
logger = log.New(os.Stdout, "[godns]", log.Ldate|log.Ltime)
|
||||||
|
}
|
||||||
|
return logger
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Resolver struct {
|
||||||
|
config *dns.ClientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) Lookup(net string, req *dns.Msg) {
|
||||||
|
c := &dns.Client{
|
||||||
|
Net: net,
|
||||||
|
ReadTimeout: r.Timeout(),
|
||||||
|
WriteTimeout: r.Timeout(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, nameserver := range r.Nameservers() {
|
||||||
|
r, rtt, _ := c.Exchange(req, nameserver)
|
||||||
|
fmt.Println(r)
|
||||||
|
fmt.Println(rtt)
|
||||||
|
|
||||||
|
}
|
||||||
|
// r,rtt,_:c.Exchange(req, a)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) Nameservers() (ns []string) {
|
||||||
|
for _, server := range r.config.Servers {
|
||||||
|
nameserver := server + ":" + r.config.Port
|
||||||
|
ns = append(ns, nameserver)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) Timeout() time.Duration {
|
||||||
|
return time.Duration(r.config.Timeout) * time.Second
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
host string
|
||||||
|
port int
|
||||||
|
rTimeout time.Duration
|
||||||
|
wTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Addr() string {
|
||||||
|
return s.host + ":" + strconv.Itoa(s.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Run() {
|
||||||
|
|
||||||
|
Handler := NewHandler()
|
||||||
|
|
||||||
|
tcpHandler := dns.NewServeMux()
|
||||||
|
tcpHandler.HandleFunc(".", Handler.DoTCP)
|
||||||
|
|
||||||
|
udpHandler := dns.NewServeMux()
|
||||||
|
udpHandler.HandleFunc(".", Handler.DoUDP)
|
||||||
|
|
||||||
|
tcpServer := &dns.Server{Addr: s.Addr(),
|
||||||
|
Net: "tcp",
|
||||||
|
Handler: tcpHandler,
|
||||||
|
ReadTimeout: s.rTimeout,
|
||||||
|
WriteTimeout: s.wTimeout}
|
||||||
|
|
||||||
|
udpServer := &dns.Server{Addr: s.Addr(),
|
||||||
|
Net: "udp",
|
||||||
|
Handler: udpHandler,
|
||||||
|
UDPSize: 65535,
|
||||||
|
ReadTimeout: s.rTimeout,
|
||||||
|
WriteTimeout: s.wTimeout}
|
||||||
|
|
||||||
|
go s.start(udpServer)
|
||||||
|
go s.start(tcpServer)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) start(ds *dns.Server) {
|
||||||
|
|
||||||
|
logger.Printf("Start %s listener on %s\n", ds.Net, s.Addr())
|
||||||
|
err := ds.ListenAndServe()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("Start %s listener on %s failed:%s", ds.Net, s.Addr(), err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
settings Settings
|
||||||
|
)
|
||||||
|
|
||||||
|
type Settings struct {
|
||||||
|
Version string
|
||||||
|
Debug bool
|
||||||
|
Server DNSServerSettings `toml:"server"`
|
||||||
|
ResolvConfig ResolvSettings `toml:"resolv"`
|
||||||
|
Redis RedisSettings `toml:"redis"`
|
||||||
|
Log LogSettings `toml:"log"`
|
||||||
|
Cache CacheSettings `toml:"cache"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResolvSettings struct {
|
||||||
|
ResolvFile string `toml:"resolv-file"`
|
||||||
|
Timeout int
|
||||||
|
}
|
||||||
|
|
||||||
|
type DNSServerSettings struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
type RedisSettings struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
DB int
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogSettings struct {
|
||||||
|
File string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CacheSettings struct {
|
||||||
|
Backend string
|
||||||
|
Expire time.Duration
|
||||||
|
Maxcount uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
var configFile string
|
||||||
|
|
||||||
|
flag.StringVar(&configFile, "c", "godns.conf", "Look for godns toml-formatting config file in this directory")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if _, err := toml.DecodeFile(configFile, &settings); err != nil {
|
||||||
|
fmt.Printf("%s is not a valid toml config file\n", configFile)
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue