Bug 1806412 - Add a custom about:neterror page for the DNS native fallback warning r=necko-reviewers,fluent-reviewers,flod,valentin,pbz

Similar to Bug 1596845 - Implement new error page for DNS errors when DoH is enabled - this changes about:neterror to show an error page specific to DNS failures that would have previously been resolved by fallback to native resolution.

With the preference, network.trr.display_fallback_warning set (defaults to off), DNS resolution will now fail when the user is in trr mode 2 (trr first) and either of these occur:
- the TRR cannot be confirmed
- the canary network heuristic is tripped

The new custom error page will be shown for failures resulting from these conditions.

This offers the user more information about the failure, and the option to bypass this warning going forward.

As with Bug 1596845, this is experimental and will be further improved over time.

To see the error page, the user must first set the network.trr.display_fallback_warning preference.
They must then encounter one of the conditions (unable to confirm TRR or tripping the canary heuristic).
Preventing TRR confirmation can be done by modifying their local hosts file to map their regional TRR domain's to an invalid address.

Project plan: https://docs.google.com/document/d/12IGABt1eXI276qHduXXbVZqRFrhLN7Ad3gKEgxz81sE
Copy deck: https://docs.google.com/document/d/130UTox8bQbybjYIwvltR4qBg2hWjsGhuNUHypLwUAEQ

Depends on D165557

Differential Revision: https://phabricator.services.mozilla.com/D165558
This commit is contained in:
Andrew Creskey 2023-01-16 13:12:04 +00:00
Родитель a2df091c3f
Коммит 902da73f87
8 изменённых файлов: 225 добавлений и 83 удалений

Просмотреть файл

@ -29,7 +29,8 @@ class NetErrorChild extends RemotePageChild {
"RPMCheckAlternateHostAvailable",
"RPMGetHttpResponseHeader",
"RPMIsTRROnlyFailure",
"RPMShowTRROnlyFailureError",
"RPMIsFirefox",
"RPMIsNativeFallbackFailure",
"RPMOpenPreferences",
"RPMGetTRRSkipReason",
"RPMGetTRRDomain",
@ -162,7 +163,7 @@ class NetErrorChild extends RemotePageChild {
}
RPMIsTRROnlyFailure() {
// As per RPMShowTRROnlyFailureError, we will only show this in Firefox
// We will only show this in Firefox because the options may direct users to settings only available on Firefox Desktop
let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface(
Ci.nsIHttpChannelInternal
);
@ -172,10 +173,37 @@ class NetErrorChild extends RemotePageChild {
return channel.effectiveTRRMode == Ci.nsIRequest.TRR_ONLY_MODE;
}
RPMShowTRROnlyFailureError() {
RPMIsFirefox() {
return lazy.AppInfo.isFirefox;
}
RPMIsNativeFallbackFailure() {
let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface(
Ci.nsIHttpChannelInternal
);
let value = channel?.trrSkipReason ?? Ci.nsITRRSkipReason.TRR_UNSET;
const warningReasons = new Set([
Ci.nsITRRSkipReason.TRR_NOT_CONFIRMED,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_CANARY,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_VPN,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PROXY,
Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_NRPT,
]);
return (
Services.dns.currentTrrMode == Ci.nsIRequest.TRR_FIRST_MODE &&
warningReasons.has(value)
);
}
RPMGetTRRSkipReason() {
let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface(
Ci.nsIHttpChannelInternal

Просмотреть файл

@ -239,6 +239,12 @@ function initPage() {
const isTRROnlyFailure = gErrorCode == "dnsNotFound" && RPMIsTRROnlyFailure();
let isNativeFallbackWarning = false;
if (RPMGetBoolPref("network.trr.display_fallback_warning")) {
isNativeFallbackWarning =
gErrorCode == "dnsNotFound" && RPMIsNativeFallbackFailure();
}
const docTitle = document.querySelector("title");
const bodyTitle = document.querySelector(".title-text");
const shortDesc = document.getElementById("errorShortDesc");
@ -390,90 +396,99 @@ function initPage() {
bodyTitleId = "generic-title";
}
if (isTRROnlyFailure && RPMShowTRROnlyFailureError()) {
document.body.className = "certerror"; // Shows warning icon
pageTitleId = "dns-not-found-trr-only-title";
document.l10n.setAttributes(docTitle, pageTitleId, {
hostname: HOST_NAME,
});
bodyTitleId = "dns-not-found-trr-only-title";
document.l10n.setAttributes(bodyTitle, bodyTitleId, {
hostname: HOST_NAME,
});
shortDesc.textContent = "";
// enable buttons
let trrExceptionButton = document.getElementById("trrExceptionButton");
trrExceptionButton.addEventListener("click", () => {
RPMSendQuery("Browser:AddTRRExcludedDomain", {
// The TRR errors may present options that direct users to settings only available on Firefox Desktop
if (RPMIsFirefox()) {
if (isTRROnlyFailure) {
document.body.className = "certerror"; // Shows warning icon
pageTitleId = "dns-not-found-trr-only-title";
document.l10n.setAttributes(docTitle, pageTitleId, {
hostname: HOST_NAME,
}).then(msg => {
retryThis(this);
});
});
trrExceptionButton.hidden = false;
let trrSettingsButton = document.getElementById("trrSettingsButton");
trrSettingsButton.addEventListener("click", () => {
RPMSendAsyncMessage("OpenTRRPreferences");
});
trrSettingsButton.hidden = false;
let message = document.getElementById("trrOnlyMessage");
document.l10n.setAttributes(
message,
"neterror-dns-not-found-trr-only-reason",
{
bodyTitleId = "dns-not-found-trr-only-title";
document.l10n.setAttributes(bodyTitle, bodyTitleId, {
hostname: HOST_NAME,
});
shortDesc.textContent = "";
// enable buttons
let trrExceptionButton = document.getElementById("trrExceptionButton");
trrExceptionButton.addEventListener("click", () => {
RPMSendQuery("Browser:AddTRRExcludedDomain", {
hostname: HOST_NAME,
}).then(msg => {
retryThis(this);
});
});
trrExceptionButton.hidden = false;
let trrSettingsButton = document.getElementById("trrSettingsButton");
trrSettingsButton.addEventListener("click", () => {
RPMSendAsyncMessage("OpenTRRPreferences");
});
trrSettingsButton.hidden = false;
let message = document.getElementById("trrOnlyMessage");
document.l10n.setAttributes(
message,
"neterror-dns-not-found-trr-only-reason",
{
hostname: HOST_NAME,
}
);
let skipReason = RPMGetTRRSkipReason();
let descriptionTag = "neterror-dns-not-found-trr-unknown-problem";
let args = { trrDomain: RPMGetTRRDomain() };
if (
skipReason == "TRR_FAILED" ||
skipReason == "TRR_CHANNEL_DNS_FAIL" ||
skipReason == "TRR_UNKNOWN_CHANNEL_FAILURE" ||
skipReason == "TRR_NET_REFUSED" ||
skipReason == "TRR_NET_INTERRUPT" ||
skipReason == "TRR_NET_INADEQ_SEQURITY"
) {
descriptionTag = "neterror-dns-not-found-trr-only-could-not-connect";
} else if (skipReason == "TRR_TIMEOUT") {
descriptionTag = "neterror-dns-not-found-trr-only-timeout";
} else if (
skipReason == "TRR_IS_OFFLINE" ||
skipReason == "TRR_NO_CONNECTIVITY"
) {
descriptionTag = "neterror-dns-not-found-trr-offline";
} else if (
skipReason == "TRR_NO_ANSWERS" ||
skipReason == "TRR_NXDOMAIN"
) {
descriptionTag = "neterror-dns-not-found-trr-unknown-host";
} else if (
skipReason == "TRR_DECODE_FAILED" ||
skipReason == "TRR_SERVER_RESPONSE_ERR"
) {
descriptionTag = "neterror-dns-not-found-trr-server-problem";
}
);
let skipReason = RPMGetTRRSkipReason();
let description = document.getElementById("trrOnlyDescription");
document.l10n.setAttributes(description, descriptionTag, args);
let descriptionTag = "neterror-dns-not-found-trr-unknown-problem";
let args = { trrDomain: RPMGetTRRDomain() };
if (
skipReason == "TRR_FAILED" ||
skipReason == "TRR_CHANNEL_DNS_FAIL" ||
skipReason == "TRR_UNKNOWN_CHANNEL_FAILURE" ||
skipReason == "TRR_NET_REFUSED" ||
skipReason == "TRR_NET_INTERRUPT" ||
skipReason == "TRR_NET_INADEQ_SEQURITY"
) {
descriptionTag = "neterror-dns-not-found-trr-only-could-not-connect";
} else if (skipReason == "TRR_TIMEOUT") {
descriptionTag = "neterror-dns-not-found-trr-only-timeout";
} else if (
skipReason == "TRR_IS_OFFLINE" ||
skipReason == "TRR_NO_CONNECTIVITY"
) {
descriptionTag = "neterror-dns-not-found-trr-offline";
} else if (skipReason == "TRR_NO_ANSWERS" || skipReason == "TRR_NXDOMAIN") {
descriptionTag = "neterror-dns-not-found-trr-unknown-host";
} else if (
skipReason == "TRR_DECODE_FAILED" ||
skipReason == "TRR_SERVER_RESPONSE_ERR"
) {
descriptionTag = "neterror-dns-not-found-trr-server-problem";
const trrLearnMoreContainer = document.getElementById(
"trrLearnMoreContainer"
);
trrLearnMoreContainer.hidden = false;
let learnMoreLink = document.getElementById("trrOnlylearnMoreLink");
// This will be replaced at a later point with a link to an offline support page
// https://bugzilla.mozilla.org/show_bug.cgi?id=1806257
learnMoreLink.href =
RPMGetFormatURLPref("network.trr_ui.skip_reason_learn_more_url") +
skipReason.toLowerCase().replaceAll("_", "-");
let div = document.getElementById("trrOnlyContainer");
div.hidden = false;
return;
} else if (isNativeFallbackWarning) {
showNativeFallbackWarning();
return;
}
let description = document.getElementById("trrOnlyDescription");
document.l10n.setAttributes(description, descriptionTag, args);
const trrLearnMoreContainer = document.getElementById(
"trrLearnMoreContainer"
);
trrLearnMoreContainer.hidden = false;
let learnMoreLink = document.getElementById("trrOnlylearnMoreLink");
// This will be replaced at a later point with a link to an offline support page
// https://bugzilla.mozilla.org/show_bug.cgi?id=1806257
learnMoreLink.href =
RPMGetFormatURLPref("network.trr_ui.skip_reason_learn_more_url") +
skipReason.toLowerCase().replaceAll("_", "-");
let div = document.getElementById("trrOnlyContainer");
div.hidden = false;
return;
}
document.l10n.setAttributes(docTitle, pageTitleId);
@ -490,6 +505,69 @@ function initPage() {
setNetErrorMessageFromCode();
}
function showNativeFallbackWarning() {
const docTitle = document.querySelector("title");
const bodyTitle = document.querySelector(".title-text");
const shortDesc = document.getElementById("errorShortDesc");
let pageTitleId = "neterror-page-title";
let bodyTitleId = gErrorCode + "-title";
document.body.className = "certerror"; // Shows warning icon
pageTitleId = "dns-not-found-native-fallback-title";
document.l10n.setAttributes(docTitle, pageTitleId, {
hostname: HOST_NAME,
});
bodyTitleId = "dns-not-found-native-fallback-title";
document.l10n.setAttributes(bodyTitle, bodyTitleId, {
hostname: HOST_NAME,
});
shortDesc.textContent = "";
let nativeFallbackIgnoreButton = document.getElementById(
"nativeFallbackIgnoreButton"
);
nativeFallbackIgnoreButton.addEventListener("click", () => {
RPMSetBoolPref("network.trr.display_fallback_warning", false);
retryThis(nativeFallbackIgnoreButton);
});
nativeFallbackIgnoreButton.hidden = false;
let message = document.getElementById("nativeFallbackMessage");
document.l10n.setAttributes(
message,
"neterror-dns-not-found-native-fallback-reason",
{
hostname: HOST_NAME,
}
);
let skipReason = RPMGetTRRSkipReason();
let descriptionTag = "neterror-dns-not-found-trr-unknown-problem";
let args = { trrDomain: RPMGetTRRDomain() };
if (skipReason.includes("HEURISTIC_TRIPPED")) {
descriptionTag = "neterror-dns-not-found-native-fallback-heuristic";
} else if (skipReason == "TRR_NOT_CONFIRMED") {
descriptionTag = "neterror-dns-not-found-native-fallback-not-confirmed";
}
let description = document.getElementById("nativeFallbackDescription");
document.l10n.setAttributes(description, descriptionTag, args);
let learnMoreContainer = document.getElementById(
"nativeFallbackLearnMoreContainer"
);
learnMoreContainer.hidden = false;
let learnMoreLink = document.getElementById("nativeFallbackLearnMoreLink");
learnMoreLink.href =
RPMGetFormatURLPref("network.trr_ui.skip_reason_learn_more_url") +
skipReason.toLowerCase().replaceAll("_", "-");
let div = document.getElementById("nativeFallbackContainer");
div.hidden = false;
}
/**
* Builds HTML elements from `parts` and appends them to `parent`.
*

Просмотреть файл

@ -51,6 +51,17 @@
<p data-l10n-id="neterror-dns-not-found-trr-only-attackers"> </p>
</p>
<p id="nativeFallbackContainer" hidden="">
<p id="nativeFallbackMessage"></p>
<div class="native-fallback-message-container">
<span id="nativeFallbackDescription"></span>
<p id="nativeFallbackLearnMoreContainer" hidden="">
<a id="nativeFallbackLearnMoreLink" target="_blank" rel="noopener noreferrer" data-l10n-id="neterror-learn-more-link"></a>
</p>
</div>
<p data-l10n-id="neterror-dns-not-found-native-fallback-attackers"> </p>
</p>
<p id="tlsVersionNotice" hidden=""></p>
<p id="learnMoreContainer" hidden="">
@ -81,6 +92,7 @@
<button class="primary try-again" data-l10n-id="neterror-try-again-button"></button>
<button id="trrExceptionButton" data-l10n-id="neterror-add-exception-button" hidden=""></button>
<button id="trrSettingsButton" data-l10n-id="neterror-settings-button" hidden=""></button>
<button id="nativeFallbackIgnoreButton" data-l10n-id="neterror-disable-native-feedback-warning" hidden=""></button>
</div>
<div class="advanced-panel-container">

Просмотреть файл

@ -110,6 +110,11 @@ dnsNotFound-title = Hmm. Were having trouble finding that site.
dns-not-found-trr-only-title =
Possible security risk for { $hostname }.
# Variables:
# $hostname (String) - Hostname of the website to which the user was trying to connect.
dns-not-found-native-fallback-title =
Possible security risk for { $hostname }.
fileNotFound-title = File not found
fileAccessDenied-title = Access to the file was denied
generic-title = Oops.

Просмотреть файл

@ -26,6 +26,7 @@ neterror-try-again-button = Try Again
neterror-add-exception-button = Always continue for this site
neterror-settings-button = Change DNS settings
neterror-view-certificate-link = View Certificate
neterror-disable-native-feedback-warning = Always continue
##
@ -65,6 +66,15 @@ neterror-dns-not-found-trr-unknown-host = An address for this website wasnt f
neterror-dns-not-found-trr-server-problem = There was a problem with { $trrDomain }.
neterror-dns-not-found-trr-unknown-problem = Unexpected problem.
## Native fallback specific messages
## Variables:
## $trrDomain (String) - Hostname of the DNS over HTTPS server that is currently in use.
neterror-dns-not-found-native-fallback-reason = { -brand-short-name } cant protect your request for this sites address through our trusted DNS resolver. Heres why:
neterror-dns-not-found-native-fallback-attackers = You can continue with a DNS resolver that is not secure. However, a third-party might be able to see what websites you visit or send you to an untrusted site.
neterror-dns-not-found-native-fallback-heuristic = DNS over HTTPs has been disabled on your network.
neterror-dns-not-found-native-fallback-not-confirmed = The connection to { $trrDomain } isnt ready yet.
##
neterror-file-not-found-filename = Check the file name for capitalization or other typing errors.

Просмотреть файл

@ -55,6 +55,8 @@ const kAllowedPrefs = new Set([
"security.tls.version.enable-deprecated",
"security.xfocsp.errorReporting.automatic",
"network.trr.display_fallback_warning",
]);
const kPrefTypeMap = new Map([

Просмотреть файл

@ -48,6 +48,7 @@ export let RemotePageAccessManager = {
"security.certerrors.permanentOverride",
"security.enterprise_roots.auto-enabled",
"security.certerror.hideAddException",
"network.trr.display_fallback_warning",
],
RPMGetIntPref: [
"services.settings.clock_skew_seconds",
@ -92,13 +93,18 @@ export let RemotePageAccessManager = {
"security.certerror.hideAddException",
"security.xfocsp.errorReporting.automatic",
"security.xfocsp.errorReporting.enabled",
"network.trr.display_fallback_warning",
],
RPMSetBoolPref: [
"security.xfocsp.errorReporting.automatic",
"network.trr.display_fallback_warning",
],
RPMSetBoolPref: ["security.xfocsp.errorReporting.automatic"],
RPMAddToHistogram: ["*"],
RPMGetInnerMostURI: ["*"],
RPMGetHttpResponseHeader: ["*"],
RPMIsTRROnlyFailure: ["*"],
RPMShowTRROnlyFailureError: ["*"],
RPMIsFirefox: ["*"],
RPMIsNativeFallbackFailure: ["*"],
RPMGetTRRSkipReason: ["*"],
RPMGetTRRDomain: ["*"],
RPMSendQuery: ["Browser:AddTRRExcludedDomain"],

Просмотреть файл

@ -21,7 +21,8 @@ module.exports = {
RPMSetBoolPref: false,
RPMGetFormatURLPref: false,
RPMIsTRROnlyFailure: false,
RPMShowTRROnlyFailureError: false,
RPMIsFirefox: false,
RPMIsNativeFallbackFailure: false,
RPMIsWindowPrivate: false,
RPMSendAsyncMessage: false,
RPMSendQuery: false,