From f726a5d5ae6ec489c7086edb5787ba1c68ecbacd Mon Sep 17 00:00:00 2001 From: Tyler Date: Sat, 25 Jan 2020 13:48:26 -0500 Subject: [PATCH] Redo settings a bit, move a lot of init logic to main.go --- cache/cache_redis.go | 6 ++-- etc/apple.china.conf | 46 ------------------------- etc/godns.conf | 64 +++++++++++++++------------------- etc/google.china.conf | 42 ----------------------- handler.go | 59 ++++++------------------------- hosts/hosts.go | 70 ++++++++----------------------------- hosts/hosts_file.go | 17 +++++---- hosts/hosts_redis.go | 72 ++++++++------------------------------ main.go | 80 ++++++++++++++++++++++++++++++++++--------- resolver/resolver.go | 7 +--- server.go | 11 ++---- settings/settings.go | 72 +++----------------------------------- 12 files changed, 152 insertions(+), 394 deletions(-) delete mode 100644 etc/apple.china.conf delete mode 100644 etc/google.china.conf diff --git a/cache/cache_redis.go b/cache/cache_redis.go index b3eb57a..aceed02 100644 --- a/cache/cache_redis.go +++ b/cache/cache_redis.go @@ -7,7 +7,7 @@ import ( "time" ) -func NewRedisCache(c settings.RedisSettings, expire int32) *RedisCache { +func NewRedisCache(c settings.RedisSettings, expire time.Duration) *RedisCache { rc := redis.NewClient(&redis.Options{Addr: c.Addr(), DB: c.DB, Password: c.Password}) return &RedisCache{ @@ -20,7 +20,7 @@ type RedisCache struct { Cache backend *redis.Client - expire int32 + expire time.Duration } func (m *RedisCache) Set(key string, msg *dns.Msg) error { @@ -38,7 +38,7 @@ func (m *RedisCache) Set(key string, msg *dns.Msg) error { if err != nil { err = SerializerError{err} } - return m.backend.Set(key, val, time.Duration(m.expire) * time.Second).Err() + return m.backend.Set(key, val, m.expire).Err() } func (m *RedisCache) Get(key string) (*dns.Msg, error) { diff --git a/etc/apple.china.conf b/etc/apple.china.conf deleted file mode 100644 index 820bf08..0000000 --- a/etc/apple.china.conf +++ /dev/null @@ -1,46 +0,0 @@ -server=/adcdownload.apple.com/114.114.114.114 -server=/appldnld.apple.com/114.114.114.114 -server=/cdn-cn1.apple-mapkit.com/114.114.114.114 -server=/cdn-cn2.apple-mapkit.com/114.114.114.114 -server=/cdn-cn3.apple-mapkit.com/114.114.114.114 -server=/cdn-cn4.apple-mapkit.com/114.114.114.114 -server=/cdn.apple-mapkit.com/114.114.114.114 -server=/cdn1.apple-mapkit.com/114.114.114.114 -server=/cdn2.apple-mapkit.com/114.114.114.114 -server=/cdn3.apple-mapkit.com/114.114.114.114 -server=/cdn4.apple-mapkit.com/114.114.114.114 -server=/cds.apple.com/114.114.114.114 -server=/cl1.apple.com/114.114.114.114 -server=/cl2.apple.com.edgekey.net.globalredir.akadns.net/114.114.114.114 -server=/cl2.apple.com.edgekey.net/114.114.114.114 -server=/cl2.apple.com/114.114.114.114 -server=/cl3.apple.com/114.114.114.114 -server=/cl4.apple.com/114.114.114.114 -server=/cl5.apple.com/114.114.114.114 -server=/gsp11-cn.ls.apple.com/114.114.114.114 -server=/gsp12-cn.ls.apple.com/114.114.114.114 -server=/gsp13-cn.ls.apple.com/114.114.114.114 -server=/gsp4-cn.ls.apple.com.edgekey.net.globalredir.akadns.net/114.114.114.114 -server=/gsp4-cn.ls.apple.com.edgekey.net/114.114.114.114 -server=/gsp4-cn.ls.apple.com/114.114.114.114 -server=/gsp5-cn.ls.apple.com/114.114.114.114 -server=/gspe19-cn.ls-apple.com.akadns.net/114.114.114.114 -server=/gspe19-cn.ls.apple.com/114.114.114.114 -server=/gspe21.ls.apple.com/114.114.114.114 -server=/gspe21-ssl.ls.apple.com/114.114.114.114 -server=/gspe35-ssl.ls.apple.com/114.114.114.114 -server=/icloud.cdn-apple.com/114.114.114.114 -server=/images.apple.com/114.114.114.114 -server=/itunes-apple.com.akadns.net/114.114.114.114 -server=/itunes.apple.com/114.114.114.114 -server=/itunesconnect.apple.com/114.114.114.114 -server=/mesu.apple.com/114.114.114.114 -server=/mesu-china.apple.com.akadns.net/114.114.114.114 -server=/phobos-apple.com.akadns.net/114.114.114.114 -server=/phobos.apple.com/114.114.114.114 -server=/store.apple.com/114.114.114.114 -server=/store.storeimages.cdn-apple.com/114.114.114.114 -server=/support.apple.com/114.114.114.114 -server=/swcdn.apple.com/114.114.114.114 -server=/swdist.apple.com/114.114.114.114 -server=/www.apple.com/114.114.114.114 diff --git a/etc/godns.conf b/etc/godns.conf index d75abea..2ba16bb 100644 --- a/etc/godns.conf +++ b/etc/godns.conf @@ -1,58 +1,48 @@ #Toml config file - - -Title = "GODNS" -Version = "0.2.0" -Author = "kenshin, tystuyfzand" - -Debug = false +debug = false [server] host = "0.0.0.0" nets = ["tcp:53", "udp:53"] [resolv] -# Domain-specific nameservers configuration, formatting keep compatible with Dnsmasq -# Semicolon separate multiple files. -resolv-file = "" +file = "" timeout = 5 # 5 seconds -# The concurrency interval request upstream recursive server -# Match the PR15, https://github.com/kenshinx/godns/pull/15 interval = 200 # 200 milliseconds -setedns0 = false #Support for larger UDP DNS responses -server-list-file = "etc/serverlist.conf" - -[redis] -enable = true -host = "192.168.1.71" -port = 6379 -db = 0 -password ="" - -[memcache] -servers = ["127.0.0.1:11211"] +edns0 = false #Support for larger UDP DNS responses +# Domain-specific nameservers configuration, formatting keep compatible with Dnsmasq +server-list = "etc/serverlist.conf" [log] stdout = true file = "./godns.log" level = "DEBUG" #DEBUG | INFO |NOTICE | WARN | ERROR - - [cache] -# backend option [memory|memcache|redis] -# redis backend not implemented yet -backend = "memory" +# backend option [memory|memcache|redis] +backend = "memory" expire = 600 # 10 minutes maxcount = 0 #If set zero. The Sum of cache itmes will be unlimit. + [cache.memcached] + servers = ["127.0.0.1:11211"] + + # Redis cache backend config + [cache.redis] + host = "192.168.1.71" + port = 6379 + db = 0 + password ="" + [hosts] -#If set false, will not query hosts file and redis hosts record -enable = true -host-file = "/etc/hosts" -redis-enable = true -redis-key = "godns:hosts" -ttl = 600 -refresh-interval = 60 # 5 seconds - + # File provider, supports inotify hot-reload + [hosts.file] + enable = true + file = "/etc/hosts" + ttl = 600 + # Redis provider + [hosts.redis] + enable = true + key = "godns:hosts" + ttl = 600 \ No newline at end of file diff --git a/etc/google.china.conf b/etc/google.china.conf deleted file mode 100644 index 0928c70..0000000 --- a/etc/google.china.conf +++ /dev/null @@ -1,42 +0,0 @@ -server=/265.com/114.114.114.114 -server=/2mdn.net/114.114.114.114 -server=/app-measurement.com/114.114.114.114 -server=/beacons.gcp.gvt2.com/114.114.114.114 -server=/beacons.gvt2.com/114.114.114.114 -server=/beacons3.gvt2.com/114.114.114.114 -server=/c.admob.com/114.114.114.114 -server=/c.android.clients.google.com/114.114.114.114 -server=/cache.pack.google.com/114.114.114.114 -server=/clientservices.googleapis.com/114.114.114.114 -server=/connectivitycheck.gstatic.com/114.114.114.114 -server=/csi.gstatic.com/114.114.114.114 -server=/dl.google.com/114.114.114.114 -server=/doubleclick.net/114.114.114.114 -server=/e.admob.com/114.114.114.114 -server=/fonts.googleapis.com/114.114.114.114 -server=/fonts.gstatic.com/114.114.114.114 -server=/google-analytics.com/114.114.114.114 -server=/googleadservices.com/114.114.114.114 -server=/googleanalytics.com/114.114.114.114 -server=/googlesyndication.com/114.114.114.114 -server=/googletagmanager.com/114.114.114.114 -server=/googletagservices.com/114.114.114.114 -server=/imasdk.googleapis.com/114.114.114.114 -server=/kh.google.com/114.114.114.114 -server=/khm.google.com/114.114.114.114 -server=/khm.googleapis.com/114.114.114.114 -server=/khm0.google.com/114.114.114.114 -server=/khm0.googleapis.com/114.114.114.114 -server=/khm1.google.com/114.114.114.114 -server=/khm1.googleapis.com/114.114.114.114 -server=/khm2.google.com/114.114.114.114 -server=/khm2.googleapis.com/114.114.114.114 -server=/khm3.google.com/114.114.114.114 -server=/khm3.googleapis.com/114.114.114.114 -server=/khmdb.google.com/114.114.114.114 -server=/khmdb.googleapis.com/114.114.114.114 -server=/media.admob.com/114.114.114.114 -server=/mediavisor.doubleclick.com/114.114.114.114 -server=/redirector.gvt1.com/114.114.114.114 -server=/toolbarqueries.google.com/114.114.114.114 -server=/update.googleapis.com/114.114.114.114 diff --git a/handler.go b/handler.go index 7f72983..128b053 100644 --- a/handler.go +++ b/handler.go @@ -3,16 +3,14 @@ package main import ( "crypto/md5" "fmt" + "github.com/miekg/dns" "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" "net" "time" - - "github.com/miekg/dns" ) const ( @@ -21,54 +19,17 @@ const ( _IP6Query = 6 ) -type GODNSHandler struct { +type Handler struct { resolver *resolver.Resolver cache, negCache cache.Cache hosts hosts.Hosts } -func NewHandler() *GODNSHandler { - - var ( - cacheConfig settings.CacheSettings - r *resolver.Resolver - resolverCache, negCache cache.Cache - ) - - r = resolver.NewResolver(settings.Resolver()) - - cacheConfig = settings.Cache() - switch cacheConfig.Backend { - case "memory": - 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": - resolverCache = cache.NewMemcachedCache( - settings.Memcache().Servers, - int32(cacheConfig.Expire)) - negCache = cache.NewMemcachedCache( - settings.Memcache().Servers, - int32(cacheConfig.Expire/2)) - case "redis": - resolverCache = cache.NewRedisCache( - settings.Redis(), - int32(cacheConfig.Expire)) - negCache = cache.NewRedisCache( - settings.Redis(), - int32(cacheConfig.Expire/2)) - default: - log.Error("Invalid cache backend %s", cacheConfig.Backend) - panic("Invalid cache backend") - } - - h := hosts.NewHosts(settings.Hosts(), settings.Redis()) - - return &GODNSHandler{r, resolverCache, negCache, h} +func NewHandler(r *resolver.Resolver, resolverCache, negCache cache.Cache, h hosts.Hosts) *Handler { + return &Handler{r, resolverCache, negCache, h} } -func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { +func (h *Handler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] question := resolver.Question{Name: utils.UnFqdn(q.Name), Type: dns.TypeToString[q.Qtype], Class: dns.ClassToString[q.Qclass]} @@ -84,7 +45,7 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { // Query hosts if h.hosts != nil && IPQuery > 0 { - if ips, ok := h.hosts.Get(question.Name, IPQuery); ok { + if ips, ttl, ok := h.hosts.Get(question.Name, IPQuery); ok { m := new(dns.Msg) m.SetReply(req) @@ -94,7 +55,7 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, - Ttl: h.hosts.TTL(), + Ttl: uint32(ttl / time.Second), } for _, ip := range ips { m.Answer = append(m.Answer, &dns.A{Hdr: hdr, A: ip}) @@ -104,7 +65,7 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, - Ttl: h.hosts.TTL(), + Ttl: uint32(ttl / time.Second), } for _, ip := range ips { m.Answer = append(m.Answer, &dns.AAAA{Hdr: hdr, AAAA: ip}) @@ -165,13 +126,13 @@ func (h *GODNSHandler) do(Net string, w dns.ResponseWriter, req *dns.Msg) { } } -func (h *GODNSHandler) Bind(net string) func(w dns.ResponseWriter, req *dns.Msg) { +func (h *Handler) Bind(net string) func(w dns.ResponseWriter, req *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) { h.do(net, w, req) } } -func (h *GODNSHandler) isIPQuery(q dns.Question) int { +func (h *Handler) isIPQuery(q dns.Question) int { if q.Qclass != dns.ClassINET { return notIPQuery } diff --git a/hosts/hosts.go b/hosts/hosts.go index 748232d..3fdf9ad 100644 --- a/hosts/hosts.go +++ b/hosts/hosts.go @@ -1,12 +1,8 @@ package hosts import ( - "meow.tf/joker/godns/log" - "meow.tf/joker/godns/settings" "net" "time" - - "github.com/hoisie/redis" ) const ( @@ -15,70 +11,38 @@ const ( _IP6Query = 6 ) +var ( + zeroDuration = time.Duration(0) +) + type Hosts interface { - Get(domain string, family int) ([]net.IP, bool) - TTL() uint32 + Get(domain string, family int) ([]net.IP, time.Duration, bool) } type ProviderList struct { - settings settings.HostsSettings - providers []HostProvider - refreshInterval time.Duration + providers []Provider } -type HostProvider interface { - Get(domain string) ([]string, bool) - Refresh() +type Provider interface { + Get(domain string) ([]string, time.Duration, bool) } -func NewHosts(hs settings.HostsSettings, rs settings.RedisSettings) Hosts { - providers := []HostProvider{ - NewFileProvider(hs.HostsFile), - } - - if hs.RedisEnable { - log.Info("Redis is enabled: %s", rs.Addr()) - - rc := &redis.Client{Addr: rs.Addr(), Db: rs.DB, Password: rs.Password} - - providers = append(providers, NewRedisProvider(rc, hs.RedisKey)) - } - - h := &ProviderList{hs, providers, time.Second * time.Duration(hs.RefreshInterval)} - - if h.refreshInterval > 0 { - h.refresh() - } - - return h -} - -func (h *ProviderList) refresh() { - ticker := time.NewTicker(h.refreshInterval) - - go func() { - for { - // Force a refresh every refreshInterval - for _, provider := range h.providers { - provider.Refresh() - } - - <-ticker.C - } - }() +func NewHosts(providers []Provider) Hosts { + return &ProviderList{providers} } /* Match local /etc/hosts file first, remote redis records second */ -func (h *ProviderList) Get(domain string, family int) ([]net.IP, bool) { +func (h *ProviderList) Get(domain string, family int) ([]net.IP, time.Duration, bool) { var sips []string var ok bool var ip net.IP var ips []net.IP + var ttl time.Duration for _, provider := range h.providers { - sips, ok = provider.Get(domain) + sips, ttl, ok = provider.Get(domain) if ok { break @@ -86,7 +50,7 @@ func (h *ProviderList) Get(domain string, family int) ([]net.IP, bool) { } if sips == nil { - return nil, false + return nil, zeroDuration, false } for _, sip := range sips { @@ -103,9 +67,5 @@ func (h *ProviderList) Get(domain string, family int) ([]net.IP, bool) { } } - return ips, ips != nil -} - -func (h *ProviderList) TTL() uint32 { - return h.settings.TTL + return ips, ttl, ips != nil } \ No newline at end of file diff --git a/hosts/hosts_file.go b/hosts/hosts_file.go index 52451c9..ae3454d 100644 --- a/hosts/hosts_file.go +++ b/hosts/hosts_file.go @@ -10,20 +10,23 @@ import ( "regexp" "strings" "sync" + "time" ) type FileHosts struct { - HostProvider + Provider file string hosts map[string]string mu sync.RWMutex + ttl time.Duration } -func NewFileProvider(file string) HostProvider { +func NewFileProvider(file string, ttl time.Duration) Provider { fp := &FileHosts{ file: file, hosts: make(map[string]string), + ttl: ttl, } watcher, err := fsnotify.NewWatcher() @@ -46,7 +49,7 @@ func NewFileProvider(file string) HostProvider { return fp } -func (f *FileHosts) Get(domain string) ([]string, bool) { +func (f *FileHosts) Get(domain string) ([]string, time.Duration, bool) { log.Debug("Checking file provider for %s", domain) f.mu.RLock() @@ -54,24 +57,24 @@ func (f *FileHosts) Get(domain string) ([]string, bool) { domain = strings.ToLower(domain) if ip, ok := f.hosts[domain]; ok { - return strings.Split(ip, ","), true + return strings.Split(ip, ","), f.ttl, true } if idx := strings.Index(domain, "."); idx != -1 { wildcard := "*." + domain[strings.Index(domain, ".") + 1:] if ip, ok := f.hosts[wildcard]; ok { - return strings.Split(ip, ","), true + return strings.Split(ip, ","), f.ttl, true } } for host, ip := range f.hosts { if glob.Glob(host, domain) { - return strings.Split(ip, ","), true + return strings.Split(ip, ","), f.ttl, true } } - return nil, false + return nil, time.Duration(0), false } var ( diff --git a/hosts/hosts_redis.go b/hosts/hosts_redis.go index be86a45..cbf916f 100644 --- a/hosts/hosts_redis.go +++ b/hosts/hosts_redis.go @@ -1,83 +1,39 @@ package hosts import ( - "github.com/hoisie/redis" + "github.com/go-redis/redis/v7" "github.com/ryanuber/go-glob" "meow.tf/joker/godns/log" "strings" "sync" + "time" ) type RedisHosts struct { - HostProvider + Provider redis *redis.Client key string hosts map[string]string mu sync.RWMutex + ttl time.Duration } -func NewRedisProvider(rc *redis.Client, key string) HostProvider { +func NewRedisProvider(rc *redis.Client, key string, ttl time.Duration) Provider { rh := &RedisHosts{ redis: rc, key: key, hosts: make(map[string]string), + ttl: ttl, } // Force an initial refresh rh.Refresh() - // Use pubsub to listen for key update events - go func() { - keyspaceEvent := "__keyspace@0__:" + key - - sub := make(chan string, 3) - sub <- keyspaceEvent - sub <- "godns:update" - sub <- "godns:update_record" - messages := make(chan redis.Message, 0) - go rc.Subscribe(sub, nil, nil, nil, messages) - - for { - msg := <-messages - - if msg.Channel == "godns:update" { - log.Debug("Refreshing redis records due to update") - rh.Refresh() - } else if msg.Channel == "godns:update_record" { - recordName := string(msg.Message) - - b, err := rc.Hget(key, recordName) - - if err != nil { - log.Warn("Record %s does not exist, but was updated", recordName) - continue - } - - log.Debug("Record %s was updated to %s", recordName, string(b)) - - rh.mu.Lock() - rh.hosts[recordName] = string(b) - rh.mu.Unlock() - } else if msg.Channel == "godns:remove_record" { - log.Debug("Record %s was removed", msg.Message) - - recordName := string(msg.Message) - - rh.mu.Lock() - delete(rh.hosts, recordName) - rh.mu.Unlock() - } else if msg.Channel == keyspaceEvent { - log.Debug("Refreshing redis records due to update") - rh.Refresh() - } - } - }() - return rh } -func (r *RedisHosts) Get(domain string) ([]string, bool) { +func (r *RedisHosts) Get(domain string) ([]string, time.Duration, bool) { log.Debug("Checking redis provider for %s", domain) r.mu.RLock() @@ -86,37 +42,39 @@ func (r *RedisHosts) Get(domain string) ([]string, bool) { domain = strings.ToLower(domain) if ip, ok := r.hosts[domain]; ok { - return strings.Split(ip, ","), true + return strings.Split(ip, ","), r.ttl, true } if idx := strings.Index(domain, "."); idx != -1 { wildcard := "*." + domain[strings.Index(domain, ".")+1:] if ip, ok := r.hosts[wildcard]; ok { - return strings.Split(ip, ","), true + return strings.Split(ip, ","), r.ttl, true } } for host, ip := range r.hosts { if glob.Glob(host, domain) { - return strings.Split(ip, ","), true + return strings.Split(ip, ","), r.ttl, true } } - return nil, false + return nil, time.Duration(0), false } func (r *RedisHosts) Set(domain, ip string) (bool, error) { r.mu.Lock() defer r.mu.Unlock() - return r.redis.Hset(r.key, strings.ToLower(domain), []byte(ip)) + return r.redis.HSet(r.key, strings.ToLower(domain), []byte(ip)).Result() } func (r *RedisHosts) Refresh() { r.mu.Lock() defer r.mu.Unlock() r.clear() - err := r.redis.Hgetall(r.key, r.hosts) + + var err error + r.hosts, err = r.redis.HGetAll(r.key).Result() if err != nil { log.Warn("Update hosts records from redis failed %s", err) } else { diff --git a/main.go b/main.go index a64e63c..5119516 100644 --- a/main.go +++ b/main.go @@ -3,8 +3,12 @@ package main import ( "flag" "fmt" + "github.com/go-redis/redis/v7" "github.com/spf13/viper" + "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" "os" "os/signal" @@ -36,29 +40,79 @@ func main() { fmt.Println("Using config file:", viper.ConfigFileUsed()) } - serverSettings := settings.Server() - server := &Server{ - host: serverSettings.Host, - port: serverSettings.Port, + host: viper.GetString("server.host"), + networks: viper.GetStringSlice("server.nets"), rTimeout: 5 * time.Second, wTimeout: 5 * time.Second, } - server.Run() + var resolverCache, negCache cache.Cache + r := resolver.NewResolver(settings.ResolvSettings{ + Timeout: viper.GetInt("resolv.timeout"), + Interval: viper.GetInt("resolv.interval"), + SetEDNS0: viper.GetBool("resolv.edns0"), + ServerListFile: viper.GetStringSlice("resolv.server-list"), + ResolvFile: viper.GetString("resolv.file"), + }) - log.Info("godns %s (%s) start", Version, runtime.Version()) + cacheDuration := viper.GetDuration("cache.expire") - if settings.Debug() { + redisConfig := settings.RedisSettings{ + Host: viper.GetString("cache.redis.host"), + Port: viper.GetInt("cache.redis.port"), + DB: viper.GetInt("cache.redis.db"), + Password: viper.GetString("cache.redis.password"), + } + + backend := viper.GetString("cache.backend") + + switch backend { + case "memory": + cacheMaxCount := viper.GetInt("cache.memory.maxCount") + + negCache = cache.NewMemoryCache(cacheDuration/2, cacheMaxCount) + resolverCache = cache.NewMemoryCache(cacheDuration, cacheMaxCount) + case "memcached": + servers := viper.GetStringSlice("cache.memcached.servers") + + resolverCache = cache.NewMemcachedCache(servers, int32(cacheDuration.Seconds())) + negCache = cache.NewMemcachedCache(servers, int32(cacheDuration.Seconds()/2)) + case "redis": + resolverCache = cache.NewRedisCache(redisConfig, cacheDuration) + negCache = cache.NewRedisCache(redisConfig, cacheDuration/2) + default: + log.Error("Invalid cache backend %s", backend) + panic("Invalid cache backend") + } + + providers := make([]hosts.Provider, 0) + + if viper.GetBool("hosts.file.enable") { + providers = append(providers, hosts.NewFileProvider(viper.GetString("hosts.file.file"), viper.GetDuration("hosts.file.ttl"))) + } + + if viper.GetBool("hosts.redis.enable") { + rc := redis.NewClient(&redis.Options{Addr: redisConfig.Addr(), DB: redisConfig.DB, Password: redisConfig.Password}) + + providers = append(providers, hosts.NewRedisProvider(rc, viper.GetString("hosts.redis.key"), viper.GetDuration("hosts.redis.ttl"))) + } + + h := hosts.NewHosts(providers) + + server.Run(NewHandler(r, resolverCache, negCache, h)) + + log.Info("godns %s (%s)", Version, runtime.Version()) + + if viper.GetBool("debug") { go profileCPU() go profileMEM() } sig := make(chan os.Signal) signal.Notify(sig, os.Interrupt) - - <- sig + log.Info("signal received, stopping") } @@ -93,8 +147,6 @@ func profileMEM() { } func initLogger() { - logSettings := settings.Log() - if viper.GetBool("log.stdout") { log.SetLogger("console", nil) } @@ -103,9 +155,5 @@ func initLogger() { log.SetLogger("file", map[string]interface{}{"file": file}) } - log.SetLevel(logSettings.LogLevel()) -} - -func init() { - runtime.GOMAXPROCS(runtime.NumCPU()) + log.SetLevel(settings.LogLevelFor(viper.GetString("log.level"))) } diff --git a/resolver/resolver.go b/resolver/resolver.go index 5c7c0c3..1cdafef 100644 --- a/resolver/resolver.go +++ b/resolver/resolver.go @@ -68,10 +68,6 @@ func NewResolver(c settings.ResolvSettings) *Resolver { } } - if len(c.DOHServer) > 0 { - r.servers = append([]string{c.DOHServer}, r.servers...) - } - return r } @@ -141,8 +137,7 @@ func (r *Resolver) parseServerListFile(buf *os.File) { } -func (r *Resolver) ReadServerListFile(path string) { - files := strings.Split(path, ";") +func (r *Resolver) ReadServerListFile(files []string) { for _, file := range files { buf, err := os.Open(file) if err != nil { diff --git a/server.go b/server.go index a1109e4..d4db3b0 100644 --- a/server.go +++ b/server.go @@ -1,7 +1,6 @@ package main import ( - "github.com/spf13/viper" "meow.tf/joker/godns/log" "strings" "time" @@ -11,21 +10,17 @@ import ( type Server struct { host string - port int + networks []string rTimeout time.Duration wTimeout time.Duration } -func (s *Server) Run() { - handler := NewHandler() - - nets := viper.GetStringSlice("networks") - +func (s *Server) Run(handler *Handler) { var addr string var split []string // Defaults: tcp, udp - for _, net := range nets { + for _, net := range s.networks { split = strings.Split(net, ":") net = split[0] diff --git a/settings/settings.go b/settings/settings.go index bbd0201..9b265da 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -1,18 +1,8 @@ package settings import ( - "flag" - "fmt" "meow.tf/joker/godns/log" - "os" "strconv" - - "github.com/BurntSushi/toml" - "github.com/caarlos0/env" -) - -var ( - settings Settings ) var LogLevelMap = map[string]int{ @@ -24,7 +14,6 @@ var LogLevelMap = map[string]int{ } type HostsSettings struct { - Enable bool `toml:"enable" env:"HOSTS_ENABLE"` HostsFile string `toml:"host-file" env:"HOSTS_FILE"` RedisEnable bool `toml:"redis-enable" env:"REDIS_HOSTS_ENABLE"` RedisKey string `toml:"redis-key" env:"REDIS_HOSTS_KEY"` @@ -48,9 +37,8 @@ type ResolvSettings struct { Timeout int `toml:"timeout" env:"RESOLV_TIMEOUT"` Interval int `toml:"interval" env:"RESOLV_INTERVAL"` SetEDNS0 bool `toml:"setedns0" env:"RESOLV_EDNS0"` - ServerListFile string `toml:"server-list-file" env:"SERVER_LIST_FILE"` + ServerListFile []string `toml:"server-list-file" env:"SERVER_LIST_FILE"` ResolvFile string `toml:"resolv-file" env:"RESOLV_FILE"` - DOHServer string `toml:"dns-over-https" env:"DNS_HTTPS_SERVER"` } type DNSServerSettings struct { @@ -79,10 +67,10 @@ type LogSettings struct { Level string `toml:"level" env:"LOG_LEVEL"` } -func (ls LogSettings) LogLevel() int { - l, ok := LogLevelMap[ls.Level] +func LogLevelFor(level string) int { + l, ok := LogLevelMap[level] if !ok { - panic("Config error: invalid log level: " + ls.Level) + panic("Config error: invalid log level: " + level) } return l } @@ -91,56 +79,4 @@ type CacheSettings struct { Backend string `toml:"backend" env:"CACHE_BACKEND"` Expire int `toml:"expire" env:"CACHE_EXPIRE"` Maxcount int `toml:"maxcount" env:"CACHE_MAX_COUNT"` -} - -func init() { - var configFile string - - flag.StringVar(&configFile, "c", "/etc/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) - } - - env.Parse(&settings.ResolvConfig) - env.Parse(&settings.Redis) - env.Parse(&settings.Memcache) - env.Parse(&settings.Log) - env.Parse(&settings.Cache) - env.Parse(&settings.Hosts) -} - -func Resolver() ResolvSettings { - return settings.ResolvConfig -} - -func Cache() CacheSettings { - return settings.Cache -} - -func Server() DNSServerSettings { - return settings.Server -} - -func Hosts() HostsSettings { - return settings.Hosts -} - -func Redis() RedisSettings { - return settings.Redis -} - -func Memcache() MemcacheSettings { - return settings.Memcache -} - -func Debug() bool { - return settings.Debug -} - -func Log() LogSettings { - return settings.Log } \ No newline at end of file