diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json
index afc2f105eb8..207d427b582 100644
--- a/client/src/__locales/en.json
+++ b/client/src/__locales/en.json
@@ -586,5 +586,13 @@
"port_53_faq_link": "Port 53 is often occupied by \"DNSStubListener\" or \"systemd-resolved\" services. Please read <0>this instruction0> on how to resolve this.",
"adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client.",
"client_not_in_allowed_clients": "The client is not allowed because it is not in the \"Allowed clients\" list.",
- "experimental": "Experimental"
+ "experimental": "Experimental",
+ "rebinding_title": "DNS Rebinding Protection",
+ "rebinding_desc": "Here you can configure protection against DNS rebinding attacks",
+ "rebinding_protection_enabled": "Enable protection from DNS rebinding attacks",
+ "rebinding_protection_enabled_desc": "If enabled, AdGuard Home will block responses containing host on the local network.",
+ "rebinding_allowed_hosts_title": "Allowed domains",
+ "rebinding_allowed_hosts_desc": "A list of domains. If configured, AdGuard Home will allow responses containing host on the local network from these domains. Here you can specify the exact domain names, wildcards and urlfilter-rules, e.g. 'example.org', '*.example.org' or '||example.org^'.",
+ "rebinding_applied": "DNS rebinding protection applied",
+ "blocked_rebind": "Blocked rebinding"
}
diff --git a/client/src/actions/dnsConfig.js b/client/src/actions/dnsConfig.js
index c599ca8def0..f7809de6d5b 100644
--- a/client/src/actions/dnsConfig.js
+++ b/client/src/actions/dnsConfig.js
@@ -37,6 +37,9 @@ export const setDnsConfig = (config) => async (dispatch) => {
data.upstream_dns = splitByNewLine(config.upstream_dns);
hasDnsSettings = true;
}
+ if (Object.prototype.hasOwnProperty.call(data, 'rebinding_allowed_hosts')) {
+ data.rebinding_allowed_hosts = splitByNewLine(config.rebinding_allowed_hosts);
+ }
await apiClient.setDnsConfig(data);
diff --git a/client/src/components/Filters/Check/Info.js b/client/src/components/Filters/Check/Info.js
index f53f254d351..bc36ef50d32 100644
--- a/client/src/components/Filters/Check/Info.js
+++ b/client/src/components/Filters/Check/Info.js
@@ -65,6 +65,7 @@ const getTitle = () => {
[FILTERED_STATUS.FILTERED_SAFE_SEARCH]: getReasonFiltered(reason),
[FILTERED_STATUS.FILTERED_SAFE_BROWSING]: getReasonFiltered(reason),
[FILTERED_STATUS.FILTERED_PARENTAL]: getReasonFiltered(reason),
+ [FILTERED_STATUS.FILTERED_BLOCKED_REBIND]: t('rebinding_applied'),
};
if (Object.prototype.hasOwnProperty.call(REASON_TO_TITLE_MAP, reason)) {
diff --git a/client/src/components/Logs/Cells/ClientCell.js b/client/src/components/Logs/Cells/ClientCell.js
index 56a3440cb1d..5ec8e1b802f 100644
--- a/client/src/components/Logs/Cells/ClientCell.js
+++ b/client/src/components/Logs/Cells/ClientCell.js
@@ -4,7 +4,7 @@ import { nanoid } from 'nanoid';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import propTypes from 'prop-types';
-import { checkFiltered, getBlockingClientName } from '../../../helpers/helpers';
+import { checkFiltered, checkBlockedRebind, getBlockingClientName } from '../../../helpers/helpers';
import { BLOCK_ACTIONS } from '../../../helpers/constants';
import { toggleBlocking, toggleBlockingForClient } from '../../../actions';
import IconTooltip from './IconTooltip';
@@ -48,6 +48,7 @@ const ClientCell = ({
const processedData = Object.entries(data);
const isFiltered = checkFiltered(reason);
+ const isBlockedRebinding = checkBlockedRebind(reason);
const nameClass = classNames('w-90 o-hidden d-flex flex-column', {
'mt-2': isDetailed && !name && !whoisAvailable,
@@ -125,7 +126,7 @@ const ClientCell = ({
'button-action__container--detailed': isDetailed,
});
- return
+ return isBlockedRebinding ||