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