From e1995408e435fc8bb9984a89290d276f6483b8e1 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Fri, 24 Nov 2023 15:20:32 +0300 Subject: [PATCH] Pull request: 6263 custom ups cache Updates #6263. Squashed commit of the following: commit f6b704fb58bb341b7fe9432fce823d7b3bf3ec9e Merge: 780d001ce 5dd10d9fc Author: Dimitry Kolyshev Date: Fri Nov 24 09:55:04 2023 +0200 Merge remote-tracking branch 'origin/master' into 6263-custom-ups-cache commit 780d001cef93ee5c4e45b55f5ae17f8ba1e01a50 Author: Dimitry Kolyshev Date: Fri Nov 24 09:53:46 2023 +0200 all: imp locales commit 820bcf0e2332408a218fb12bec4e299871608756 Merge: e7ca51563 1320043e9 Author: Dimitry Kolyshev Date: Thu Nov 23 11:16:54 2023 +0200 Merge remote-tracking branch 'origin/master' into 6263-custom-ups-cache # Conflicts: # CHANGELOG.md commit e7ca515630bb7a543cd94460c5b063e5e4ab7aff Merge: 23392d08b 0f5e8ca56 Author: Dimitry Kolyshev Date: Wed Nov 22 09:49:32 2023 +0200 Merge remote-tracking branch 'origin/master' into 6263-custom-ups-cache commit 23392d08b13a5c339a8f1e2be266a7a35dd093d4 Merge: a09cd190c feb15745d Author: Dimitry Kolyshev Date: Wed Nov 22 09:49:10 2023 +0200 Merge remote-tracking branch 'origin/6263-custom-ups-cache' into 6263-custom-ups-cache commit a09cd190c03cb65ce6eece7582d72ad73920415e Author: Dimitry Kolyshev Date: Wed Nov 22 09:48:43 2023 +0200 home: imp code commit feb15745d2e867e360cd97de6763a668d6921158 Author: Ildar Kamalov Date: Tue Nov 21 17:27:38 2023 +0300 client: move cache fields to the upstream tab commit 789060e4d439a7d32b606625353c826c61a1db85 Author: Ildar Kamalov Date: Tue Nov 21 16:28:03 2023 +0300 client: add form fields commit a700bfb42e94a03ecc8abefb12e77548a201cb28 Merge: 7669419b5 db42254d7 Author: Dimitry Kolyshev Date: Tue Nov 21 11:44:14 2023 +0200 Merge remote-tracking branch 'origin/master' into 6263-custom-ups-cache commit 7669419b5981bf456af13b9374474c4a932d7c00 Author: Dimitry Kolyshev Date: Tue Nov 21 11:34:17 2023 +0200 home: imp code commit 4a9dc1d6c1f3dfe56737f482becdfe465189d444 Author: Dimitry Kolyshev Date: Mon Nov 20 15:08:44 2023 +0200 docs: http client docs commit 944e0d7a4be3313f360ddace8bd7e0080512ddf8 Author: Dimitry Kolyshev Date: Mon Nov 20 13:51:00 2023 +0200 home: http client dns cache --- CHANGELOG.md | 4 + client/src/__locales/en.json | 5 +- .../Clients/ClientsTable/ClientsTable.js | 4 + .../src/components/Settings/Clients/Form.js | 38 ++++- internal/home/client.go | 1 + internal/home/clientshttp.go | 142 +++++++++++------- openapi/CHANGELOG.md | 12 ++ openapi/openapi.yaml | 19 +++ 8 files changed, 165 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4c041aa..04d41bf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ NOTE: Add new changes BELOW THIS COMMENT. ### Added +- Ability to set client's custom DNS cache ([#6362], [dnsproxy#169]). - Ability to disable plain-DNS serving through configuration file if an encrypted protocol is already used ([#1660]). - Ability to specify rate limiting settings in the Web UI ([#6369]). @@ -48,10 +49,13 @@ NOTE: Add new changes BELOW THIS COMMENT. [#1660]: https://github.com/AdguardTeam/AdGuardHome/issues/1660 [#5759]: https://github.com/AdguardTeam/AdGuardHome/issues/5759 +[#6362]: https://github.com/AdguardTeam/AdGuardHome/issues/6362 [#6369]: https://github.com/AdguardTeam/AdGuardHome/issues/6369 [#6402]: https://github.com/AdguardTeam/AdGuardHome/issues/6402 [#6420]: https://github.com/AdguardTeam/AdGuardHome/issues/6420 +[dnsproxy#169] https://github.com/AdguardTeam/dnsproxy/issues/169 + diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index e75c1259..a5839c0f 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -734,5 +734,8 @@ "wednesday_short": "Wed", "thursday_short": "Thu", "friday_short": "Fri", - "saturday_short": "Sat" + "saturday_short": "Sat", + "upstream_dns_cache_configuration": "Upstream DNS cache configuration", + "enable_upstream_dns_cache": "Enable DNS caching for this client's custom upstream configuration", + "dns_cache_size": "DNS cache size, in bytes" } diff --git a/client/src/components/Settings/Clients/ClientsTable/ClientsTable.js b/client/src/components/Settings/Clients/ClientsTable/ClientsTable.js index 9f65986f..f4744a5a 100644 --- a/client/src/components/Settings/Clients/ClientsTable/ClientsTable.js +++ b/client/src/components/Settings/Clients/ClientsTable/ClientsTable.js @@ -79,6 +79,10 @@ const ClientsTable = ({ } else { config.tags = []; } + + if (typeof values.upstreams_cache_size === 'string') { + config.upstreams_cache_size = 0; + } } if (modalType === MODAL_TYPE.EDIT_FILTERS) { diff --git a/client/src/components/Settings/Clients/Form.js b/client/src/components/Settings/Clients/Form.js index 652957d0..ba4ec4b3 100644 --- a/client/src/components/Settings/Clients/Form.js +++ b/client/src/components/Settings/Clients/Form.js @@ -12,8 +12,13 @@ import i18n from '../../../i18n'; import Tabs from '../../ui/Tabs'; import Examples from '../Dns/Upstream/Examples'; import { ScheduleForm } from '../../Filters/Services/ScheduleForm'; -import { toggleAllServices, trimLinesAndRemoveEmpty, captitalizeWords } from '../../../helpers/helpers'; import { + toggleAllServices, + trimLinesAndRemoveEmpty, + captitalizeWords, +} from '../../../helpers/helpers'; +import { + toNumber, renderInputField, renderGroupField, CheckboxField, @@ -21,7 +26,7 @@ import { renderTextareaField, } from '../../../helpers/form'; import { validateClientId, validateRequiredValue } from '../../../helpers/validators'; -import { CLIENT_ID_LINK, FORM_NAME } from '../../../helpers/constants'; +import { CLIENT_ID_LINK, FORM_NAME, UINT32_RANGE } from '../../../helpers/constants'; import './Service.css'; const settingsCheckboxes = [ @@ -307,6 +312,35 @@ let Form = (props) => { normalizeOnBlur={trimLinesAndRemoveEmpty} /> +
+ {t('upstream_dns_cache_configuration')} +
+
+ +
+
+ + +
, }, }; diff --git a/internal/home/client.go b/internal/home/client.go index 49260ed9..70ce112e 100644 --- a/internal/home/client.go +++ b/internal/home/client.go @@ -20,6 +20,7 @@ type Client struct { // upstream must be used. upstreamConfig *proxy.CustomUpstreamConfig + // TODO(d.kolyshev): Make safeSearchConf a pointer. safeSearchConf filtering.SafeSearchConfig SafeSearch filtering.SafeSearch diff --git a/internal/home/clientshttp.go b/internal/home/clientshttp.go index d6fc2fc9..ad51e944 100644 --- a/internal/home/clientshttp.go +++ b/internal/home/clientshttp.go @@ -56,34 +56,9 @@ type clientJSON struct { IgnoreQueryLog aghalg.NullBool `json:"ignore_querylog"` IgnoreStatistics aghalg.NullBool `json:"ignore_statistics"` -} -// copySettings returns a copy of specific settings from JSON or a previous -// client. -func (j *clientJSON) copySettings( - prev *Client, -) (weekly *schedule.Weekly, ignoreQueryLog, ignoreStatistics bool) { - if j.Schedule != nil { - weekly = j.Schedule.Clone() - } else if prev != nil && prev.BlockedServices != nil { - weekly = prev.BlockedServices.Schedule.Clone() - } else { - weekly = schedule.EmptyWeekly() - } - - if j.IgnoreQueryLog != aghalg.NBNull { - ignoreQueryLog = j.IgnoreQueryLog == aghalg.NBTrue - } else if prev != nil { - ignoreQueryLog = prev.IgnoreQueryLog - } - - if j.IgnoreStatistics != aghalg.NBNull { - ignoreStatistics = j.IgnoreStatistics == aghalg.NBTrue - } else if prev != nil { - ignoreStatistics = prev.IgnoreStatistics - } - - return weekly, ignoreQueryLog, ignoreStatistics + UpstreamsCacheSize uint32 `json:"upstreams_cache_size"` + UpstreamsCacheEnabled aghalg.NullBool `json:"upstreams_cache_enabled"` } type runtimeClientJSON struct { @@ -142,42 +117,35 @@ func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, r *http // jsonToClient converts JSON object to Client object. func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *Client, err error) { - var safeSearchConf filtering.SafeSearchConfig - if cj.SafeSearchConf != nil { - safeSearchConf = *cj.SafeSearchConf - } else { - // TODO(d.kolyshev): Remove after cleaning the deprecated - // [clientJSON.SafeSearchEnabled] field. - safeSearchConf = filtering.SafeSearchConfig{ - Enabled: cj.SafeSearchEnabled, - } + safeSearchConf := copySafeSearch(cj.SafeSearchConf, cj.SafeSearchEnabled) - // Set default service flags for enabled safesearch. - if safeSearchConf.Enabled { - safeSearchConf.Bing = true - safeSearchConf.DuckDuckGo = true - safeSearchConf.Google = true - safeSearchConf.Pixabay = true - safeSearchConf.Yandex = true - safeSearchConf.YouTube = true - } + var ignoreQueryLog bool + if cj.IgnoreQueryLog != aghalg.NBNull { + ignoreQueryLog = cj.IgnoreQueryLog == aghalg.NBTrue + } else if prev != nil { + ignoreQueryLog = prev.IgnoreQueryLog } - weekly, ignoreQueryLog, ignoreStatistics := cj.copySettings(prev) - - bs := &filtering.BlockedServices{ - Schedule: weekly, - IDs: cj.BlockedServices, - } - err = bs.Validate() - if err != nil { - return nil, fmt.Errorf("validating blocked services: %w", err) + var ignoreStatistics bool + if cj.IgnoreStatistics != aghalg.NBNull { + ignoreStatistics = cj.IgnoreStatistics == aghalg.NBTrue + } else if prev != nil { + ignoreStatistics = prev.IgnoreStatistics } var upsCacheEnabled bool var upsCacheSize uint32 - if prev != nil { - upsCacheEnabled, upsCacheSize = prev.UpstreamsCacheEnabled, prev.UpstreamsCacheSize + if cj.UpstreamsCacheEnabled != aghalg.NBNull { + upsCacheEnabled = cj.UpstreamsCacheEnabled == aghalg.NBTrue + upsCacheSize = cj.UpstreamsCacheSize + } else if prev != nil { + upsCacheEnabled = prev.UpstreamsCacheEnabled + upsCacheSize = prev.UpstreamsCacheSize + } + + svcs, err := copyBlockedServices(cj.Schedule, cj.BlockedServices, prev) + if err != nil { + return nil, fmt.Errorf("invalid blocked services: %w", err) } c = &Client{ @@ -185,7 +153,7 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C Name: cj.Name, - BlockedServices: bs, + BlockedServices: svcs, IDs: cj.IDs, Tags: cj.Tags, @@ -216,6 +184,63 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C return c, nil } +// copySafeSearch returns safe search config created from provided parameters. +func copySafeSearch( + jsonConf *filtering.SafeSearchConfig, + enabled bool, +) (conf filtering.SafeSearchConfig) { + if jsonConf != nil { + return *jsonConf + } + + // TODO(d.kolyshev): Remove after cleaning the deprecated + // [clientJSON.SafeSearchEnabled] field. + conf = filtering.SafeSearchConfig{ + Enabled: enabled, + } + + // Set default service flags for enabled safesearch. + if conf.Enabled { + conf.Bing = true + conf.DuckDuckGo = true + conf.Google = true + conf.Pixabay = true + conf.Yandex = true + conf.YouTube = true + } + + return conf +} + +// copyBlockedServices converts a json blocked services to an internal blocked +// services. +func copyBlockedServices( + sch *schedule.Weekly, + svcStrs []string, + prev *Client, +) (svcs *filtering.BlockedServices, err error) { + var weekly *schedule.Weekly + if sch != nil { + weekly = sch.Clone() + } else if prev != nil && prev.BlockedServices != nil { + weekly = prev.BlockedServices.Schedule.Clone() + } else { + weekly = schedule.EmptyWeekly() + } + + svcs = &filtering.BlockedServices{ + Schedule: weekly, + IDs: svcStrs, + } + + err = svcs.Validate() + if err != nil { + return nil, fmt.Errorf("validating blocked services: %w", err) + } + + return svcs, nil +} + // clientToJSON converts Client object to JSON. func clientToJSON(c *Client) (cj *clientJSON) { // TODO(d.kolyshev): Remove after cleaning the deprecated @@ -243,6 +268,9 @@ func clientToJSON(c *Client) (cj *clientJSON) { IgnoreQueryLog: aghalg.BoolToNullBool(c.IgnoreQueryLog), IgnoreStatistics: aghalg.BoolToNullBool(c.IgnoreStatistics), + + UpstreamsCacheSize: c.UpstreamsCacheSize, + UpstreamsCacheEnabled: aghalg.BoolToNullBool(c.UpstreamsCacheEnabled), } } diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index 41747529..16e7ab0d 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -6,6 +6,18 @@ ## v0.107.42: API changes +### The new fields `"upstreams_cache_enabled"` and `"upstreams_cache_size"` in `Client` object + +* The new field `"upstreams_cache_enabled"` in `GET /control/clients`, + `GET /control/clients/find`, `POST /control/clients/add`, and + `POST /control/clients/update` methods shows if client's DNS cache is enabled + for the client. If not set AdGuard Home will use default value (false). + +* The new field `"upstreams_cache_size"` in `GET /control/clients`, + `GET /control/clients/find`, `POST /control/clients/add`, and + `POST /control/clients/update` methods is the size of client's DNS cache in + bytes. + ### The new field `"ratelimit_subnet_len_ipv4"` in `DNSConfig` object * The new field `"ratelimit_subnet_len_ipv4"` in `GET /control/dns_info` and diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 2c225ea6..c105ee1d 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -2684,6 +2684,25 @@ If `ignore_statistics` is not set in HTTP API `GET /clients/update` request then the existing value will not be changed. + This behaviour can be changed in the future versions. + 'type': 'boolean' + 'upstreams_cache_enabled': + 'description': | + NOTE: If `upstreams_cache_enabled` is not set in HTTP API + `GET /clients/add` request then default value (false) will be used. + + If `upstreams_cache_enabled` is not set in HTTP API + `GET /clients/update` request then the existing value will not be + changed. + + This behaviour can be changed in the future versions. + 'type': 'boolean' + 'upstreams_cache_size': + 'description': | + NOTE: If `upstreams_cache_enabled` is not set in HTTP API + `GET /clients/update` request then the existing value will not be + changed. + This behaviour can be changed in the future versions. 'type': 'boolean' 'ClientAuto':