From 75d680ff30001e846edcbbc6c102fb36ce52bcba Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Thu, 10 Sep 2020 12:32:36 +0300 Subject: [PATCH 1/8] * (dnsforward): added some hosts to disallowed by default --- dnsforward/config.go | 3 +++ dnsforward/dnsforward.go | 3 +++ go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dnsforward/config.go b/dnsforward/config.go index 5e4fe170..8d27d1ff 100644 --- a/dnsforward/config.go +++ b/dnsforward/config.go @@ -214,6 +214,9 @@ func (s *Server) initDefaultSettings() { if s.conf.TCPListenAddr == nil { s.conf.TCPListenAddr = defaultValues.TCPListenAddr } + if len(s.conf.BlockedHosts) == 0 { + s.conf.BlockedHosts = defaultBlockedHosts + } } // prepareUpstreamSettings - prepares upstream DNS server settings diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 39d09a39..0cb645dd 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -31,6 +31,9 @@ var defaultDNS = []string{ } var defaultBootstrap = []string{"9.9.9.10", "149.112.112.10", "2620:fe::10", "2620:fe::fe:10"} +// Often requested by all kinds of DNS probes +var defaultBlockedHosts = []string{"version.bind", "id.server", "hostname.bind"} + var webRegistered bool // Server is the main way to start a DNS server. diff --git a/go.mod b/go.mod index e1d1dfb7..4638e6da 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome go 1.14 require ( - github.com/AdguardTeam/dnsproxy v0.32.1 + github.com/AdguardTeam/dnsproxy v0.32.2 github.com/AdguardTeam/golibs v0.4.2 github.com/AdguardTeam/urlfilter v0.12.2 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 10b294c7..3f4250a7 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AdguardTeam/dnsproxy v0.32.1 h1:UoiFt/aT8YCBFUGe7hG8ehLRXyvoIf22mOQqeIQxhWI= -github.com/AdguardTeam/dnsproxy v0.32.1/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw= +github.com/AdguardTeam/dnsproxy v0.32.2 h1:gD2VojnQEIzWp3fkT20RS9ehyF0MBGGZQdcX/eKM7fQ= +github.com/AdguardTeam/dnsproxy v0.32.2/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= From 67e6b7d3e817fedf63a462fa5caf4bad495dd9ed Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Thu, 10 Sep 2020 18:19:09 +0300 Subject: [PATCH 2/8] * (dnsforward): upgrade dnsproxy to v0.32.4 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4638e6da..8c61faa3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome go 1.14 require ( - github.com/AdguardTeam/dnsproxy v0.32.2 + github.com/AdguardTeam/dnsproxy v0.32.4 github.com/AdguardTeam/golibs v0.4.2 github.com/AdguardTeam/urlfilter v0.12.2 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 3f4250a7..3520b5d8 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AdguardTeam/dnsproxy v0.32.2 h1:gD2VojnQEIzWp3fkT20RS9ehyF0MBGGZQdcX/eKM7fQ= -github.com/AdguardTeam/dnsproxy v0.32.2/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw= +github.com/AdguardTeam/dnsproxy v0.32.4 h1:EsT/5WaKXh3pAAHgt5hKISZNqQwVIbm5e02Z/B0ZVus= +github.com/AdguardTeam/dnsproxy v0.32.4/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= From caee4b86fa4e4c5742427af34a80c8338b7dcd82 Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Thu, 10 Sep 2020 23:54:15 +0300 Subject: [PATCH 3/8] * (dnsforward): upgrade dnsproxy to v0.32.5 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8c61faa3..68944567 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome go 1.14 require ( - github.com/AdguardTeam/dnsproxy v0.32.4 + github.com/AdguardTeam/dnsproxy v0.32.5 github.com/AdguardTeam/golibs v0.4.2 github.com/AdguardTeam/urlfilter v0.12.2 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 3520b5d8..aed6cc4b 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AdguardTeam/dnsproxy v0.32.4 h1:EsT/5WaKXh3pAAHgt5hKISZNqQwVIbm5e02Z/B0ZVus= -github.com/AdguardTeam/dnsproxy v0.32.4/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw= +github.com/AdguardTeam/dnsproxy v0.32.5 h1:UiExd/uHt2UOL4tYg1+WfXXUlkxmlpnMnQiTs63PekQ= +github.com/AdguardTeam/dnsproxy v0.32.5/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= From cb8afde629f272be79782b8e5bee4908ae97eabc Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Fri, 11 Sep 2020 11:53:36 +0300 Subject: [PATCH 4/8] * (dnsforward): fix reverse lookups from /etc/hosts There was a bug with empty PTR responses for IPs that are in the hosts file Closes: #2085 --- dnsforward/dnsforward_test.go | 54 ++++++++++++++-- dnsforward/filter.go | 29 ++++----- util/auto_hosts.go | 118 ++++++++++++++++++---------------- util/auto_hosts_test.go | 4 -- 4 files changed, 125 insertions(+), 80 deletions(-) diff --git a/dnsforward/dnsforward_test.go b/dnsforward/dnsforward_test.go index 664a5c1b..2fb89075 100644 --- a/dnsforward/dnsforward_test.go +++ b/dnsforward/dnsforward_test.go @@ -9,13 +9,17 @@ import ( "crypto/x509/pkix" "encoding/pem" "fmt" + "io/ioutil" "math/big" "net" + "os" "sort" "sync" "testing" "time" + "github.com/AdguardTeam/AdGuardHome/util" + "github.com/AdguardTeam/AdGuardHome/dhcpd" "github.com/AdguardTeam/AdGuardHome/dnsfilter" "github.com/AdguardTeam/dnsproxy/proxy" @@ -664,17 +668,17 @@ func TestBlockedBySafeBrowsing(t *testing.T) { func TestRewrite(t *testing.T) { c := dnsfilter.Config{} c.Rewrites = []dnsfilter.RewriteEntry{ - dnsfilter.RewriteEntry{ + { Domain: "test.com", Answer: "1.2.3.4", Type: dns.TypeA, }, - dnsfilter.RewriteEntry{ + { Domain: "alias.test.com", Answer: "test.com", Type: dns.TypeCNAME, }, - dnsfilter.RewriteEntry{ + { Domain: "my.alias.example.org", Answer: "example.org", Type: dns.TypeCNAME, @@ -1066,7 +1070,7 @@ func (d *testDHCP) SetOnLeaseChanged(onLeaseChanged dhcpd.OnLeaseChangedT) { return } -func TestPTRResponse(t *testing.T) { +func TestPTRResponseFromDHCPLeases(t *testing.T) { dhcp := &testDHCP{} c := dnsfilter.Config{} @@ -1094,3 +1098,45 @@ func TestPTRResponse(t *testing.T) { s.Close() } + +func TestPTRResponseFromHosts(t *testing.T) { + c := dnsfilter.Config{ + AutoHosts: &util.AutoHosts{}, + } + + // Prepare test hosts file + hf, _ := ioutil.TempFile("", "") + defer func() { _ = os.Remove(hf.Name()) }() + defer hf.Close() + + _, _ = hf.WriteString(" 127.0.0.1 host # comment \n") + _, _ = hf.WriteString(" ::1 localhost#comment \n") + + // Init auto hosts + c.AutoHosts.Init(hf.Name()) + defer c.AutoHosts.Close() + + f := dnsfilter.New(&c, nil) + s := NewServer(DNSCreateParams{DNSFilter: f}) + s.conf.UDPListenAddr = &net.UDPAddr{Port: 0} + s.conf.TCPListenAddr = &net.TCPAddr{Port: 0} + s.conf.UpstreamDNS = []string{"127.0.0.1:53"} + s.conf.FilteringConfig.ProtectionEnabled = true + err := s.Prepare(nil) + assert.True(t, err == nil) + assert.Nil(t, s.Start()) + + addr := s.dnsProxy.Addr(proxy.ProtoUDP) + req := createTestMessage("1.0.0.127.in-addr.arpa.") + req.Question[0].Qtype = dns.TypePTR + + resp, err := dns.Exchange(req, addr.String()) + assert.Nil(t, err) + assert.Equal(t, 1, len(resp.Answer)) + assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype) + assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name) + ptr := resp.Answer[0].(*dns.PTR) + assert.Equal(t, "host.", ptr.Ptr) + + s.Close() +} diff --git a/dnsforward/filter.go b/dnsforward/filter.go index 068c5112..4ef3979d 100644 --- a/dnsforward/filter.go +++ b/dnsforward/filter.go @@ -51,7 +51,7 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) { return nil, errorx.Decorate(err, "dnsfilter failed to check host '%s'", host) } else if res.IsFiltered { - // log.Tracef("Host %s is filtered, reason - '%s', matched rule: '%s'", host, res.Reason, res.Rule) + log.Tracef("Host %s is filtered, reason - '%s', matched rule: '%s'", host, res.Reason, res.Rule) d.Res = s.genDNSFilterMessage(d, &res) } else if res.Reason == dnsfilter.ReasonRewrite && len(res.CanonName) != 0 && len(res.IPList) == 0 { @@ -59,6 +59,19 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) { // resolve canonical name, not the original host name d.Req.Question[0].Name = dns.Fqdn(res.CanonName) + } else if res.Reason == dnsfilter.RewriteEtcHosts && len(res.ReverseHost) != 0 { + + resp := s.makeResponse(req) + ptr := &dns.PTR{} + ptr.Hdr = dns.RR_Header{ + Name: req.Question[0].Name, + Rrtype: dns.TypePTR, + Ttl: s.conf.BlockedResponseTTL, + Class: dns.ClassINET, + } + ptr.Ptr = res.ReverseHost + resp.Answer = append(resp.Answer, ptr) + d.Res = resp } else if res.Reason == dnsfilter.ReasonRewrite || res.Reason == dnsfilter.RewriteEtcHosts { resp := s.makeResponse(req) @@ -81,20 +94,6 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) { } d.Res = resp - - } else if res.Reason == dnsfilter.RewriteEtcHosts && len(res.ReverseHost) != 0 { - - resp := s.makeResponse(req) - ptr := &dns.PTR{} - ptr.Hdr = dns.RR_Header{ - Name: req.Question[0].Name, - Rrtype: dns.TypePTR, - Ttl: s.conf.BlockedResponseTTL, - Class: dns.ClassINET, - } - ptr.Ptr = res.ReverseHost - resp.Answer = append(resp.Answer, ptr) - d.Res = resp } return &res, err diff --git a/util/auto_hosts.go b/util/auto_hosts.go index b12acd81..1cec9c1a 100644 --- a/util/auto_hosts.go +++ b/util/auto_hosts.go @@ -10,9 +10,10 @@ import ( "strings" "sync" + "github.com/miekg/dns" + "github.com/AdguardTeam/golibs/log" "github.com/fsnotify/fsnotify" - "github.com/miekg/dns" ) type onChangedT func() @@ -62,6 +63,9 @@ func (a *AutoHosts) Init(hostsFn string) { a.hostsDirs = append(a.hostsDirs, "/tmp/hosts") // OpenWRT: "/tmp/hosts/dhcp.cfg01411c" } + // Load hosts initially + a.updateHosts() + var err error a.watcher, err = fsnotify.NewWatcher() if err != nil { @@ -102,6 +106,62 @@ func (a *AutoHosts) Close() { } } +// Process - get the list of IP addresses for the hostname +// Return nil if not found +func (a *AutoHosts) Process(host string, qtype uint16) []net.IP { + if qtype == dns.TypePTR { + return nil + } + + var ipsCopy []net.IP + a.lock.Lock() + ips, _ := a.table[host] + if len(ips) != 0 { + ipsCopy = make([]net.IP, len(ips)) + copy(ipsCopy, ips) + } + a.lock.Unlock() + + log.Debug("AutoHosts: answer: %s -> %v", host, ipsCopy) + return ipsCopy +} + +// ProcessReverse - process PTR request +// Return "" if not found or an error occurred +func (a *AutoHosts) ProcessReverse(addr string, qtype uint16) string { + if qtype != dns.TypePTR { + return "" + } + + ipReal := DNSUnreverseAddr(addr) + if ipReal == nil { + return "" // invalid IP in question + } + ipStr := ipReal.String() + + a.lock.Lock() + host := a.tableReverse[ipStr] + a.lock.Unlock() + + if len(host) == 0 { + return "" // not found + } + + log.Debug("AutoHosts: reverse-lookup: %s -> %s", addr, host) + return host +} + +// List - get "IP -> hostname" table. Thread-safe. +func (a *AutoHosts) List() map[string]string { + table := make(map[string]string) + a.lock.Lock() + for k, v := range a.tableReverse { + table[k] = v + } + a.lock.Unlock() + return table +} + // update table func (a *AutoHosts) updateTable(table map[string][]net.IP, host string, ipAddr net.IP) { ips, ok := table[host] @@ -275,59 +335,3 @@ func (a *AutoHosts) updateHosts() { a.notify() } - -// Process - get the list of IP addresses for the hostname -// Return nil if not found -func (a *AutoHosts) Process(host string, qtype uint16) []net.IP { - if qtype == dns.TypePTR { - return nil - } - - var ipsCopy []net.IP - a.lock.Lock() - ips, _ := a.table[host] - if len(ips) != 0 { - ipsCopy = make([]net.IP, len(ips)) - copy(ipsCopy, ips) - } - a.lock.Unlock() - - log.Debug("AutoHosts: answer: %s -> %v", host, ipsCopy) - return ipsCopy -} - -// ProcessReverse - process PTR request -// Return "" if not found or an error occurred -func (a *AutoHosts) ProcessReverse(addr string, qtype uint16) string { - if qtype != dns.TypePTR { - return "" - } - - ipReal := DNSUnreverseAddr(addr) - if ipReal == nil { - return "" // invalid IP in question - } - ipStr := ipReal.String() - - a.lock.Lock() - host := a.tableReverse[ipStr] - a.lock.Unlock() - - if len(host) == 0 { - return "" // not found - } - - log.Debug("AutoHosts: reverse-lookup: %s -> %s", addr, host) - return host -} - -// List - get "IP -> hostname" table. Thread-safe. -func (a *AutoHosts) List() map[string]string { - table := make(map[string]string) - a.lock.Lock() - for k, v := range a.tableReverse { - table[k] = v - } - a.lock.Unlock() - return table -} diff --git a/util/auto_hosts_test.go b/util/auto_hosts_test.go index ea2e43ad..efd94b99 100644 --- a/util/auto_hosts_test.go +++ b/util/auto_hosts_test.go @@ -34,9 +34,6 @@ func TestAutoHostsResolution(t *testing.T) { ah.Init(f.Name()) - // Update from the hosts file - ah.updateHosts() - // Existing host ips := ah.Process("localhost", dns.TypeA) assert.NotNil(t, ips) @@ -79,7 +76,6 @@ func TestAutoHostsFSNotify(t *testing.T) { // Init _, _ = f.WriteString(" 127.0.0.1 host localhost \n") ah.Init(f.Name()) - ah.updateHosts() // Unknown host ips := ah.Process("newhost", dns.TypeA) From 8533081da7632cca634e400c5b14b3bf52a55b61 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Fri, 11 Sep 2020 12:06:52 +0300 Subject: [PATCH 5/8] - client: Fix dashboard client names display --- client/src/components/Dashboard/Dashboard.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/src/components/Dashboard/Dashboard.css b/client/src/components/Dashboard/Dashboard.css index 04522ef6..6d3aef7f 100644 --- a/client/src/components/Dashboard/Dashboard.css +++ b/client/src/components/Dashboard/Dashboard.css @@ -26,3 +26,10 @@ left: -20px; width: calc(100% + 20px); } + +@media (max-width: 1279.98px) { + .table__action { + position: absolute; + right: 0; + } +} From b3a68bb806dd16228398a64e66ef08b891cb3f30 Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Fri, 11 Sep 2020 13:19:37 +0300 Subject: [PATCH 6/8] * (global): added --no-mem-optimization flag This commit adds a new command-line argument that disables memory optimizations AGH is using. These memory optimizations might be necessary on low-memory devices, but they aren't free and there's a performance hit (see #2044). Now they can be disabled - just pass --no-mem-optimization when you run AGH or when you install the service -- ./AdGuardHome -s install --no-mem-optimization Closes: #2044 --- home/home.go | 3 +++ home/memory.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ home/options.go | 14 +++++++++++++- main.go | 31 ------------------------------- 4 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 home/memory.go diff --git a/home/home.go b/home/home.go index 898fb4bd..3c2dce58 100644 --- a/home/home.go +++ b/home/home.go @@ -161,6 +161,9 @@ func run(args options) { // configure log level and output configureLogger(args) + // Go memory hacks + memoryUsage(args) + // print the first message after logger is configured log.Println(version()) log.Debug("Current working directory is %s", Context.workDir) diff --git a/home/memory.go b/home/memory.go new file mode 100644 index 00000000..5ca1c12f --- /dev/null +++ b/home/memory.go @@ -0,0 +1,44 @@ +package home + +import ( + "os" + "runtime/debug" + "time" + + "github.com/AdguardTeam/golibs/log" +) + +// memoryUsage implements a couple of not really beautiful hacks which purpose is to +// make OS reclaim the memory freed by AdGuard Home as soon as possible. +// See this for the details on the performance hits & gains: +// https://github.com/AdguardTeam/AdGuardHome/issues/2044#issuecomment-687042211 +func memoryUsage(args options) { + if args.disableMemoryOptimization { + log.Info("Memory optimization is disabled") + return + } + + // Makes Go allocate heap at a slower pace + // By default we keep it at 50% + debug.SetGCPercent(50) + + // madvdontneed: setting madvdontneed=1 will use MADV_DONTNEED + // instead of MADV_FREE on Linux when returning memory to the + // kernel. This is less efficient, but causes RSS numbers to drop + // more quickly. + _ = os.Setenv("GODEBUG", "madvdontneed=1") + + // periodically call "debug.FreeOSMemory" so + // that the OS could reclaim the free memory + go func() { + ticker := time.NewTicker(5 * time.Minute) + for { + select { + case t := <-ticker.C: + t.Second() + log.Debug("Free OS memory") + debug.FreeOSMemory() + } + } + }() +} diff --git a/home/options.go b/home/options.go index 90d356e8..1d8a8a4e 100644 --- a/home/options.go +++ b/home/options.go @@ -24,7 +24,11 @@ type options struct { // runningAsService flag is set to true when options are passed from the service runner runningAsService bool - glinetMode bool // Activate GL-Inet mode + // disableMemoryOptimization - disables memory optimization hacks + // see memoryUsage() function for the details + disableMemoryOptimization bool + + glinetMode bool // Activate GL-Inet compatibility mode } // functions used for their side-effects @@ -151,6 +155,13 @@ var noCheckUpdateArg = arg{ func(o options) []string { return boolSliceOrNil(o.disableUpdate) }, } +var disableMemoryOptimizationArg = arg{ + "Disable memory optimization", + "no-mem-optimization", "", + nil, func(o options) (options, error) { o.disableMemoryOptimization = true; return o, nil }, nil, + func(o options) []string { return boolSliceOrNil(o.disableMemoryOptimization) }, +} + var verboseArg = arg{ "Enable verbose output", "verbose", "v", @@ -194,6 +205,7 @@ func init() { pidfileArg, checkConfigArg, noCheckUpdateArg, + disableMemoryOptimizationArg, verboseArg, glinetArg, versionArg, diff --git a/main.go b/main.go index eebcd5c4..f712d6c0 100644 --- a/main.go +++ b/main.go @@ -4,10 +4,6 @@ package main import ( - "os" - "runtime/debug" - "time" - "github.com/AdguardTeam/AdGuardHome/home" ) @@ -21,32 +17,5 @@ var channel = "release" var goarm = "" func main() { - memoryUsage() - home.Main(version, channel, goarm) } - -// memoryUsage implements a couple of not really beautiful hacks which purpose is to -// make OS reclaim the memory freed by AdGuard Home as soon as possible. -func memoryUsage() { - debug.SetGCPercent(10) - - // madvdontneed: setting madvdontneed=1 will use MADV_DONTNEED - // instead of MADV_FREE on Linux when returning memory to the - // kernel. This is less efficient, but causes RSS numbers to drop - // more quickly. - _ = os.Setenv("GODEBUG", "madvdontneed=1") - - // periodically call "debug.FreeOSMemory" so - // that the OS could reclaim the free memory - go func() { - ticker := time.NewTicker(15 * time.Second) - for { - select { - case t := <-ticker.C: - t.Second() - debug.FreeOSMemory() - } - } - }() -} From 1c88667306e7a52d36a6a1cbf3eca86fd612bd7f Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Fri, 11 Sep 2020 13:21:37 +0300 Subject: [PATCH 7/8] * (home): added tests for no-mem-optimization flag --- home/options_test.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/home/options_test.go b/home/options_test.go index 5a2b1155..afaa873f 100644 --- a/home/options_test.go +++ b/home/options_test.go @@ -140,6 +140,15 @@ func TestParseDisableUpdate(t *testing.T) { } } +func TestParseDisableMemoryOptimization(t *testing.T) { + if testParseOk(t).disableMemoryOptimization { + t.Fatal("empty is not disable update") + } + if !testParseOk(t, "--no-mem-optimization").disableMemoryOptimization { + t.Fatal("--no-mem-optimization is disable update") + } +} + func TestParseService(t *testing.T) { if testParseOk(t).serviceControlAction != "" { t.Fatal("empty is no service command") @@ -226,12 +235,17 @@ func TestSerializeGLInet(t *testing.T) { testSerialize(t, options{glinetMode: true}, "--glinet") } +func TestSerializeDisableMemoryOptimization(t *testing.T) { + testSerialize(t, options{disableMemoryOptimization: true}, "--no-mem-optimization") +} + func TestSerializeMultiple(t *testing.T) { testSerialize(t, options{ - serviceControlAction: "run", - configFilename: "config", - workDir: "work", - pidFile: "pid", - disableUpdate: true, - }, "-c", "config", "-w", "work", "-s", "run", "--pidfile", "pid", "--no-check-update") + serviceControlAction: "run", + configFilename: "config", + workDir: "work", + pidFile: "pid", + disableUpdate: true, + disableMemoryOptimization: true, + }, "-c", "config", "-w", "work", "-s", "run", "--pidfile", "pid", "--no-check-update", "--no-mem-optimization") } From 2a5b0b8da1f85727e36a4601c51bdfb79ef2583f Mon Sep 17 00:00:00 2001 From: Artem Baskal Date: Mon, 14 Sep 2020 20:16:46 +0300 Subject: [PATCH 8/8] - client: Allow change minimum TTL override in UI Close #2091 #2094 #2056 Squashed commit of the following: commit a84384bb409bfe60c4bd6477b2249c4431aa3b63 Merge: cdc5f27f a22db5f3 Author: ArtemBaskal Date: Mon Sep 14 19:59:47 2020 +0300 Merge branch 'master' into fix/2091 commit cdc5f27f279f33c7d988f2927adc172e77e0a6af Author: ArtemBaskal Date: Mon Sep 14 15:41:00 2020 +0300 Fix uint32 fields validation commit 0c6fcb90f9741ae8a33bf6c4d53bd954f2033a88 Author: ArtemBaskal Date: Mon Sep 14 14:43:20 2020 +0300 Validate DNS cache configuration DNS values unit32 range commit 1f90a1fcbc04f6c7ffb75b453e5c67e117d1c5bf Author: ArtemBaskal Date: Mon Sep 14 12:11:39 2020 +0300 Remove the limit on cache-min-ttl commit 72e961034cc5752a50a4afc57c7be6a93d652f7d Author: ArtemBaskal Date: Fri Sep 11 16:50:19 2020 +0300 Fix translation commit 6aebf4b87bb806ac0729b40418ba6056b3f71afa Author: ArtemBaskal Date: Fri Sep 11 12:53:01 2020 +0300 - client: Allow change minimum TTL override in UI --- client/src/__locales/en.json | 7 +- .../components/Settings/Dhcp/FormDHCPv4.js | 8 +-- .../components/Settings/Dhcp/FormDHCPv6.js | 13 ++-- .../src/components/Settings/Dns/Cache/Form.js | 65 +++++++++---------- .../components/Settings/Dns/Cache/index.js | 11 ++++ .../components/Settings/Dns/Config/Form.js | 7 +- client/src/helpers/constants.js | 13 +++- client/src/helpers/validators.js | 23 ------- 8 files changed, 69 insertions(+), 78 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index ece13f64..a5e0208b 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -253,7 +253,7 @@ "rate_limit": "Rate limit", "edns_enable": "Enable EDNS Client Subnet", "edns_cs_desc": "If enabled, AdGuard Home will be sending clients' subnets to the DNS servers.", - "rate_limit_desc": "The number of requests per second that a single client is allowed to make (0: unlimited)", + "rate_limit_desc": "The number of requests per second that a single client is allowed to make (setting it to 0 means unlimited)", "blocking_ipv4_desc": "IP address to be returned for a blocked A request", "blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request", "blocking_mode_default": "Default: Respond with REFUSED when blocked by Adblock-style rule; respond with the IP address specified in the rule when blocked by /etc/hosts-style rule", @@ -564,10 +564,9 @@ "enter_cache_size": "Enter cache size", "enter_cache_ttl_min_override": "Enter minimum TTL", "enter_cache_ttl_max_override": "Enter maximum TTL", - "cache_ttl_min_override_desc": "Override TTL value (minimum) received from upstream server. This value can't larger than 3600 (1 hour)", + "cache_ttl_min_override_desc": "Override TTL value (minimum) received from upstream server", "cache_ttl_max_override_desc": "Override TTL value (maximum) received from upstream server", - "min_exceeds_max_value": "Minimum value exceeds maximum value", - "value_not_larger_than": "Value can't be larger than {{maximum}}", + "ttl_cache_validation": "Minimum cache TTL value must be less than or equal to the maximum value", "filter_category_general": "General", "filter_category_security": "Security", "filter_category_regional": "Regional", diff --git a/client/src/components/Settings/Dhcp/FormDHCPv4.js b/client/src/components/Settings/Dhcp/FormDHCPv4.js index b938b6f0..873e7696 100644 --- a/client/src/components/Settings/Dhcp/FormDHCPv4.js +++ b/client/src/components/Settings/Dhcp/FormDHCPv4.js @@ -8,10 +8,9 @@ import { renderInputField, toNumber, } from '../../../helpers/form'; -import { FORM_NAME } from '../../../helpers/constants'; +import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants'; import { validateIpv4, - validateIsPositiveValue, validateRequiredValue, validateIpv4RangeEnd, } from '../../../helpers/validators'; @@ -110,9 +109,10 @@ const FormDHCPv4 = ({ type="number" className="form-control" placeholder={t(ipv4placeholders.lease_duration)} - validate={[validateIsPositiveValue, validateRequired]} + validate={validateRequired} normalize={toNumber} - min={0} + min={1} + max={UINT32_RANGE.MAX} disabled={!isInterfaceIncludesIpv4} /> diff --git a/client/src/components/Settings/Dhcp/FormDHCPv6.js b/client/src/components/Settings/Dhcp/FormDHCPv6.js index 80219fd6..e37a6213 100644 --- a/client/src/components/Settings/Dhcp/FormDHCPv6.js +++ b/client/src/components/Settings/Dhcp/FormDHCPv6.js @@ -8,12 +8,8 @@ import { renderInputField, toNumber, } from '../../../helpers/form'; -import { FORM_NAME } from '../../../helpers/constants'; -import { - validateIpv6, - validateIsPositiveValue, - validateRequiredValue, -} from '../../../helpers/validators'; +import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants'; +import { validateIpv6, validateRequiredValue } from '../../../helpers/validators'; const FormDHCPv6 = ({ handleSubmit, @@ -86,9 +82,10 @@ const FormDHCPv6 = ({ type="number" className="form-control" placeholder={t(ipv6placeholders.lease_duration)} - validate={[validateIsPositiveValue, validateRequired]} + validate={validateRequired} normalizeOnBlur={toNumber} - min={0} + min={1} + max={UINT32_RANGE.MAX} disabled={!isInterfaceIncludesIpv6} /> diff --git a/client/src/components/Settings/Dns/Cache/Form.js b/client/src/components/Settings/Dns/Cache/Form.js index c7b2d6ed..f17310c9 100644 --- a/client/src/components/Settings/Dns/Cache/Form.js +++ b/client/src/components/Settings/Dns/Cache/Form.js @@ -4,32 +4,30 @@ import { Field, reduxForm } from 'redux-form'; import { Trans, useTranslation } from 'react-i18next'; import { shallowEqual, useSelector } from 'react-redux'; import { renderInputField, toNumber } from '../../../../helpers/form'; -import { validateBiggerOrEqualZeroValue, getMaxValueValidator, validateRequiredValue } from '../../../../helpers/validators'; -import { FORM_NAME, SECONDS_IN_HOUR } from '../../../../helpers/constants'; +import { validateRequiredValue } from '../../../../helpers/validators'; +import { CACHE_CONFIG_FIELDS, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants'; -const validateMaxValue3600 = getMaxValueValidator(SECONDS_IN_HOUR); - -const getInputFields = ({ validateRequiredValue, validateMaxValue3600 }) => [{ - name: 'cache_size', - title: 'cache_size', - description: 'cache_size_desc', - placeholder: 'enter_cache_size', - validate: validateRequiredValue, -}, -{ - name: 'cache_ttl_min', - title: 'cache_ttl_min_override', - description: 'cache_ttl_min_override_desc', - placeholder: 'enter_cache_ttl_min_override', - max: SECONDS_IN_HOUR, - validate: validateMaxValue3600, -}, -{ - name: 'cache_ttl_max', - title: 'cache_ttl_max_override', - description: 'cache_ttl_max_override_desc', - placeholder: 'enter_cache_ttl_max_override', -}]; +const getInputFields = (validateRequiredValue) => [ + { + name: CACHE_CONFIG_FIELDS.cache_size, + title: 'cache_size', + description: 'cache_size_desc', + placeholder: 'enter_cache_size', + validate: validateRequiredValue, + }, + { + name: CACHE_CONFIG_FIELDS.cache_ttl_min, + title: 'cache_ttl_min_override', + description: 'cache_ttl_min_override_desc', + placeholder: 'enter_cache_ttl_min_override', + }, + { + name: CACHE_CONFIG_FIELDS.cache_ttl_max, + title: 'cache_ttl_max_override', + description: 'cache_ttl_max_override_desc', + placeholder: 'enter_cache_ttl_max_override', + }, +]; const Form = ({ handleSubmit, submitting, invalid, @@ -41,17 +39,16 @@ const Form = ({ cache_ttl_max, cache_ttl_min, } = useSelector((state) => state.form[FORM_NAME.CACHE].values, shallowEqual); - const minExceedsMax = cache_ttl_min > cache_ttl_max; + const minExceedsMax = typeof cache_ttl_min === 'number' + && typeof cache_ttl_max === 'number' + && cache_ttl_min > cache_ttl_max; - const INPUTS_FIELDS = getInputFields({ - validateRequiredValue, - validateMaxValue3600, - }); + const INPUTS_FIELDS = getInputFields(validateRequiredValue); return
{INPUTS_FIELDS.map(({ - name, title, description, placeholder, validate, max, + name, title, description, placeholder, validate, min = 0, max = UINT32_RANGE.MAX, }) =>
@@ -66,15 +63,15 @@ const Form = ({ disabled={processingSetConfig} normalize={toNumber} className="form-control" - validate={[validateBiggerOrEqualZeroValue].concat(validate || [])} - min={0} + validate={validate} + min={min} max={max} />
)} {minExceedsMax - && {t('min_exceeds_max_value')}} + && {t('ttl_cache_validation')}}