diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json
index a30e5d0b..71d9daaf 100644
--- a/client/src/__locales/en.json
+++ b/client/src/__locales/en.json
@@ -1,7 +1,8 @@
{
"client_settings": "Client settings",
- "example_upstream_reserved": "you can specify DNS upstream <0>for a specific domain(s)0>",
- "upstream_parallel": "Use parallel queries to speed up resolving by simultaneously querying all upstream servers",
+ "example_upstream_reserved": "You can specify DNS upstream <0>for the specific domain(s)0>",
+ "upstream_parallel": "Use parallel requests to speed up resolving by simultaneously querying all upstream servers",
+ "parallel_requests": "Parallel requests",
"bootstrap_dns": "Bootstrap DNS servers",
"bootstrap_dns_desc": "Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams.",
"check_dhcp_servers": "Check for DHCP servers",
@@ -453,6 +454,8 @@
"example_rewrite_wildcard": "rewrite responses for all <0>example.org0> subdomains.",
"disable_ipv6": "Disable IPv6",
"disable_ipv6_desc": "If this feature is enabled, all DNS queries for IPv6 addresses (type AAAA) will be dropped.",
+ "fastest_addr": "Fastest IP address",
+ "fastest_addr_desc": "Query all DNS servers and return the fastest IP address among all responses",
"autofix_warning_text": "If you click \"Fix\", AdGuard Home will configure your system to use AdGuard Home DNS server.",
"autofix_warning_list": "It will perform these tasks: <0>Deactivate system DNSStubListener0> <0>Set DNS server address to 127.0.0.10> <0>Replace symbolic link target of /etc/resolv.conf with /run/systemd/resolve/resolv.conf0> <0>Stop DNSStubListener (reload systemd-resolved service)0>",
"autofix_warning_result": "As a result all DNS requests from your system will be processed by AdGuard Home by default.",
diff --git a/client/src/actions/dnsConfig.js b/client/src/actions/dnsConfig.js
index 1976613e..c7a4dc2f 100644
--- a/client/src/actions/dnsConfig.js
+++ b/client/src/actions/dnsConfig.js
@@ -2,6 +2,7 @@ import { createAction } from 'redux-actions';
import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index';
+import { normalizeTextarea } from '../helpers/helpers';
export const getDnsConfigRequest = createAction('GET_DNS_CONFIG_REQUEST');
export const getDnsConfigFailure = createAction('GET_DNS_CONFIG_FAILURE');
@@ -25,8 +26,26 @@ export const setDnsConfigSuccess = createAction('SET_DNS_CONFIG_SUCCESS');
export const setDnsConfig = config => async (dispatch) => {
dispatch(setDnsConfigRequest());
try {
- await apiClient.setDnsConfig(config);
- dispatch(addSuccessToast('config_successfully_saved'));
+ const data = { ...config };
+
+ let hasDnsSettings = false;
+ if (Object.prototype.hasOwnProperty.call(data, 'bootstrap_dns')) {
+ data.bootstrap_dns = normalizeTextarea(config.bootstrap_dns);
+ hasDnsSettings = true;
+ }
+ if (Object.prototype.hasOwnProperty.call(data, 'upstream_dns')) {
+ data.upstream_dns = normalizeTextarea(config.upstream_dns);
+ hasDnsSettings = true;
+ }
+
+ await apiClient.setDnsConfig(data);
+
+ if (hasDnsSettings) {
+ dispatch(addSuccessToast('updated_upstream_dns_toast'));
+ } else {
+ dispatch(addSuccessToast('config_successfully_saved'));
+ }
+
dispatch(setDnsConfigSuccess(config));
} catch (error) {
dispatch(addErrorToast({ error }));
diff --git a/client/src/actions/index.js b/client/src/actions/index.js
index 0d212b1b..0cff2116 100644
--- a/client/src/actions/index.js
+++ b/client/src/actions/index.js
@@ -244,6 +244,7 @@ export const getDnsStatus = () => async (dispatch) => {
dispatch(dnsStatusFailure());
window.location.reload(true);
};
+
const handleRequestSuccess = (response) => {
const dnsStatus = response.data;
const { running } = dnsStatus;
@@ -265,42 +266,6 @@ export const getDnsStatus = () => async (dispatch) => {
}
};
-export const getDnsSettingsRequest = createAction('GET_DNS_SETTINGS_REQUEST');
-export const getDnsSettingsFailure = createAction('GET_DNS_SETTINGS_FAILURE');
-export const getDnsSettingsSuccess = createAction('GET_DNS_SETTINGS_SUCCESS');
-
-export const getDnsSettings = () => async (dispatch) => {
- dispatch(getDnsSettingsRequest());
- try {
- const dnsStatus = await apiClient.getGlobalStatus();
- dispatch(getDnsSettingsSuccess(dnsStatus));
- } catch (error) {
- dispatch(addErrorToast({ error }));
- dispatch(getDnsSettingsFailure());
- }
-};
-
-export const handleUpstreamChange = createAction('HANDLE_UPSTREAM_CHANGE');
-export const setUpstreamRequest = createAction('SET_UPSTREAM_REQUEST');
-export const setUpstreamFailure = createAction('SET_UPSTREAM_FAILURE');
-export const setUpstreamSuccess = createAction('SET_UPSTREAM_SUCCESS');
-
-export const setUpstream = config => async (dispatch) => {
- dispatch(setUpstreamRequest());
- try {
- const values = { ...config };
- values.bootstrap_dns = normalizeTextarea(values.bootstrap_dns);
- values.upstream_dns = normalizeTextarea(values.upstream_dns);
-
- await apiClient.setUpstream(values);
- dispatch(addSuccessToast('updated_upstream_dns_toast'));
- dispatch(setUpstreamSuccess(config));
- } catch (error) {
- dispatch(addErrorToast({ error }));
- dispatch(setUpstreamFailure());
- }
-};
-
export const testUpstreamRequest = createAction('TEST_UPSTREAM_REQUEST');
export const testUpstreamFailure = createAction('TEST_UPSTREAM_FAILURE');
export const testUpstreamSuccess = createAction('TEST_UPSTREAM_SUCCESS');
diff --git a/client/src/api/Api.js b/client/src/api/Api.js
index 94a05b19..f678d7c3 100644
--- a/client/src/api/Api.js
+++ b/client/src/api/Api.js
@@ -32,7 +32,6 @@ class Api {
// Global methods
GLOBAL_STATUS = { path: 'status', method: 'GET' };
- GLOBAL_SET_UPSTREAM_DNS = { path: 'set_upstreams_config', method: 'POST' };
GLOBAL_TEST_UPSTREAM_DNS = { path: 'test_upstream_dns', method: 'POST' };
GLOBAL_VERSION = { path: 'version.json', method: 'POST' };
GLOBAL_UPDATE = { path: 'update', method: 'POST' };
@@ -42,15 +41,6 @@ class Api {
return this.makeRequest(path, method);
}
- setUpstream(url) {
- const { path, method } = this.GLOBAL_SET_UPSTREAM_DNS;
- const config = {
- data: url,
- headers: { 'Content-Type': 'application/json' },
- };
- return this.makeRequest(path, method, config);
- }
-
testUpstream(servers) {
const { path, method } = this.GLOBAL_TEST_UPSTREAM_DNS;
const config = {
diff --git a/client/src/components/Settings/Dns/Config/Form.js b/client/src/components/Settings/Dns/Config/Form.js
index 1db400e8..46fae81e 100644
--- a/client/src/components/Settings/Dns/Config/Form.js
+++ b/client/src/components/Settings/Dns/Config/Form.js
@@ -17,26 +17,55 @@ import {
} from '../../../../helpers/form';
import { BLOCKING_MODES } from '../../../../helpers/constants';
-const getFields = (processing, t) => Object.values(BLOCKING_MODES).map(mode => (
-