Pull request: 1333-protection-pause vol.1

Merge in DNS/adguard-home from 1333-protection-pause-1 to master

Squashed commit of the following:

commit 5ff98385bc5ff66e214d80782eb4dc41e344aa38
Merge: 97f94a54 0bc3ef89
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Mar 24 19:08:21 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

commit 97f94a5498ac221f88f2f7dfef4b255f4945329e
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Fri Mar 24 13:03:20 2023 +0200

    Fix protection timer bugs

commit 1cc61af1996bd803f3fa638cb9e2388470072bf0
Merge: 5a144ea3 235ce458
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 22:27:47 2023 +0700

    Merge remote-tracking branch 'origin/1333-protection-pause-1' into 1333-protection-pause-1

commit 5a144ea3a48c3d0d5e57dd14232ab7a8e77a8c1e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 22:25:08 2023 +0700

    dnsforward: imp code

commit 235ce458a62b3152f36e32580ed0226a56580ec6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Mar 23 17:35:06 2023 +0300

    dnsforward: imp locks

commit 0ea3a0a176b810a2b3f0b307aa406fe1670c9219
Merge: 52f66810 df61741f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 19:30:41 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md
    #	openapi/CHANGELOG.md

commit 52f668109673286a50909c042e6352cd803e8eed
Merge: 9a7eb7b3 306c1983
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 11:23:50 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md
    #	internal/dnsforward/http.go

commit 9a7eb7b3ab2b5f6ad321aa3245d33839c3aa6fbd
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Wed Mar 22 06:56:55 2023 +0200

    Review fix

commit 5612d51252ba91842bd6811baec1c91136bb3bf2
Merge: c0a918a5 c3edab43
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Mar 21 22:00:39 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	client/src/__locales/en.json

commit c0a918a518ad9b37041aed159d215516258bc987
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Tue Mar 21 12:13:18 2023 +0200

    Review fix

commit 34faa61cc1e6210a612e7a2f4895a1504df37680
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Tue Mar 21 10:43:37 2023 +0200

    Fix props to new api

commit 158e582373863495f0e0ca177d7b365cc66ad671
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Mon Mar 20 18:44:34 2023 +0200

    Review fix

commit 9e8b8c3778b8e1dfad0d39e44f70886dfd3aeb9a
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Mar 20 22:31:28 2023 +0700

    all: docs

commit 761a203f53b535ca235cfe62f289bd0e02b90be2
Merge: d0b07231 48431f8b
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Mar 20 22:26:13 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

commit d0b07231b6f29b534930f1fcfc82b4934c295ff8
Merge: ea448760 a2053526
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Mar 13 13:00:52 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md
    #	client/src/components/App/index.css
    #	internal/dnsforward/config.go

commit ea4487608a9c81d25f155ff63fee7c9dcf21f448
Merge: dfd0f33f a556ce8f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Feb 21 11:54:27 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md

commit dfd0f33fb474d497cbc9237ee466276728eea397
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Feb 21 11:51:40 2023 +0700

    all: docs

commit d36df96fba8c6d923faef85c198b6bd0743b7ee8
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Feb 20 12:41:49 2023 +0700

    all: safesearch

commit 60f2ceec563221337f34bb60baa96aa2b2429c40
Merge: 7c514427 6f6ced33
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Feb 20 12:30:42 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md

commit 7c514427e77c5b09d8e148c78220a71046e68cd1
Merge: 0fa4ff99 4d295a38
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Feb 16 11:55:21 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md

... and 26 more commits
This commit is contained in:
Dimitry Kolyshev
2023-03-24 15:11:47 +03:00
parent 0bc3ef89ea
commit 9c48e96939
23 changed files with 528 additions and 46 deletions

View File

@@ -81,6 +81,10 @@ type FilteringConfig struct {
// 0, then default value is used (3600).
BlockedResponseTTL uint32 `yaml:"blocked_response_ttl"`
// ProtectionDisabledUntil is the timestamp until when the protection is
// disabled.
ProtectionDisabledUntil *time.Time `yaml:"protection_disabled_until"`
// ParentalBlockHost is the IP (or domain name) which is used to respond to
// DNS requests blocked by parental control.
ParentalBlockHost string `yaml:"parental_block_host"`
@@ -635,3 +639,33 @@ func (s *Server) onGetCertificate(ch *tls.ClientHelloInfo) (*tls.Certificate, er
}
return &s.conf.cert, nil
}
// UpdatedProtectionStatus updates protection state, if the protection was
// disabled temporarily. Returns the updated state of protection.
func (s *Server) UpdatedProtectionStatus() (enabled bool) {
changed := false
defer func() {
if changed {
log.Info("dns: protection is restarted after pause")
s.conf.ConfigModified()
}
}()
s.serverLock.Lock()
defer s.serverLock.Unlock()
disabledUntil := s.conf.ProtectionDisabledUntil
if disabledUntil == nil {
return s.conf.ProtectionEnabled
}
if time.Now().Before(*disabledUntil) {
return false
}
s.conf.ProtectionEnabled = true
s.conf.ProtectionDisabledUntil = nil
changed = true
return true
}

View File

@@ -191,7 +191,7 @@ func (s *Server) processInitial(dctx *dnsContext) (rc resultCode) {
dctx.clientID = string(s.clientIDCache.Get(key[:]))
// Get the client-specific filtering settings.
dctx.protectionEnabled = s.conf.ProtectionEnabled
dctx.protectionEnabled = s.UpdatedProtectionStatus()
dctx.setts = s.getClientRequestFilteringSettings(dctx)
return resultCodeSuccess

View File

@@ -88,6 +88,9 @@ type jsonDNSConfig struct {
// BlockingIPv6 is custom IPv6 address for blocked AAAA requests.
BlockingIPv6 net.IP `json:"blocking_ipv6"`
// DisabledUntil is a timestamp until when the protection is disabled.
DisabledUntil *time.Time `json:"protection_disabled_until"`
// EDNSCSCustomIP is custom IP for EDNS Client Subnet.
EDNSCSCustomIP netip.Addr `json:"edns_cs_custom_ip"`
@@ -98,13 +101,14 @@ type jsonDNSConfig struct {
}
func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
protectionEnabled := s.UpdatedProtectionStatus()
s.serverLock.RLock()
defer s.serverLock.RUnlock()
upstreams := stringutil.CloneSliceOrEmpty(s.conf.UpstreamDNS)
upstreamFile := s.conf.UpstreamDNSFileName
bootstraps := stringutil.CloneSliceOrEmpty(s.conf.BootstrapDNS)
protectionEnabled := s.conf.ProtectionEnabled
blockingMode := s.conf.BlockingMode
blockingIPv4 := s.conf.BlockingIPv4
blockingIPv6 := s.conf.BlockingIPv6
@@ -123,6 +127,13 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
resolveClients := s.conf.ResolveClients
usePrivateRDNS := s.conf.UsePrivateRDNS
localPTRUpstreams := stringutil.CloneSliceOrEmpty(s.conf.LocalPTRResolvers)
var disabledUntil *time.Time
if s.conf.ProtectionDisabledUntil != nil {
t := *s.conf.ProtectionDisabledUntil
disabledUntil = &t
}
var upstreamMode string
if s.conf.FastestAddr {
upstreamMode = "fastest_addr"
@@ -158,6 +169,7 @@ func (s *Server) getDNSConfig() (c *jsonDNSConfig) {
UsePrivateRDNS: &usePrivateRDNS,
LocalPTRUpstreams: &localPTRUpstreams,
DefaultLocalPTRUpstreams: defLocalPTRUps,
DisabledUntil: disabledUntil,
}
}
@@ -741,6 +753,52 @@ func (s *Server) handleCacheClear(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, "OK")
}
// protectionJSON is an object for /control/protection endpoint.
type protectionJSON struct {
Enabled bool `json:"enabled"`
Duration uint `json:"duration"`
}
// handleSetProtection is a handler for the POST /control/protection HTTP API.
func (s *Server) handleSetProtection(w http.ResponseWriter, r *http.Request) {
protectionReq := &protectionJSON{}
err := json.NewDecoder(r.Body).Decode(protectionReq)
if err != nil {
aghhttp.Error(r, w, http.StatusBadRequest, "reading req: %s", err)
return
}
var disabledUntil *time.Time
if protectionReq.Duration > 0 {
if protectionReq.Enabled {
aghhttp.Error(
r,
w,
http.StatusBadRequest,
"Setting a duration is only allowed with protection disabling",
)
return
}
calcTime := time.Now().Add(time.Duration(protectionReq.Duration) * time.Millisecond)
disabledUntil = &calcTime
}
func() {
s.serverLock.Lock()
defer s.serverLock.Unlock()
s.conf.ProtectionEnabled = protectionReq.Enabled
s.conf.ProtectionDisabledUntil = disabledUntil
}()
s.conf.ConfigModified()
aghhttp.OK(w)
}
// handleDoH is the DNS-over-HTTPs handler.
//
// Control flow:
@@ -775,6 +833,7 @@ func (s *Server) registerHandlers() {
s.conf.HTTPRegister(http.MethodGet, "/control/dns_info", s.handleGetConfig)
s.conf.HTTPRegister(http.MethodPost, "/control/dns_config", s.handleSetConfig)
s.conf.HTTPRegister(http.MethodPost, "/control/test_upstream_dns", s.handleTestUpstreamDNS)
s.conf.HTTPRegister(http.MethodPost, "/control/protection", s.handleSetProtection)
s.conf.HTTPRegister(http.MethodGet, "/control/access/list", s.handleAccessList)
s.conf.HTTPRegister(http.MethodPost, "/control/access/set", s.handleAccessSet)

View File

@@ -12,6 +12,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -43,6 +44,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -74,6 +76,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",

View File

@@ -19,6 +19,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -54,6 +55,7 @@
"9.9.9.10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -90,6 +92,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "refused",
"blocking_ipv4": "",
@@ -126,6 +129,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -162,6 +166,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 6,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -198,6 +203,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -236,6 +242,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -274,6 +281,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -310,6 +318,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -346,6 +355,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -382,6 +392,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -418,6 +429,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -456,6 +468,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -494,6 +507,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -531,6 +545,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -567,6 +582,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -605,6 +621,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -646,6 +663,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",
@@ -682,6 +700,7 @@
"2620:fe::fe:10"
],
"protection_enabled": true,
"protection_disabled_until": null,
"ratelimit": 0,
"blocking_mode": "default",
"blocking_ipv4": "",

View File

@@ -103,6 +103,8 @@ type statusResponse struct {
DNSPort int `json:"dns_port"`
HTTPPort int `json:"http_port"`
IsProtectionEnabled bool `json:"protection_enabled"`
// ProtectionDisabledDuration is a pause duration in milliseconds.
ProtectionDisabledDuration int64 `json:"protection_disabled_duration"`
// TODO(e.burkov): Inspect if front-end doesn't requires this field as
// openapi.yaml declares.
IsDHCPAvailable bool `json:"dhcp_available"`
@@ -119,28 +121,36 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
return
}
isProtectionEnabled := false
var c *dnsforward.FilteringConfig
if Context.dnsServer != nil {
c = &dnsforward.FilteringConfig{}
Context.dnsServer.WriteDiskConfig(c)
isProtectionEnabled = Context.dnsServer.UpdatedProtectionStatus()
}
var resp statusResponse
func() {
config.RLock()
defer config.RUnlock()
var pauseDuration int64
if until := config.DNS.ProtectionDisabledUntil; until != nil {
pauseDuration = time.Until(*until).Milliseconds()
}
resp = statusResponse{
Version: version.Version(),
DNSAddrs: dnsAddrs,
DNSPort: config.DNS.Port,
HTTPPort: config.BindPort,
Language: config.Language,
IsRunning: isRunning(),
Version: version.Version(),
DNSAddrs: dnsAddrs,
DNSPort: config.DNS.Port,
HTTPPort: config.BindPort,
Language: config.Language,
IsRunning: isRunning(),
ProtectionDisabledDuration: pauseDuration,
IsProtectionEnabled: isProtectionEnabled,
}
}()
var c *dnsforward.FilteringConfig
if Context.dnsServer != nil {
c = &dnsforward.FilteringConfig{}
Context.dnsServer.WriteDiskConfig(c)
resp.IsProtectionEnabled = c.ProtectionEnabled
}
// IsDHCPAvailable field is now false by default for Windows.
if runtime.GOOS != "windows" {
resp.IsDHCPAvailable = Context.dhcpServer != nil