first commit
This commit is contained in:
		
							
								
								
									
										16
									
								
								README.MD
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								README.MD
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								cache.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								cache.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | package main | ||||||
|  |  | ||||||
|  | type Cache struct { | ||||||
|  | 	config CacheSettings | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *Cache) Get() { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *Cache) Set() { | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								godns.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								godns.conf
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										54
									
								
								handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								handler.go
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								resolver.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								resolver.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								server.go
									
									
									
									
									
										Normal file
									
								
							| @ -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()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								settings.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								settings.go
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user