Merge: * dnsforward: create dnsfilter asynchronously

Close #928

* commit '75b864f25ec5f762d6cbfc07d3dce7d77ca0629c':
  * dnsforward: create dnsfilter asynchronously
This commit is contained in:
Simon Zolin 2019-09-23 20:03:38 +03:00
commit 77892bb7e9
2 changed files with 79 additions and 5 deletions

View File

@ -44,6 +44,12 @@ type Server struct {
queryLog querylog.QueryLog // Query log instance queryLog querylog.QueryLog // Query log instance
stats stats.Stats stats stats.Stats
// How many times the server was started
// While creating a dnsfilter object,
// we use this value to set s.dnsFilter property only with the most recent settings.
startCounter uint32
dnsfilterCreatorChan chan dnsfilterCreatorParams
AllowedClients map[string]bool // IP addresses of whitelist clients AllowedClients map[string]bool // IP addresses of whitelist clients
DisallowedClients map[string]bool // IP addresses of clients that should be blocked DisallowedClients map[string]bool // IP addresses of clients that should be blocked
AllowedClientsIPNet []net.IPNet // CIDRs of whitelist clients AllowedClientsIPNet []net.IPNet // CIDRs of whitelist clients
@ -54,6 +60,11 @@ type Server struct {
conf ServerConfig conf ServerConfig
} }
type dnsfilterCreatorParams struct {
conf dnsfilter.Config
filters map[int]string
}
// NewServer creates a new instance of the dnsforward.Server // NewServer creates a new instance of the dnsforward.Server
// Note: this function must be called only once // Note: this function must be called only once
func NewServer(stats stats.Stats, queryLog querylog.QueryLog) *Server { func NewServer(stats stats.Stats, queryLog querylog.QueryLog) *Server {
@ -73,6 +84,12 @@ func (s *Server) Close() {
// FilteringConfig represents the DNS filtering configuration of AdGuard Home // FilteringConfig represents the DNS filtering configuration of AdGuard Home
// The zero FilteringConfig is empty and ready for use. // The zero FilteringConfig is empty and ready for use.
type FilteringConfig struct { type FilteringConfig struct {
// Create dnsfilter asynchronously.
// Requests won't be filtered until dnsfilter is created.
// If "restart" command is received while we're creating an old dnsfilter object,
// we delay creation of the new object until the old one is created.
AsyncStartup bool
ProtectionEnabled bool `yaml:"protection_enabled"` // whether or not use any of dnsfilter features ProtectionEnabled bool `yaml:"protection_enabled"` // whether or not use any of dnsfilter features
FilteringEnabled bool `yaml:"filtering_enabled"` // whether or not use filter lists FilteringEnabled bool `yaml:"filtering_enabled"` // whether or not use filter lists
FiltersUpdateIntervalHours uint32 `yaml:"filters_update_interval"` // time period to update filters (in hours) FiltersUpdateIntervalHours uint32 `yaml:"filters_update_interval"` // time period to update filters (in hours)
@ -254,8 +271,6 @@ func (s *Server) startInternal(config *ServerConfig) error {
// Initializes the DNS filter // Initializes the DNS filter
func (s *Server) initDNSFilter(config *ServerConfig) error { func (s *Server) initDNSFilter(config *ServerConfig) error {
log.Tracef("Creating dnsfilter")
if config != nil { if config != nil {
s.conf = *config s.conf = *config
} }
@ -280,13 +295,71 @@ func (s *Server) initDNSFilter(config *ServerConfig) error {
s.conf.SafeBrowsingBlockHost = safeBrowsingBlockHost s.conf.SafeBrowsingBlockHost = safeBrowsingBlockHost
} }
s.dnsFilter = dnsfilter.New(&s.conf.Config, filters) if s.conf.AsyncStartup {
if s.dnsFilter == nil { params := dnsfilterCreatorParams{
conf: s.conf.Config,
filters: filters,
}
s.startCounter++
if s.startCounter == 1 {
s.dnsfilterCreatorChan = make(chan dnsfilterCreatorParams, 1)
go s.dnsfilterCreator()
}
// remove all pending tasks
stop := false
for !stop {
select {
case <-s.dnsfilterCreatorChan:
//
default:
stop = true
}
}
s.dnsfilterCreatorChan <- params
} else {
log.Debug("creating dnsfilter...")
f := dnsfilter.New(&s.conf.Config, filters)
if f == nil {
return fmt.Errorf("could not initialize dnsfilter") return fmt.Errorf("could not initialize dnsfilter")
} }
log.Debug("created dnsfilter")
s.dnsFilter = f
}
return nil return nil
} }
func (s *Server) dnsfilterCreator() {
for {
params := <-s.dnsfilterCreatorChan
s.Lock()
counter := s.startCounter
s.Unlock()
log.Debug("creating dnsfilter...")
f := dnsfilter.New(&params.conf, params.filters)
if f == nil {
log.Error("could not initialize dnsfilter")
continue
}
set := false
s.Lock()
if counter == s.startCounter {
s.dnsFilter = f
set = true
}
s.Unlock()
if set {
log.Debug("created and activated dnsfilter")
} else {
log.Debug("created dnsfilter")
}
}
}
// Stop stops the DNS server // Stop stops the DNS server
func (s *Server) Stop() error { func (s *Server) Stop() error {
s.Lock() s.Lock()

View File

@ -104,6 +104,7 @@ func generateServerConfig() (dnsforward.ServerConfig, error) {
FilteringConfig: config.DNS.FilteringConfig, FilteringConfig: config.DNS.FilteringConfig,
Filters: filters, Filters: filters,
} }
newconfig.AsyncStartup = true
bindhost := config.DNS.BindHost bindhost := config.DNS.BindHost
if config.DNS.BindHost == "0.0.0.0" { if config.DNS.BindHost == "0.0.0.0" {
bindhost = "127.0.0.1" bindhost = "127.0.0.1"