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':