diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d07c0e..61b55eef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to ### Added +- New flag `--no-etc-hosts` to disable client domain name lookups in the + operating system's /etc/hosts files ([#1947]). - The ability to set up custom upstreams to resolve PTR queries for local addresses and to disable the automatic resolving of clients' addresses ([#2704]). @@ -54,6 +56,7 @@ and this project adheres to [#1273]: https://github.com/AdguardTeam/AdGuardHome/issues/1273 [#1401]: https://github.com/AdguardTeam/AdGuardHome/issues/1401 +[#1947]: https://github.com/AdguardTeam/AdGuardHome/issues/1947 [#2385]: https://github.com/AdguardTeam/AdGuardHome/issues/2385 [#2393]: https://github.com/AdguardTeam/AdGuardHome/issues/2393 [#2412]: https://github.com/AdguardTeam/AdGuardHome/issues/2412 diff --git a/internal/util/autohosts.go b/internal/aghnet/etchostscontainer.go similarity index 56% rename from internal/util/autohosts.go rename to internal/aghnet/etchostscontainer.go index a9b63c77..2d54d497 100644 --- a/internal/util/autohosts.go +++ b/internal/aghnet/etchostscontainer.go @@ -1,8 +1,4 @@ -// Package util contains various utilities. -// -// TODO(a.garipov): Such packages are widely considered an antipattern. Remove -// this when we refactor our project structure. -package util +package aghnet import ( "bufio" @@ -16,7 +12,6 @@ import ( "strings" "sync" - "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/golibs/log" "github.com/fsnotify/fsnotify" @@ -25,8 +20,11 @@ import ( type onChangedT func() -// AutoHosts - automatic DNS records -type AutoHosts struct { +// EtcHostsContainer - automatic DNS records +// +// TODO(e.burkov): Move the logic under interface. Refactor. Probably remove +// the resolving logic. +type EtcHostsContainer struct { // lock protects table and tableReverse. lock sync.RWMutex // table is the host-to-IPs map. @@ -47,63 +45,67 @@ type AutoHosts struct { } // SetOnChanged - set callback function that will be called when the data is changed -func (a *AutoHosts) SetOnChanged(onChanged onChangedT) { - a.onChanged = onChanged +func (ehc *EtcHostsContainer) SetOnChanged(onChanged onChangedT) { + ehc.onChanged = onChanged } // Notify other modules -func (a *AutoHosts) notify() { - if a.onChanged == nil { +func (ehc *EtcHostsContainer) notify() { + if ehc.onChanged == nil { return } - a.onChanged() + ehc.onChanged() } // Init - initialize // hostsFn: Override default name for the hosts-file (optional) -func (a *AutoHosts) Init(hostsFn string) { - a.table = make(map[string][]net.IP) - a.onlyWritesChan = make(chan fsnotify.Event, 2) +func (ehc *EtcHostsContainer) Init(hostsFn string) { + ehc.table = make(map[string][]net.IP) + ehc.onlyWritesChan = make(chan fsnotify.Event, 2) - a.hostsFn = "/etc/hosts" + ehc.hostsFn = "/etc/hosts" if runtime.GOOS == "windows" { - a.hostsFn = os.ExpandEnv("$SystemRoot\\system32\\drivers\\etc\\hosts") + ehc.hostsFn = os.ExpandEnv("$SystemRoot\\system32\\drivers\\etc\\hosts") } if len(hostsFn) != 0 { - a.hostsFn = hostsFn + ehc.hostsFn = hostsFn } if aghos.IsOpenWrt() { // OpenWrt: "/tmp/hosts/dhcp.cfg01411c". - a.hostsDirs = append(a.hostsDirs, "/tmp/hosts") + ehc.hostsDirs = append(ehc.hostsDirs, "/tmp/hosts") } // Load hosts initially - a.updateHosts() + ehc.updateHosts() var err error - a.watcher, err = fsnotify.NewWatcher() + ehc.watcher, err = fsnotify.NewWatcher() if err != nil { - log.Error("autohosts: %s", err) + log.Error("etchostscontainer: %s", err) } } // Start - start module -func (a *AutoHosts) Start() { - log.Debug("Start AutoHosts module") +func (ehc *EtcHostsContainer) Start() { + if ehc == nil { + return + } - a.updateHosts() + log.Debug("Start etchostscontainer module") - if a.watcher != nil { - go a.watcherLoop() + ehc.updateHosts() - err := a.watcher.Add(a.hostsFn) + if ehc.watcher != nil { + go ehc.watcherLoop() + + err := ehc.watcher.Add(ehc.hostsFn) if err != nil { - log.Error("Error while initializing watcher for a file %s: %s", a.hostsFn, err) + log.Error("Error while initializing watcher for a file %s: %s", ehc.hostsFn, err) } - for _, dir := range a.hostsDirs { - err = a.watcher.Add(dir) + for _, dir := range ehc.hostsDirs { + err = ehc.watcher.Add(dir) if err != nil { log.Error("Error while initializing watcher for a directory %s: %s", dir, err) } @@ -112,67 +114,71 @@ func (a *AutoHosts) Start() { } // Close - close module -func (a *AutoHosts) Close() { - if a.watcher != nil { - _ = a.watcher.Close() +func (ehc *EtcHostsContainer) Close() { + if ehc == nil { + return } - close(a.onlyWritesChan) + + if ehc.watcher != nil { + _ = ehc.watcher.Close() + } + close(ehc.onlyWritesChan) } // Process returns the list of IP addresses for the hostname or nil if nothing // found. -func (a *AutoHosts) Process(host string, qtype uint16) []net.IP { +func (ehc *EtcHostsContainer) Process(host string, qtype uint16) []net.IP { if qtype == dns.TypePTR { return nil } var ipsCopy []net.IP - a.lock.RLock() - defer a.lock.RUnlock() + ehc.lock.RLock() + defer ehc.lock.RUnlock() - if ips, ok := a.table[host]; ok { + if ips, ok := ehc.table[host]; ok { ipsCopy = make([]net.IP, len(ips)) copy(ipsCopy, ips) } - log.Debug("autohosts: answer: %s -> %v", host, ipsCopy) + log.Debug("etchostscontainer: answer: %s -> %v", host, ipsCopy) return ipsCopy } // ProcessReverse processes a PTR request. It returns nil if nothing is found. -func (a *AutoHosts) ProcessReverse(addr string, qtype uint16) (hosts []string) { +func (ehc *EtcHostsContainer) ProcessReverse(addr string, qtype uint16) (hosts []string) { if qtype != dns.TypePTR { return nil } - ipReal := aghnet.UnreverseAddr(addr) + ipReal := UnreverseAddr(addr) if ipReal == nil { return nil } ipStr := ipReal.String() - a.lock.RLock() - defer a.lock.RUnlock() + ehc.lock.RLock() + defer ehc.lock.RUnlock() - hosts = a.tableReverse[ipStr] + hosts = ehc.tableReverse[ipStr] if len(hosts) == 0 { return nil // not found } - log.Debug("autohosts: reverse-lookup: %s -> %s", addr, hosts) + log.Debug("etchostscontainer: reverse-lookup: %s -> %s", addr, hosts) return hosts } // List returns an IP-to-hostnames table. It is safe for concurrent use. -func (a *AutoHosts) List() (ipToHosts map[string][]string) { - a.lock.RLock() - defer a.lock.RUnlock() +func (ehc *EtcHostsContainer) List() (ipToHosts map[string][]string) { + ehc.lock.RLock() + defer ehc.lock.RUnlock() - ipToHosts = make(map[string][]string, len(a.tableReverse)) - for k, v := range a.tableReverse { + ipToHosts = make(map[string][]string, len(ehc.tableReverse)) + for k, v := range ehc.tableReverse { ipToHosts[k] = v } @@ -180,7 +186,7 @@ func (a *AutoHosts) List() (ipToHosts map[string][]string) { } // update table -func (a *AutoHosts) updateTable(table map[string][]net.IP, host string, ipAddr net.IP) { +func (ehc *EtcHostsContainer) updateTable(table map[string][]net.IP, host string, ipAddr net.IP) { ips, ok := table[host] if ok { for _, ip := range ips { @@ -199,17 +205,17 @@ func (a *AutoHosts) updateTable(table map[string][]net.IP, host string, ipAddr n ok = true } if ok { - log.Debug("autohosts: added %s -> %s", ipAddr, host) + log.Debug("etchostscontainer: added %s -> %s", ipAddr, host) } } // updateTableRev updates the reverse address table. -func (a *AutoHosts) updateTableRev(tableRev map[string][]string, newHost string, ipAddr net.IP) { +func (ehc *EtcHostsContainer) updateTableRev(tableRev map[string][]string, newHost string, ipAddr net.IP) { ipStr := ipAddr.String() hosts, ok := tableRev[ipStr] if !ok { tableRev[ipStr] = []string{newHost} - log.Debug("autohosts: added reverse-address %s -> %s", ipStr, newHost) + log.Debug("etchostscontainer: added reverse-address %s -> %s", ipStr, newHost) return } @@ -221,20 +227,20 @@ func (a *AutoHosts) updateTableRev(tableRev map[string][]string, newHost string, } tableRev[ipStr] = append(tableRev[ipStr], newHost) - log.Debug("autohosts: added reverse-address %s -> %s", ipStr, newHost) + log.Debug("etchostscontainer: added reverse-address %s -> %s", ipStr, newHost) } // Read IP-hostname pairs from file // Multiple hostnames per line (per one IP) is supported. -func (a *AutoHosts) load(table map[string][]net.IP, tableRev map[string][]string, fn string) { +func (ehc *EtcHostsContainer) load(table map[string][]net.IP, tableRev map[string][]string, fn string) { f, err := os.Open(fn) if err != nil { - log.Error("autohosts: %s", err) + log.Error("etchostscontainer: %s", err) return } defer f.Close() r := bufio.NewReader(f) - log.Debug("autohosts: loading hosts from file %s", fn) + log.Debug("etchostscontainer: loading hosts from file %s", fn) for done := false; !done; { var line string @@ -242,7 +248,7 @@ func (a *AutoHosts) load(table map[string][]net.IP, tableRev map[string][]string if err == io.EOF { done = true } else if err != nil { - log.Error("autohosts: %s", err) + log.Error("etchostscontainer: %s", err) return } @@ -276,8 +282,8 @@ func (a *AutoHosts) load(table map[string][]net.IP, tableRev map[string][]string host = host[:sharp] } - a.updateTable(table, host, ip) - a.updateTableRev(tableRev, host, ip) + ehc.updateTable(table, host, ip) + ehc.updateTableRev(tableRev, host, ip) if sharp >= 0 { // Skip the comments again. break @@ -287,20 +293,20 @@ func (a *AutoHosts) load(table map[string][]net.IP, tableRev map[string][]string } // onlyWrites is a filter for (*fsnotify.Watcher).Events. -func (a *AutoHosts) onlyWrites() { - for event := range a.watcher.Events { +func (ehc *EtcHostsContainer) onlyWrites() { + for event := range ehc.watcher.Events { if event.Op&fsnotify.Write == fsnotify.Write { - a.onlyWritesChan <- event + ehc.onlyWritesChan <- event } } } // Receive notifications from fsnotify package -func (a *AutoHosts) watcherLoop() { - go a.onlyWrites() +func (ehc *EtcHostsContainer) watcherLoop() { + go ehc.onlyWrites() for { select { - case event, ok := <-a.onlyWritesChan: + case event, ok := <-ehc.onlyWritesChan: if !ok { return } @@ -310,7 +316,7 @@ func (a *AutoHosts) watcherLoop() { repeat := true for repeat { select { - case _, ok = <-a.onlyWritesChan: + case _, ok = <-ehc.onlyWritesChan: repeat = ok default: repeat = false @@ -318,48 +324,48 @@ func (a *AutoHosts) watcherLoop() { } if event.Op&fsnotify.Write == fsnotify.Write { - log.Debug("autohosts: modified: %s", event.Name) - a.updateHosts() + log.Debug("etchostscontainer: modified: %s", event.Name) + ehc.updateHosts() } - case err, ok := <-a.watcher.Errors: + case err, ok := <-ehc.watcher.Errors: if !ok { return } - log.Error("autohosts: %s", err) + log.Error("etchostscontainer: %s", err) } } } // updateHosts - loads system hosts -func (a *AutoHosts) updateHosts() { +func (ehc *EtcHostsContainer) updateHosts() { table := make(map[string][]net.IP) tableRev := make(map[string][]string) - a.load(table, tableRev, a.hostsFn) + ehc.load(table, tableRev, ehc.hostsFn) - for _, dir := range a.hostsDirs { + for _, dir := range ehc.hostsDirs { fis, err := ioutil.ReadDir(dir) if err != nil { if !errors.Is(err, os.ErrNotExist) { - log.Error("autohosts: Opening directory: %q: %s", dir, err) + log.Error("etchostscontainer: Opening directory: %q: %s", dir, err) } continue } for _, fi := range fis { - a.load(table, tableRev, filepath.Join(dir, fi.Name())) + ehc.load(table, tableRev, filepath.Join(dir, fi.Name())) } } func() { - a.lock.Lock() - defer a.lock.Unlock() + ehc.lock.Lock() + defer ehc.lock.Unlock() - a.table = table - a.tableReverse = tableRev + ehc.table = table + ehc.tableReverse = tableRev }() - a.notify() + ehc.notify() } diff --git a/internal/util/autohosts_test.go b/internal/aghnet/etshostscontainer_test.go similarity index 79% rename from internal/util/autohosts_test.go rename to internal/aghnet/etshostscontainer_test.go index 60ff4622..38a780d4 100644 --- a/internal/util/autohosts_test.go +++ b/internal/aghnet/etshostscontainer_test.go @@ -1,4 +1,4 @@ -package util +package aghnet import ( "io/ioutil" @@ -43,8 +43,8 @@ func assertWriting(t *testing.T, f *os.File, strs ...string) { } } -func TestAutoHostsResolution(t *testing.T) { - ah := &AutoHosts{} +func TestEtcHostsContainerResolution(t *testing.T) { + ehc := &EtcHostsContainer{} f := prepareTestFile(t) @@ -52,25 +52,25 @@ func TestAutoHostsResolution(t *testing.T) { " 127.0.0.1 host localhost # comment \n", " ::1 localhost#comment \n", ) - ah.Init(f.Name()) + ehc.Init(f.Name()) t.Run("existing_host", func(t *testing.T) { - ips := ah.Process("localhost", dns.TypeA) + ips := ehc.Process("localhost", dns.TypeA) require.Len(t, ips, 1) assert.Equal(t, net.IPv4(127, 0, 0, 1), ips[0]) }) t.Run("unknown_host", func(t *testing.T) { - ips := ah.Process("newhost", dns.TypeA) + ips := ehc.Process("newhost", dns.TypeA) assert.Nil(t, ips) // Comment. - ips = ah.Process("comment", dns.TypeA) + ips = ehc.Process("comment", dns.TypeA) assert.Nil(t, ips) }) t.Run("hosts_file", func(t *testing.T) { - names, ok := ah.List()["127.0.0.1"] + names, ok := ehc.List()["127.0.0.1"] require.True(t, ok) assert.Equal(t, []string{"host", "localhost"}, names) }) @@ -90,29 +90,29 @@ func TestAutoHostsResolution(t *testing.T) { require.Nil(t, err) a = strings.TrimSuffix(a, ".") - hosts := ah.ProcessReverse(a, dns.TypePTR) + hosts := ehc.ProcessReverse(a, dns.TypePTR) require.Len(t, hosts, tc.wantLen) assert.Equal(t, tc.wantHost, hosts[0]) } }) } -func TestAutoHostsFSNotify(t *testing.T) { - ah := &AutoHosts{} +func TestEtcHostsContainerFSNotify(t *testing.T) { + ehc := &EtcHostsContainer{} f := prepareTestFile(t) assertWriting(t, f, " 127.0.0.1 host localhost \n") - ah.Init(f.Name()) + ehc.Init(f.Name()) t.Run("unknown_host", func(t *testing.T) { - ips := ah.Process("newhost", dns.TypeA) + ips := ehc.Process("newhost", dns.TypeA) assert.Nil(t, ips) }) // Start monitoring for changes. - ah.Start() - t.Cleanup(ah.Close) + ehc.Start() + t.Cleanup(ehc.Close) assertWriting(t, f, "127.0.0.2 newhost\n") require.Nil(t, f.Sync()) @@ -122,7 +122,7 @@ func TestAutoHostsFSNotify(t *testing.T) { time.Sleep(50 * time.Millisecond) t.Run("notified", func(t *testing.T) { - ips := ah.Process("newhost", dns.TypeA) + ips := ehc.Process("newhost", dns.TypeA) assert.NotNil(t, ips) require.Len(t, ips, 1) assert.True(t, net.IP{127, 0, 0, 2}.Equal(ips[0])) diff --git a/internal/dnsfilter/dnsfilter.go b/internal/dnsfilter/dnsfilter.go index b306c16f..a0413a84 100644 --- a/internal/dnsfilter/dnsfilter.go +++ b/internal/dnsfilter/dnsfilter.go @@ -13,7 +13,7 @@ import ( "strings" "sync" - "github.com/AdguardTeam/AdGuardHome/internal/util" + "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/cache" "github.com/AdguardTeam/golibs/log" @@ -65,8 +65,9 @@ type Config struct { // Per-client settings can override this configuration. BlockedServices []string `yaml:"blocked_services"` - // IP-hostname pairs taken from system configuration (e.g. /etc/hosts) files - AutoHosts *util.AutoHosts `yaml:"-"` + // EtcHosts is a container of IP-hostname pairs taken from the operating + // system configuration files (e.g. /etc/hosts). + EtcHosts *aghnet.EtcHostsContainer `yaml:"-"` // Called when the configuration is changed by HTTP request ConfigModified func() `yaml:"-"` @@ -428,11 +429,11 @@ func (d *DNSFilter) checkAutoHosts( qtype uint16, _ *FilteringSettings, ) (res Result, err error) { - if d.Config.AutoHosts == nil { + if d.Config.EtcHosts == nil { return Result{}, nil } - ips := d.Config.AutoHosts.Process(host, qtype) + ips := d.Config.EtcHosts.Process(host, qtype) if ips != nil { res = Result{ Reason: RewrittenAutoHosts, @@ -442,7 +443,7 @@ func (d *DNSFilter) checkAutoHosts( return res, nil } - revHosts := d.Config.AutoHosts.ProcessReverse(host, qtype) + revHosts := d.Config.EtcHosts.ProcessReverse(host, qtype) if len(revHosts) != 0 { res = Result{ Reason: RewrittenAutoHosts, diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index 510fb87d..aa954a7c 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -23,7 +23,6 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/dhcpd" "github.com/AdguardTeam/AdGuardHome/internal/dnsfilter" - "github.com/AdguardTeam/AdGuardHome/internal/util" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/miekg/dns" @@ -1074,7 +1073,7 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) { func TestPTRResponseFromHosts(t *testing.T) { c := dnsfilter.Config{ - AutoHosts: &util.AutoHosts{}, + EtcHosts: &aghnet.EtcHostsContainer{}, } // Prepare test hosts file. @@ -1090,8 +1089,8 @@ func TestPTRResponseFromHosts(t *testing.T) { _, _ = hf.WriteString(" ::1 localhost#comment \n") // Init auto hosts. - c.AutoHosts.Init(hf.Name()) - t.Cleanup(c.AutoHosts.Close) + c.EtcHosts.Init(hf.Name()) + t.Cleanup(c.EtcHosts.Close) var snd *aghnet.SubnetDetector snd, err = aghnet.NewSubnetDetector() diff --git a/internal/home/clients.go b/internal/home/clients.go index 32043f8c..25bc6d8f 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -18,7 +18,6 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/dnsfilter" "github.com/AdguardTeam/AdGuardHome/internal/dnsforward" "github.com/AdguardTeam/AdGuardHome/internal/querylog" - "github.com/AdguardTeam/AdGuardHome/internal/util" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/log" @@ -92,7 +91,7 @@ type clientsContainer struct { // dnsServer is used for checking clients IP status access list status dnsServer *dnsforward.Server - autoHosts *util.AutoHosts // get entries from system hosts-files + etcHosts *aghnet.EtcHostsContainer // get entries from system hosts-files testing bool // if TRUE, this object is used for internal tests } @@ -100,7 +99,11 @@ type clientsContainer struct { // Init initializes clients container // dhcpServer: optional // Note: this function must be called only once -func (clients *clientsContainer) Init(objects []clientObject, dhcpServer *dhcpd.Server, autoHosts *util.AutoHosts) { +func (clients *clientsContainer) Init( + objects []clientObject, + dhcpServer *dhcpd.Server, + etcHosts *aghnet.EtcHostsContainer, +) { if clients.list != nil { log.Fatal("clients.list != nil") } @@ -114,7 +117,9 @@ func (clients *clientsContainer) Init(objects []clientObject, dhcpServer *dhcpd. } clients.dhcpServer = dhcpServer - clients.autoHosts = autoHosts + if etcHosts != nil { + clients.etcHosts = etcHosts + } clients.addFromConfig(objects) if !clients.testing { @@ -122,7 +127,9 @@ func (clients *clientsContainer) Init(objects []clientObject, dhcpServer *dhcpd. if clients.dhcpServer != nil { clients.dhcpServer.SetOnLeaseChanged(clients.onDHCPLeaseChanged) } - clients.autoHosts.SetOnChanged(clients.onHostsChanged) + if clients.etcHosts != nil { + clients.etcHosts.SetOnChanged(clients.onHostsChanged) + } } } @@ -692,7 +699,11 @@ func (clients *clientsContainer) rmHostsBySrc(src clientSource) { // addFromHostsFile fills the client-hostname pairing index from the system's // hosts files. func (clients *clientsContainer) addFromHostsFile() { - hosts := clients.autoHosts.List() + if clients.etcHosts == nil { + return + } + + hosts := clients.etcHosts.List() clients.lock.Lock() defer clients.lock.Unlock() diff --git a/internal/home/dns.go b/internal/home/dns.go index e1cbc1e3..35d58540 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -57,7 +57,7 @@ func initDNSServer() error { Context.queryLog = querylog.New(conf) filterConf := config.DNS.DnsfilterConf - filterConf.AutoHosts = &Context.autoHosts + filterConf.EtcHosts = Context.etcHosts filterConf.ConfigModified = onConfigModified filterConf.HTTPRegister = httpRegister Context.dnsFilter = dnsfilter.New(&filterConf, nil) diff --git a/internal/home/home.go b/internal/home/home.go index be70fc21..a4c863de 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -46,19 +46,19 @@ type homeContext struct { // Modules // -- - clients clientsContainer // per-client-settings module - stats stats.Stats // statistics module - queryLog querylog.QueryLog // query log module - dnsServer *dnsforward.Server // DNS module - rdns *RDNS // rDNS module - whois *Whois // WHOIS module - dnsFilter *dnsfilter.DNSFilter // DNS filtering module - dhcpServer *dhcpd.Server // DHCP module - auth *Auth // HTTP authentication module - filters Filtering // DNS filtering module - web *Web // Web (HTTP, HTTPS) module - tls *TLSMod // TLS module - autoHosts util.AutoHosts // IP-hostname pairs taken from system configuration (e.g. /etc/hosts) files + clients clientsContainer // per-client-settings module + stats stats.Stats // statistics module + queryLog querylog.QueryLog // query log module + dnsServer *dnsforward.Server // DNS module + rdns *RDNS // rDNS module + whois *Whois // WHOIS module + dnsFilter *dnsfilter.DNSFilter // DNS filtering module + dhcpServer *dhcpd.Server // DHCP module + auth *Auth // HTTP authentication module + filters Filtering // DNS filtering module + web *Web // Web (HTTP, HTTPS) module + tls *TLSMod // TLS module + etcHosts *aghnet.EtcHostsContainer // IP-hostname pairs taken from system configuration (e.g. /etc/hosts) files updater *updater.Updater subnetDetector *aghnet.SubnetDetector @@ -186,8 +186,6 @@ func setupConfig(args options) { log.Fatalf("can't initialize dhcp module") } - Context.autoHosts.Init("") - Context.updater = updater.NewUpdater(&updater.Config{ Client: Context.client, Version: version.Version(), @@ -200,7 +198,11 @@ func setupConfig(args options) { ConfName: config.getConfigFilename(), }) - Context.clients.Init(config.Clients, Context.dhcpServer, &Context.autoHosts) + if !args.noEtcHosts { + Context.etcHosts = &aghnet.EtcHostsContainer{} + Context.etcHosts.Init("") + Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts) + } config.Clients = nil if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") && @@ -317,7 +319,7 @@ func run(args options) { } Context.tls.Start() - Context.autoHosts.Start() + Context.etcHosts.Start() go func() { serr := startDNSServer() @@ -530,7 +532,7 @@ func cleanup(ctx context.Context) { Context.dhcpServer.Stop() } - Context.autoHosts.Close() + Context.etcHosts.Close() if Context.tls != nil { Context.tls.Close() diff --git a/internal/home/options.go b/internal/home/options.go index 293c50b0..f7823347 100644 --- a/internal/home/options.go +++ b/internal/home/options.go @@ -32,6 +32,10 @@ type options struct { disableMemoryOptimization bool glinetMode bool // Activate GL-Inet compatibility mode + + // noEtcHosts flag should be provided when /etc/hosts file shouldn't be + // used. + noEtcHosts bool } // functions used for their side-effects @@ -191,7 +195,7 @@ var glinetArg = arg{ } var versionArg = arg{ - description: "Show the version and exit", + description: "Show the version and exit. Show more detailed version description with -v", longName: "version", shortName: "", updateWithValue: nil, @@ -212,7 +216,7 @@ var versionArg = arg{ } var helpArg = arg{ - "Print this help. Show more detailed version description with -v", + "Print this help", "help", "", nil, nil, func(o options, exec string) (effect, error) { return func() error { _ = printHelp(exec); os.Exit(64); return nil }, nil @@ -220,6 +224,16 @@ var helpArg = arg{ func(o options) []string { return nil }, } +var noEtcHostsArg = arg{ + description: "Do not use the OS-provided hosts.", + longName: "no-etc-hosts", + shortName: "", + updateWithValue: nil, + updateNoValue: func(o options) (options, error) { o.noEtcHosts = true; return o, nil }, + effect: nil, + serialize: func(o options) []string { return boolSliceOrNil(o.noEtcHosts) }, +} + func init() { args = []arg{ configArg, @@ -232,6 +246,7 @@ func init() { checkConfigArg, noCheckUpdateArg, disableMemoryOptimizationArg, + noEtcHostsArg, verboseArg, glinetArg, versionArg, diff --git a/internal/util/tls.go b/internal/util/tls.go index ed70d24f..f7498d72 100644 --- a/internal/util/tls.go +++ b/internal/util/tls.go @@ -1,3 +1,7 @@ +// Package util contains various utilities. +// +// TODO(a.garipov): Such packages are widely considered an antipattern. Remove +// this when we refactor our project structure. package util import (