diff --git a/.gitignore b/.gitignore index 5e56e04..d05c4ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /bin +godns +godns.log +etc/godns.conf \ No newline at end of file diff --git a/cache_redis.go b/cache_redis.go index 208ad57..eb42267 100644 --- a/cache_redis.go +++ b/cache_redis.go @@ -65,6 +65,6 @@ func (m *RedisCache) Remove(key string) error { } func (m *RedisCache) Full() bool { - // memcache is never full (LRU) + // redis is never full (LRU) return false } diff --git a/docker/Dockerfile b/docker/Dockerfile index e9d0b3f..1ee7b79 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,6 +8,6 @@ RUN apk --no-cache add tini ENTRYPOINT ["/sbin/tini", "-g", "--"] CMD ["godns"] -COPY etc/godns.conf /etc/godns.conf +COPY etc/godns.example.conf /etc/godns.conf COPY godns /usr/local/bin/godns RUN chmod +x /usr/local/bin/godns diff --git a/docker/Dockerfile.arm b/docker/Dockerfile.arm index 9c4a359..317889a 100644 --- a/docker/Dockerfile.arm +++ b/docker/Dockerfile.arm @@ -10,6 +10,6 @@ RUN apk --no-cache add tini ENTRYPOINT ["/sbin/tini", "-g", "--"] CMD ["godns"] -COPY etc/godns.conf /etc/godns.conf +COPY etc/godns.example.conf /etc/godns.conf COPY godns-arm /usr/local/bin/godns RUN chmod +x /usr/local/bin/godns diff --git a/docker/Dockerfile.arm64 b/docker/Dockerfile.arm64 index 63cbe8e..df66cd6 100644 --- a/docker/Dockerfile.arm64 +++ b/docker/Dockerfile.arm64 @@ -10,6 +10,6 @@ RUN apk --no-cache add tini ENTRYPOINT ["/sbin/tini", "-g", "--"] CMD ["godns"] -COPY etc/godns.conf /etc/godns.conf +COPY etc/godns.example.conf /etc/godns.conf COPY godns-arm64 /usr/local/bin/godns RUN chmod +x /usr/local/bin/godns diff --git a/etc/godns.conf b/etc/godns.conf index 7455b4c..213e631 100644 --- a/etc/godns.conf +++ b/etc/godns.conf @@ -14,17 +14,16 @@ port = 53 [resolv] # Domain-specific nameservers configuration, formatting keep compatible with Dnsmasq # Semicolon separate multiple files. -resolv-file = "/etc/resolv.conf" +resolv-file = "etc/resolv.conf" 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 [redis] enable = true -host = "127.0.0.1" +host = "192.168.1.71" port = 6379 db = 0 password ="" @@ -35,7 +34,7 @@ servers = ["127.0.0.1:11211"] [log] stdout = true file = "./godns.log" -level = "INFO" #DEBUG | INFO |NOTICE | WARN | ERROR +level = "DEBUG" #DEBUG | INFO |NOTICE | WARN | ERROR @@ -50,9 +49,9 @@ maxcount = 0 #If set zero. The Sum of cache itmes will be unlimit. #If set false, will not query hosts file and redis hosts record enable = true host-file = "/etc/hosts" -redis-enable = false +redis-enable = true redis-key = "godns:hosts" ttl = 600 -refresh-interval = 5 # 5 seconds +refresh-interval = 60 # 5 seconds diff --git a/etc/godns.example.conf b/etc/godns.example.conf new file mode 100644 index 0000000..ef46fe5 --- /dev/null +++ b/etc/godns.example.conf @@ -0,0 +1,56 @@ +#Toml config file +title = "GODNS" +version = "0.2.0" +author = "kenshin, tystuyfzand" + +debug = false + +[server] +host = "" +port = 53 + +[resolv] +# Domain-specific nameservers configuration, formatting keep compatible with Dnsmasq +# Semicolon separate multiple files. +resolv-file = "/etc/resolv.conf" +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 +# When defined, this is preferred over regular DNS. This requires a resolver to be active besides this, only for the initial lookup. +# A hosts file entry will suffice as well. +# dns-over-https = "https://cloudflare-dns.com/dns-query" +setedns0 = false #Support for larger UDP DNS responses + +[redis] +enable = true +host = "127.0.0.1" +port = 6379 +db = 0 +password ="" + +[memcache] +servers = ["127.0.0.1:11211"] + +[log] +stdout = true +file = "./godns.log" +level = "INFO" #DEBUG | INFO |NOTICE | WARN | ERROR + +[cache] +# backend option [memory|memcache|redis] +backend = "memory" +expire = 600 # 10 minutes +maxcount = 0 #If set zero. The Sum of cache items will be unlimit. + +[hosts] +#If set false, will not query hosts file and redis hosts record +enable = true +host-file = "/etc/hosts" +redis-enable = false +redis-key = "godns:hosts" +ttl = 600 +# Refresh interval can be high since we have automatic updating via push and fsnotify +refresh-interval = 300 + + diff --git a/hosts.go b/hosts.go index 734c6d2..668c695 100644 --- a/hosts.go +++ b/hosts.go @@ -32,7 +32,9 @@ func NewHosts(hs HostsSettings, rs RedisSettings) Hosts { h := Hosts{providers, time.Second * time.Duration(hs.RefreshInterval)} - h.refresh() + if h.refreshInterval > 0 { + h.refresh() + } return h } diff --git a/hosts_redis.go b/hosts_redis.go index f752279..b26d42b 100644 --- a/hosts_redis.go +++ b/hosts_redis.go @@ -23,11 +23,14 @@ func NewRedisProvider(rc *redis.Client, key string) HostProvider { hosts: make(map[string]string), } + // Force an initial refresh + rh.Refresh() + // Use pubsub to listen for key update events go func() { keyspaceEvent := "__keyspace@0__:" + key - sub := make(chan string, 2) + sub := make(chan string, 3) sub <- keyspaceEvent sub <- "godns:update" sub <- "godns:update_record" @@ -38,6 +41,7 @@ func NewRedisProvider(rc *redis.Client, key string) HostProvider { msg := <- messages if msg.Channel == "godns:update" { + logger.Debug("Refreshing redis records due to update") rh.Refresh() } else if msg.Channel == "godns:update_record" { recordName := string(msg.Message) @@ -45,17 +49,23 @@ func NewRedisProvider(rc *redis.Client, key string) HostProvider { b, err := rc.Hget(key, recordName) if err != nil { + logger.Warn("Record %s does not exist, but was updated", recordName) continue } - rh.mu.RLock() + logger.Debug("Record %s was updated to %s", recordName, string(b)) + + rh.mu.Lock() rh.hosts[recordName] = string(b) - rh.mu.RUnlock() + rh.mu.Unlock() } else if msg.Channel == "godns:remove_record" { - rh.mu.RLock() + logger.Debug("Record %s was removed", msg.Message) + + rh.mu.Lock() delete(rh.hosts, string(msg.Message)) - rh.mu.RUnlock() + rh.mu.Unlock() } else if msg.Channel == keyspaceEvent { + logger.Debug("Refreshing redis records due to update") rh.Refresh() } } diff --git a/settings.go b/settings.go index 55f06f4..96ca08c 100644 --- a/settings.go +++ b/settings.go @@ -23,8 +23,8 @@ var LogLevelMap = map[string]int{ } type Settings struct { - Version string - Debug bool + Version string `toml:"version"` + Debug bool `toml:"debug"` Server DNSServerSettings `toml:"server"` ResolvConfig ResolvSettings `toml:"resolv"` Redis RedisSettings `toml:"redis"` @@ -35,9 +35,9 @@ type Settings struct { } type ResolvSettings struct { - Timeout int - Interval int - SetEDNS0 bool + 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"` ResolvFile string `toml:"resolv-file" env:"RESOLV_FILE"` DOHServer string `toml:"dns-over-https" env:"DNS_HTTPS_SERVER"` @@ -64,7 +64,7 @@ func (s RedisSettings) Addr() string { } type LogSettings struct { - Stdout bool + Stdout bool `toml:"stdout" env:"LOG_STDOUT"` File string `toml:"file" env:"LOG_FILE"` Level string `toml:"level" env:"LOG_LEVEL"` }