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