diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 59b2a6d3..862bf162 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -63,6 +63,13 @@ func NewServer(stats stats.Stats, queryLog querylog.QueryLog) *Server { return s } +func (s *Server) Close() { + s.Lock() + s.stats = nil + s.queryLog = nil + s.Unlock() +} + // FilteringConfig represents the DNS filtering configuration of AdGuard Home // The zero FilteringConfig is empty and ready for use. type FilteringConfig struct { @@ -467,6 +474,9 @@ func (s *Server) handleDNSRequest(p *proxy.Proxy, d *proxy.DNSContext) error { } elapsed := time.Since(start) + s.RLock() + // Synchronize access to s.queryLog and s.stats so they won't be suddenly uninitialized while in use. + // This can happen after proxy server has been stopped, but its workers haven't yet exited. if s.conf.QueryLogEnabled && shouldLog && s.queryLog != nil { upstreamAddr := "" if d.Upstream != nil { @@ -476,6 +486,7 @@ func (s *Server) handleDNSRequest(p *proxy.Proxy, d *proxy.DNSContext) error { } s.updateStats(d, elapsed, *res) + s.RUnlock() return nil } diff --git a/home/dns.go b/home/dns.go index c775bb4a..c9f199e1 100644 --- a/home/dns.go +++ b/home/dns.go @@ -204,8 +204,16 @@ func stopDNSServer() error { return errorx.Decorate(err, "Couldn't stop forwarding DNS server") } + // DNS forward module must be closed BEFORE stats or queryLog because it depends on them + config.dnsServer.Close() + config.stats.Close() + config.stats = nil + config.queryLog.Close() + config.queryLog = nil + config.auth.Close() + config.auth = nil return nil } diff --git a/stats/stats_unit.go b/stats/stats_unit.go index 20bfb721..eb6d6e85 100644 --- a/stats/stats_unit.go +++ b/stats/stats_unit.go @@ -420,6 +420,7 @@ func (s *statsCtx) Clear() { func (s *statsCtx) Update(e Entry) { if e.Result == 0 || + e.Result >= rLast || len(e.Domain) == 0 || !(len(e.Client) == 4 || len(e.Client) == 16) { return