diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 75e7f02a858a..7616b65ed1bd 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -2039,6 +2039,17 @@ pref("extensions.screenshots.disabled", false); // Preference that determines whether Screenshots is opened as a dedicated browser component pref("screenshots.browser.component.enabled", false); +// DoH Rollout: whether to enable automatic performance-based TRR-selection. +// This pref is controlled by a Normandy rollout so we don't overload providers. +pref("doh-rollout.trr-selection.enabled", false); + +// DoH Rollout: whether to enable automatic steering to provider endpoints. +// This pref is also controlled by a Normandy rollout. +pref("doh-rollout.provider-steering.enabled", true); + +// DoH Rollout: provider details for automatic steering. +pref("doh-rollout.provider-steering.provider-list", "[{ \"name\": \"comcast\", \"canonicalName\": \"doh-discovery.xfinity.com\", \"uri\": \"https://doh.xfinity.com/dns-query\" }]"); + // DoH Rollout: whether to clear the mode value at shutdown. pref("doh-rollout.clearModeOnShutdown", false); diff --git a/browser/components/doh/DoHConfig.jsm b/browser/components/doh/DoHConfig.jsm index c22271431ceb..d8c712039575 100644 --- a/browser/components/doh/DoHConfig.jsm +++ b/browser/components/doh/DoHConfig.jsm @@ -26,39 +26,36 @@ XPCOMUtils.defineLazyModuleGetters(this, { const kGlobalPrefBranch = "doh-rollout"; var kRegionPrefBranch; -const kConfigPrefs = { - kEnabledPref: "enabled", - kProvidersPref: "provider-list", - kTRRSelectionEnabledPref: "trr-selection.enabled", - kTRRSelectionProvidersPref: "trr-selection.provider-list", - kTRRSelectionCommitResultPref: "trr-selection.commit-result", - kProviderSteeringEnabledPref: "provider-steering.enabled", - kProviderSteeringListPref: "provider-steering.provider-list", -}; +const kEnabledPref = "enabled"; + +const kProvidersPref = "provider-list"; + +const kTRRSelectionEnabledPref = "trr-selection.enabled"; +const kTRRSelectionProvidersPref = "trr-selection.provider-list"; +const kTRRSelectionCommitResultPref = "trr-selection.commit-result"; + +const kProviderSteeringEnabledPref = "provider-steering.enabled"; +const kProviderSteeringListPref = "provider-steering.provider-list"; const kPrefChangedTopic = "nsPref:changed"; const gProvidersCollection = RemoteSettings("doh-providers"); const gConfigCollection = RemoteSettings("doh-config"); -function getPrefValueRegionFirst(prefName) { - let regionalPrefName = `${kRegionPrefBranch}.${prefName}`; - if (Services.prefs.prefHasUserValue(regionalPrefName)) { - return Preferences.get(regionalPrefName); - } - return Preferences.get(`${kGlobalPrefBranch}.${prefName}`); +function getPrefValueRegionFirst(prefName, defaultValue) { + return ( + Preferences.get(`${kRegionPrefBranch}.${prefName}`) || + Preferences.get(`${kGlobalPrefBranch}.${prefName}`, defaultValue) + ); } function getProviderListFromPref(prefName) { - let prefVal = getPrefValueRegionFirst(prefName); - if (prefVal) { - try { - return JSON.parse(prefVal); - } catch (e) { - Cu.reportError(`DoH provider list not a valid JSON array: ${prefName}`); - } + try { + return JSON.parse(getPrefValueRegionFirst(prefName, "[]")); + } catch (e) { + Cu.reportError(`DoH provider list not a valid JSON array: ${prefName}`); } - return undefined; + return []; } // Generate a base config object with getters that return pref values. When @@ -68,94 +65,43 @@ function getProviderListFromPref(prefName) { // from it, we lose the ability to override getters because they are defined // as non-configureable properties on class instances. So just use a function. function makeBaseConfigObject() { - function makeConfigProperty({ - obj, - propName, - defaultVal, - prefName, - isProviderList, - }) { - let prefFn = isProviderList - ? getProviderListFromPref - : getPrefValueRegionFirst; + return { + get enabled() { + return getPrefValueRegionFirst(kEnabledPref, false); + }, - let overridePropName = "_" + propName; + get providerList() { + return getProviderListFromPref(kProvidersPref); + }, - Object.defineProperty(obj, propName, { - get() { - // If a pref value exists, it gets top priority. Otherwise, if it has an - // explicitly set value (from Remote Settings), we return that. - let prefVal = prefFn(prefName); - if (prefVal !== undefined) { - return prefVal; - } - if (this[overridePropName] !== undefined) { - return this[overridePropName]; - } - return defaultVal; - }, - set(val) { - this[overridePropName] = val; - }, - }); - } - let newConfig = { get fallbackProviderURI() { return this.providerList[0]?.uri; }, - trrSelection: {}, - providerSteering: {}, + + trrSelection: { + get enabled() { + return getPrefValueRegionFirst(kTRRSelectionEnabledPref, false); + }, + + get commitResult() { + return getPrefValueRegionFirst(kTRRSelectionCommitResultPref, false); + }, + + get providerList() { + return getProviderListFromPref(kTRRSelectionProvidersPref); + }, + }, + + providerSteering: { + get enabled() { + return getPrefValueRegionFirst(kProviderSteeringEnabledPref, false); + }, + + get providerList() { + return getProviderListFromPref(kProviderSteeringListPref); + }, + }, }; - makeConfigProperty({ - obj: newConfig, - propName: "enabled", - defaultVal: false, - prefName: kConfigPrefs.kEnabledPref, - isProviderList: false, - }); - makeConfigProperty({ - obj: newConfig, - propName: "providerList", - defaultVal: [], - prefName: kConfigPrefs.kProvidersPref, - isProviderList: true, - }); - makeConfigProperty({ - obj: newConfig.trrSelection, - propName: "enabled", - defaultVal: false, - prefName: kConfigPrefs.kTRRSelectionEnabledPref, - isProviderList: false, - }); - makeConfigProperty({ - obj: newConfig.trrSelection, - propName: "commitResult", - defaultVal: false, - prefName: kConfigPrefs.kTRRSelectionCommitResultPref, - isProviderList: false, - }); - makeConfigProperty({ - obj: newConfig.trrSelection, - propName: "providerList", - defaultVal: [], - prefName: kConfigPrefs.kTRRSelectionProvidersPref, - isProviderList: true, - }); - makeConfigProperty({ - obj: newConfig.providerSteering, - propName: "enabled", - defaultVal: false, - prefName: kConfigPrefs.kProviderSteeringEnabledPref, - isProviderList: false, - }); - makeConfigProperty({ - obj: newConfig.providerSteering, - propName: "providerList", - defaultVal: [], - prefName: kConfigPrefs.kProviderSteeringListPref, - isProviderList: true, - }); - return newConfig; } const DoHConfigController = { @@ -226,16 +172,10 @@ const DoHConfigController = { observe(subject, topic, data) { switch (topic) { case kPrefChangedTopic: - let allowedPrefs = Object.getOwnPropertyNames(kConfigPrefs).map( - k => kConfigPrefs[k] - ); if ( - !allowedPrefs.some(pref => - [ - `${kRegionPrefBranch}.${pref}`, - `${kGlobalPrefBranch}.${pref}`, - ].includes(data) - ) + !data.startsWith(kRegionPrefBranch) && + data != `${kGlobalPrefBranch}.${kEnabledPref}` && + data != `${kGlobalPrefBranch}.${kProvidersPref}` ) { break; } @@ -280,6 +220,7 @@ const DoHConfigController = { } if (localConfig.rolloutEnabled) { + delete newConfig.enabled; newConfig.enabled = true; } @@ -301,6 +242,7 @@ const DoHConfigController = { let regionalProviders = parseProviderList(localConfig.providers); if (regionalProviders?.length) { + delete newConfig.providerList; newConfig.providerList = regionalProviders; } @@ -310,7 +252,10 @@ const DoHConfigController = { p => p.canonicalName?.length ); if (steeringProviders?.length) { + delete newConfig.providerSteering.providerList; newConfig.providerSteering.providerList = steeringProviders; + + delete newConfig.providerSteering.enabled; newConfig.providerSteering.enabled = true; } } @@ -320,7 +265,10 @@ const DoHConfigController = { localConfig.autoDefaultProviders ); if (defaultProviders?.length) { + delete newConfig.trrSelection.providerList; newConfig.trrSelection.providerList = defaultProviders; + + delete newConfig.trrSelection.enabled; newConfig.trrSelection.enabled = true; } } diff --git a/browser/components/doh/test/browser/browser_providerSteering.js b/browser/components/doh/test/browser/browser_providerSteering.js index 3992379633ed..9befdc017623 100644 --- a/browser/components/doh/test/browser/browser_providerSteering.js +++ b/browser/components/doh/test/browser/browser_providerSteering.js @@ -29,13 +29,10 @@ add_task(async function testProviderSteering() { uri: "https://bar.provider2.com/query", }, ]; - let configFlushPromise = DoHTestUtils.waitForConfigFlush(); Preferences.set( prefs.PROVIDER_STEERING_LIST_PREF, JSON.stringify(providerTestcases) ); - await configFlushPromise; - await checkHeuristicsTelemetry("enable_doh", "startup"); let testNetChangeResult = async ( expectedURI, diff --git a/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js b/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js index cd4356ed3f11..89a8b506b99a 100644 --- a/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js +++ b/browser/components/doh/test/browser/browser_remoteSettings_newProfile.js @@ -7,18 +7,6 @@ add_task(setup); add_task(setupRegion); -async function setPrefAndWaitForConfigFlush(pref, value) { - let configFlushedPromise = DoHTestUtils.waitForConfigFlush(); - Preferences.set(pref, value); - await configFlushedPromise; -} - -async function clearPrefAndWaitForConfigFlush(pref, value) { - let configFlushedPromise = DoHTestUtils.waitForConfigFlush(); - Preferences.reset(pref); - await configFlushedPromise; -} - add_task(async function testNewProfile() { is( DoHConfigController.currentConfig.enabled, @@ -64,7 +52,6 @@ add_task(async function testNewProfile() { "Rollout should be enabled" ); await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); Assert.deepEqual( DoHConfigController.currentConfig.providerList, [provider1, provider3], @@ -96,46 +83,6 @@ add_task(async function testNewProfile() { "Fallback provider URI should be that of the first one" ); - // Test that overriding with prefs works. - await setPrefAndWaitForConfigFlush(prefs.PROVIDER_STEERING_PREF, false); - is( - DoHConfigController.currentConfig.providerSteering.enabled, - false, - "Provider steering should be disabled" - ); - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); - - await setPrefAndWaitForConfigFlush(prefs.TRR_SELECT_ENABLED_PREF, false); - is( - DoHConfigController.currentConfig.trrSelection.enabled, - false, - "TRR selection should be disabled" - ); - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); - - // Try a regional pref this time - await setPrefAndWaitForConfigFlush( - `${kRegionalPrefNamespace}.enabled`, - false - ); - is( - DoHConfigController.currentConfig.enabled, - false, - "Rollout should be disabled" - ); - await ensureTRRMode(undefined); - await ensureNoHeuristicsTelemetry(); - - await clearPrefAndWaitForConfigFlush(`${kRegionalPrefNamespace}.enabled`); - - is( - DoHConfigController.currentConfig.enabled, - true, - "Rollout should be enabled" - ); - await DoHTestUtils.resetRemoteSettingsConfig(); is( diff --git a/browser/components/doh/test/browser/browser_trrSelect.js b/browser/components/doh/test/browser/browser_trrSelect.js index 68861be8b8f8..f392cc2d0d35 100644 --- a/browser/components/doh/test/browser/browser_trrSelect.js +++ b/browser/components/doh/test/browser/browser_trrSelect.js @@ -4,22 +4,6 @@ "use strict"; -async function waitForStartup() { - await ensureTRRMode(2); - await checkHeuristicsTelemetry("enable_doh", "startup"); -} - -async function setPrefAndWaitForConfigFlush(pref, value) { - let configFlushed = DoHTestUtils.waitForConfigFlush(); - if (value) { - Preferences.set(pref, value); - } else { - Preferences.reset(pref); - } - await configFlushed; - await waitForStartup(); -} - add_task(setup); add_task(async function testTRRSelect() { @@ -42,22 +26,25 @@ add_task(async function testTRRSelect() { // Reset and restart the controller for good measure. Preferences.reset(prefs.TRR_SELECT_DRY_RUN_RESULT_PREF); Preferences.reset(prefs.TRR_SELECT_URI_PREF); - await restartDoHController(); - await waitForStartup(); + prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF); + await restartDoHController(); + await prefPromise; is( Preferences.get(prefs.TRR_SELECT_URI_PREF), "https://example.com/dns-query", "TRR selection complete." ); - // Disable committing. The committed URI should be reset to the + // Wait for heuristics to complete. + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); + + // Disable committing and reset. The committed URI should be reset to the // default provider and the dry-run-result should persist. - prefPromise = TestUtils.waitForPrefChange( - prefs.TRR_SELECT_URI_PREF, - newVal => newVal == "https://example.com/1" - ); - await setPrefAndWaitForConfigFlush(prefs.TRR_SELECT_COMMIT_PREF, false); + Preferences.set(prefs.TRR_SELECT_COMMIT_PREF, false); + prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF); + await restartDoHController(); await prefPromise; is( Preferences.get(prefs.TRR_SELECT_URI_PREF), @@ -78,13 +65,15 @@ add_task(async function testTRRSelect() { "dry-run result has the correct value." ); - // Reset again, dry-run-result should be recorded but not + // Wait for heuristics to complete. + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); + + // Reset and restart again, dry-run-result should be recorded but not // be committed. Committing is still disabled from above. Preferences.reset(prefs.TRR_SELECT_DRY_RUN_RESULT_PREF); Preferences.reset(prefs.TRR_SELECT_URI_PREF); await restartDoHController(); - await waitForStartup(); - try { await BrowserTestUtils.waitForCondition(() => { return ( @@ -106,6 +95,11 @@ add_task(async function testTRRSelect() { "https://example.com/dns-query", "TRR selection complete, dry-run result recorded." ); + Preferences.set(prefs.TRR_SELECT_COMMIT_PREF, true); + + // Wait for heuristics to complete. + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); // Reset doh-rollout.uri, and change the dry-run-result to another one on the // default list. After init, the existing dry-run-result should be committed. @@ -118,7 +112,7 @@ add_task(async function testTRRSelect() { prefs.TRR_SELECT_URI_PREF, newVal => newVal == "https://example.com/2" ); - await setPrefAndWaitForConfigFlush(prefs.TRR_SELECT_COMMIT_PREF, true); + await restartDoHController(); await prefPromise; is( Preferences.get(prefs.TRR_SELECT_URI_PREF), @@ -126,17 +120,18 @@ add_task(async function testTRRSelect() { "TRR selection complete, existing dry-run-result committed." ); + // Wait for heuristics to complete. + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); + // Reset doh-rollout.uri, and change the dry-run-result to another one NOT on // default list. After init, a new TRR should be selected and committed. - prefPromise = TestUtils.waitForPrefChange( - prefs.TRR_SELECT_URI_PREF, - newVal => newVal == "https://example.com/dns-query" - ); Preferences.reset(prefs.TRR_SELECT_URI_PREF); Preferences.set( prefs.TRR_SELECT_DRY_RUN_RESULT_PREF, "https://example.com/4" ); + prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF); await restartDoHController(); await prefPromise; is( @@ -144,4 +139,8 @@ add_task(async function testTRRSelect() { "https://example.com/dns-query", "TRR selection complete, existing dry-run-result discarded and refreshed." ); + + // Wait for heuristics to complete. + await ensureTRRMode(2); + await checkHeuristicsTelemetry("enable_doh", "startup"); }); diff --git a/browser/components/doh/test/browser/browser_trrSelection_disable.js b/browser/components/doh/test/browser/browser_trrSelection_disable.js index dc7bd6826234..f24000e68dcf 100644 --- a/browser/components/doh/test/browser/browser_trrSelection_disable.js +++ b/browser/components/doh/test/browser/browser_trrSelection_disable.js @@ -7,12 +7,8 @@ add_task(setup); add_task(async function testTrrSelectionDisable() { - // Turn off TRR Selection. - let configFlushed = DoHTestUtils.waitForConfigFlush(); - Preferences.set(prefs.TRR_SELECT_ENABLED_PREF, false); - await configFlushed; - // Set up a passing environment and enable DoH. + Preferences.set(prefs.TRR_SELECT_ENABLED_PREF, false); setPassingHeuristics(); let promise = waitForDoorhanger(); Preferences.set(prefs.ENABLED_PREF, true); diff --git a/browser/components/doh/test/browser/head.js b/browser/components/doh/test/browser/head.js index 767d0f917b15..3194454a45ce 100644 --- a/browser/components/doh/test/browser/head.js +++ b/browser/components/doh/test/browser/head.js @@ -86,10 +86,9 @@ async function setup() { // Avoid non-local connections to the TRR endpoint. Preferences.set(prefs.CONFIRMATION_NS_PREF, "skip"); - // Enable trr selection and provider steeringfor tests. This is off - // by default so it can be controlled via Normandy. + // Enable trr selection for tests. This is off by default so it can be + // controlled via Normandy. Preferences.set(prefs.TRR_SELECT_ENABLED_PREF, true); - Preferences.set(prefs.PROVIDER_STEERING_PREF, true); // Enable committing the TRR selection. This pref ships false by default so // it can be controlled e.g. via Normandy, but for testing let's set enable. @@ -211,11 +210,11 @@ async function checkHeuristicsTelemetry( events = Services.telemetry.snapshotEvents( Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS ).parent; - events = events?.filter( - e => e[1] == "doh" && e[2] == "evaluate_v2" && e[3] == "heuristics" - ); - return events?.length; + return events && events.length; }); + events = events.filter( + e => e[1] == "doh" && e[2] == "evaluate_v2" && e[3] == "heuristics" + ); is(events.length, 1, "Found the expected heuristics event."); is(events[0][4], decision, "The event records the expected decision"); if (evaluateReason) { diff --git a/browser/components/preferences/dialogs/connection.js b/browser/components/preferences/dialogs/connection.js index a28ee29829ec..af84740e2ffd 100644 --- a/browser/components/preferences/dialogs/connection.js +++ b/browser/components/preferences/dialogs/connection.js @@ -7,12 +7,6 @@ /* import-globals-from ../../../../toolkit/content/preferencesBindings.js */ /* import-globals-from ../extensionControlled.js */ -ChromeUtils.defineModuleGetter( - this, - "DoHConfigController", - "resource:///modules/DoHConfig.jsm" -); - document .getElementById("ConnectionsDialog") .addEventListener("dialoghelp", window.top.openPrefsHelp); @@ -39,16 +33,13 @@ Preferences.addAll([ { id: "network.proxy.backup.ssl_port", type: "int" }, { id: "network.trr.mode", type: "int" }, { id: "network.trr.uri", type: "string" }, + { id: "network.trr.resolvers", type: "string" }, { id: "network.trr.custom_uri", type: "string" }, { id: "doh-rollout.enabled", type: "bool" }, { id: "doh-rollout.disable-heuristics", type: "bool" }, { id: "doh-rollout.skipHeuristicsCheck", type: "bool" }, ]); -const DoHConfigObserver = () => { - gConnectionsDialog.initDnsOverHttpsUI(); -}; - window.addEventListener( "DOMContentLoaded", () => { @@ -65,20 +56,9 @@ window.addEventListener( gConnectionsDialog.updateDnsOverHttpsUI(); }); - Services.obs.addObserver( - DoHConfigObserver, - DoHConfigController.kConfigUpdateTopic - ); - window.addEventListener( - "unload", - e => { - Services.obs.removeObserver( - DoHConfigObserver, - DoHConfigController.kConfigUpdateTopic - ); - }, - { once: true } - ); + Preferences.get("network.trr.resolvers").on("change", () => { + gConnectionsDialog.initDnsOverHttpsUI(); + }); // XXX: We can't init the DNS-over-HTTPs UI until the onsyncfrompreference for network.trr.mode // has been called. The uiReady promise will be resolved after the first call to @@ -127,12 +107,9 @@ var gConnectionsDialog = { if (customValue) { Services.prefs.setStringPref("network.trr.uri", customValue); } else { - Services.prefs.setStringPref( - "network.trr.uri", - DoHConfigController.currentConfig.fallbackProviderURI - ); + Services.prefs.clearUserPref("network.trr.uri"); } - } else if (this.isDnsOverHttpsEnabled()) { + } else { Services.prefs.setStringPref( "network.trr.uri", dnsOverHttpsResolverChoice @@ -422,14 +399,30 @@ var gConnectionsDialog = { }, get dnsOverHttpsResolvers() { - let providers = DoHConfigController.currentConfig.providerList; + let rawValue = Preferences.get("network.trr.resolvers", "").value; // if there's no default, we'll hold its position with an empty string - let defaultURI = DoHConfigController.currentConfig.fallbackProviderURI; - let defaultIndex = providers.findIndex(p => p.uri == defaultURI); + let defaultURI = Preferences.get("network.trr.uri", "").defaultValue; + let providers = []; + if (rawValue) { + try { + providers = JSON.parse(rawValue); + } catch (ex) { + Cu.reportError( + `Bad JSON data in pref network.trr.resolvers: ${rawValue}` + ); + } + } + if (!Array.isArray(providers)) { + Cu.reportError( + `Expected a JSON array in network.trr.resolvers: ${rawValue}` + ); + providers = []; + } + let defaultIndex = providers.findIndex(p => p.url == defaultURI); if (defaultIndex == -1 && defaultURI) { // the default value for the pref isn't included in the resolvers list // so we'll make a stub for it. Without an id, we'll have to use the url as the label - providers.unshift({ uri: defaultURI }); + providers.unshift({ url: defaultURI }); } return providers; }, @@ -498,7 +491,7 @@ var gConnectionsDialog = { if ( currentURI && !customURI && - !resolvers.find(r => r.uri == currentURI) + !resolvers.find(r => r.url == currentURI) ) { Services.prefs.setStringPref("network.trr.custom_uri", currentURI); } @@ -543,24 +536,24 @@ var gConnectionsDialog = { initDnsOverHttpsUI() { let resolvers = this.dnsOverHttpsResolvers; - let defaultURI = DoHConfigController.currentConfig.fallbackProviderURI; + let defaultURI = Preferences.get("network.trr.uri").defaultValue; let currentURI = Preferences.get("network.trr.uri").value; let menu = document.getElementById("networkDnsOverHttpsResolverChoices"); // populate the DNS-Over-HTTPs resolver list menu.removeAllItems(); for (let resolver of resolvers) { - let item = menu.appendItem(undefined, resolver.uri); - if (resolver.uri == defaultURI) { + let item = menu.appendItem(undefined, resolver.url); + if (resolver.url == defaultURI) { document.l10n.setAttributes( item, "connection-dns-over-https-url-item-default", { - name: resolver.UIName || resolver.uri, + name: resolver.name || resolver.url, } ); } else { - item.label = resolver.UIName || resolver.uri; + item.label = resolver.name || resolver.url; } } let lastItem = menu.appendItem(undefined, "custom"); @@ -571,7 +564,7 @@ var gConnectionsDialog = { // set initial selection in the resolver provider picker let selectedIndex = currentURI - ? resolvers.findIndex(r => r.uri == currentURI) + ? resolvers.findIndex(r => r.url == currentURI) : 0; if (selectedIndex == -1) { // select the last "Custom" item diff --git a/browser/components/preferences/tests/browser_connection_dnsoverhttps.js b/browser/components/preferences/tests/browser_connection_dnsoverhttps.js index 200cba069ca0..6998825abdb3 100644 --- a/browser/components/preferences/tests/browser_connection_dnsoverhttps.js +++ b/browser/components/preferences/tests/browser_connection_dnsoverhttps.js @@ -1,10 +1,3 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -requestLongerTimeout(2); - var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.defineModuleGetter( @@ -12,34 +5,29 @@ ChromeUtils.defineModuleGetter( "DoHController", "resource:///modules/DoHController.jsm" ); -ChromeUtils.defineModuleGetter( - this, - "DoHConfigController", - "resource:///modules/DoHConfig.jsm" -); -ChromeUtils.defineModuleGetter( - this, - "DoHTestUtils", - "resource://testing-common/DoHTestUtils.jsm" -); const SUBDIALOG_URL = "chrome://browser/content/preferences/dialogs/connection.xhtml"; const TRR_MODE_PREF = "network.trr.mode"; const TRR_URI_PREF = "network.trr.uri"; +const TRR_RESOLVERS_PREF = "network.trr.resolvers"; const TRR_CUSTOM_URI_PREF = "network.trr.custom_uri"; const ROLLOUT_ENABLED_PREF = "doh-rollout.enabled"; const ROLLOUT_SELF_ENABLED_PREF = "doh-rollout.self-enabled"; const HEURISTICS_DISABLED_PREF = "doh-rollout.disable-heuristics"; -const FIRST_RESOLVER_VALUE = DoHTestUtils.providers[0].uri; -const SECOND_RESOLVER_VALUE = DoHTestUtils.providers[1].uri; -const DEFAULT_RESOLVER_VALUE = FIRST_RESOLVER_VALUE; +const DEFAULT_RESOLVER_VALUE = "https://mozilla.cloudflare-dns.com/dns-query"; +const NEXTDNS_RESOLVER_VALUE = "https://firefox.dns.nextdns.io/"; const modeCheckboxSelector = "#networkDnsOverHttps"; const uriTextboxSelector = "#networkCustomDnsOverHttpsInput"; const resolverMenulistSelector = "#networkDnsOverHttpsResolverChoices"; const defaultPrefValues = Object.freeze({ [TRR_MODE_PREF]: 0, + [TRR_URI_PREF]: "https://mozilla.cloudflare-dns.com/dns-query", + [TRR_RESOLVERS_PREF]: JSON.stringify([ + { name: "Cloudflare", url: DEFAULT_RESOLVER_VALUE }, + { name: "example.org", url: "https://example.org/dns-query" }, + ]), [TRR_CUSTOM_URI_PREF]: "", }); @@ -47,6 +35,7 @@ async function resetPrefs() { await DoHController._uninit(); Services.prefs.clearUserPref(TRR_MODE_PREF); Services.prefs.clearUserPref(TRR_URI_PREF); + Services.prefs.clearUserPref(TRR_RESOLVERS_PREF); Services.prefs.clearUserPref(TRR_CUSTOM_URI_PREF); Services.prefs.getChildList("doh-rollout.").forEach(pref => { Services.prefs.clearUserPref(pref); @@ -55,13 +44,12 @@ async function resetPrefs() { // confuse tests running after this one that are looking at those. Services.telemetry.clearEvents(); await DoHController.init(); - await DoHTestUtils.resetRemoteSettingsConfig(); } Services.prefs.setStringPref("network.trr.confirmationNS", "skip"); let preferencesOpen = new Promise(res => open_preferences(res)); -registerCleanupFunction(async () => { - await resetPrefs(); +registerCleanupFunction(() => { + resetPrefs(); gBrowser.removeCurrentTab(); Services.prefs.clearUserPref("network.trr.confirmationNS"); }); @@ -134,6 +122,10 @@ async function testWithProperties(props, startTime) { if (props.hasOwnProperty(TRR_URI_PREF)) { Services.prefs.setStringPref(TRR_URI_PREF, props[TRR_URI_PREF]); } + if (props.hasOwnProperty(TRR_RESOLVERS_PREF)) { + info(`Setting ${TRR_RESOLVERS_PREF} to ${props[TRR_RESOLVERS_PREF]}`); + Services.prefs.setStringPref(TRR_RESOLVERS_PREF, props[TRR_RESOLVERS_PREF]); + } let dialog = await openConnectionsSubDialog(); await dialog.uiReady; @@ -271,19 +263,12 @@ async function testWithProperties(props, startTime) { info(Date.now() - startTime + ": testWithProperties: prefs changed"); if (props.hasOwnProperty("expectedFinalUriPref")) { - if (props.expectedFinalUriPref) { - let uriPref = Services.prefs.getStringPref(TRR_URI_PREF); - is( - uriPref, - props.expectedFinalUriPref, - "uri pref ended up with the expected value" - ); - } else { - ok( - !Services.prefs.prefHasUserValue(TRR_URI_PREF), - "uri pref ended up with the expected value (unset)" - ); - } + let uriPref = Services.prefs.getStringPref(TRR_URI_PREF); + is( + uriPref, + props.expectedFinalUriPref, + "uri pref ended up with the expected value" + ); } if (props.hasOwnProperty("expectedModePref")) { @@ -320,16 +305,17 @@ async function testWithProperties(props, startTime) { add_task(async function default_values() { let customUriPref = Services.prefs.getStringPref(TRR_CUSTOM_URI_PREF); - let uriPrefHasUserValue = Services.prefs.prefHasUserValue(TRR_URI_PREF); + let uriPref = Services.prefs.getStringPref(TRR_URI_PREF); let modePref = Services.prefs.getIntPref(TRR_MODE_PREF); is( modePref, defaultPrefValues[TRR_MODE_PREF], `Actual value of ${TRR_MODE_PREF} matches expected default value` ); - ok( - !uriPrefHasUserValue, - `Actual value of ${TRR_URI_PREF} matches expected default value (unset)` + is( + uriPref, + defaultPrefValues[TRR_URI_PREF], + `Actual value of ${TRR_URI_PREF} matches expected default value` ); is( customUriPref, @@ -348,6 +334,7 @@ let testVariations = [ name: "mode 1", [TRR_MODE_PREF]: 1, expectedModeChecked: false, + expectedFinalUriPref: DEFAULT_RESOLVER_VALUE, }, { name: "mode 2", @@ -365,6 +352,7 @@ let testVariations = [ name: "mode 4", [TRR_MODE_PREF]: 4, expectedModeChecked: false, + expectedFinalUriPref: DEFAULT_RESOLVER_VALUE, }, { name: "mode 5", [TRR_MODE_PREF]: 5, expectedModeChecked: false }, // verify an out of bounds mode value maps to the correct checked state @@ -428,14 +416,14 @@ let testVariations = [ { name: "Select NextDNS as TRR provider", [TRR_MODE_PREF]: 2, - selectResolver: SECOND_RESOLVER_VALUE, - expectedFinalUriPref: SECOND_RESOLVER_VALUE, + selectResolver: NEXTDNS_RESOLVER_VALUE, + expectedFinalUriPref: NEXTDNS_RESOLVER_VALUE, }, { name: "return to default from NextDNS", [TRR_MODE_PREF]: 2, - [TRR_URI_PREF]: SECOND_RESOLVER_VALUE, - expectedResolverListValue: SECOND_RESOLVER_VALUE, + [TRR_URI_PREF]: NEXTDNS_RESOLVER_VALUE, + expectedResolverListValue: NEXTDNS_RESOLVER_VALUE, selectResolver: DEFAULT_RESOLVER_VALUE, expectedFinalUriPref: DEFAULT_RESOLVER_VALUE, }, @@ -486,9 +474,11 @@ let testVariations = [ }, { name: "empty default resolver list", + [TRR_RESOLVERS_PREF]: "", [TRR_MODE_PREF]: 2, [TRR_URI_PREF]: "https://example.com", [TRR_CUSTOM_URI_PREF]: "", + [TRR_RESOLVERS_PREF]: "", expectedUriValue: "https://example.com", expectedResolverListValue: "custom", expectedFinalUriPref: "https://example.com", diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 3cfec55c2f96..9ce0788934aa 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -9414,12 +9414,6 @@ value: 1048576 mirror: always -# Default global TRR provider -- name: network.trr.default_provider_uri - type: String - value: "https://mozilla.cloudflare-dns.com/dns-query" - mirror: never - # Single TRR request timeout, in milliseconds - name: network.trr.request_timeout_ms type: RelaxedAtomicUint32 diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 23fca1b57db4..8acc49e2ff90 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -3926,7 +3926,11 @@ pref("network.connectivity-service.IPv6.url", "http://detectportal.firefox.com/s // DNS Trusted Recursive Resolver // 0 - default off, 1 - reserved/off, 2 - TRR first, 3 - TRR only, 4 - reserved/off, 5 off by choice pref("network.trr.mode", 0); -pref("network.trr.uri", ""); +// DNS-over-HTTP service to use, must be HTTPS:// +pref("network.trr.uri", "https://mozilla.cloudflare-dns.com/dns-query"); +// List of DNS-over-HTTP resolver service providers. This pref populates the +// drop-down list in the Network Settings dialog box in about:preferences. +pref("network.trr.resolvers", "[{ \"name\": \"Cloudflare\", \"url\": \"https://mozilla.cloudflare-dns.com/dns-query\" },{ \"name\": \"NextDNS\", \"url\": \"https://firefox.dns.nextdns.io/\" }]"); // credentials to pass to DOH end-point pref("network.trr.credentials", ""); pref("network.trr.custom_uri", ""); diff --git a/netwerk/dns/TRRService.cpp b/netwerk/dns/TRRService.cpp index 313ab1731428..6e85f8d5cad7 100644 --- a/netwerk/dns/TRRService.cpp +++ b/netwerk/dns/TRRService.cpp @@ -372,7 +372,6 @@ nsresult TRRService::ReadPrefs(const char* name) { } } if (!name || !strcmp(name, TRR_PREF("uri")) || - !strcmp(name, TRR_PREF("default_provider_uri")) || !strcmp(name, kRolloutURIPref)) { OnTRRURIChange(); } diff --git a/netwerk/dns/TRRServiceBase.cpp b/netwerk/dns/TRRServiceBase.cpp index 3320f8b9a4e0..cbe7f7b1f905 100644 --- a/netwerk/dns/TRRServiceBase.cpp +++ b/netwerk/dns/TRRServiceBase.cpp @@ -13,7 +13,6 @@ #include "nsIDNSService.h" // Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. #include "DNSLogging.h" -#include "mozilla/StaticPrefs_network.h" namespace mozilla { namespace net { @@ -86,7 +85,7 @@ void TRRServiceBase::CheckURIPrefs() { } // Otherwise just use the default value. - MaybeSetPrivateURI(mDefaultURIPref); + MaybeSetPrivateURI(mURIPref); } // static @@ -145,7 +144,6 @@ void TRRServiceBase::OnTRRURIChange() { mURIPrefHasUserValue = Preferences::HasUserValue("network.trr.uri"); Preferences::GetCString("network.trr.uri", mURIPref); Preferences::GetCString(kRolloutURIPref, mRolloutURIPref); - Preferences::GetCString("network.trr.default_provider_uri", mDefaultURIPref); CheckURIPrefs(); } diff --git a/netwerk/dns/TRRServiceBase.h b/netwerk/dns/TRRServiceBase.h index 4ca143231055..438e3602db6d 100644 --- a/netwerk/dns/TRRServiceBase.h +++ b/netwerk/dns/TRRServiceBase.h @@ -44,7 +44,6 @@ class TRRServiceBase { bool mURIPrefHasUserValue = false; nsCString mURIPref; nsCString mRolloutURIPref; - nsCString mDefaultURIPref; Atomic mMode; Atomic mURISetByDetection; diff --git a/netwerk/test/unit/test_trr.js b/netwerk/test/unit/test_trr.js index b7843f7a0b85..813fd8c10e78 100644 --- a/netwerk/test/unit/test_trr.js +++ b/netwerk/test/unit/test_trr.js @@ -534,9 +534,9 @@ add_task(async function test_detected_uri() { dns.clearCache(true); Services.prefs.setIntPref("network.trr.mode", 3); Services.prefs.clearUserPref("network.trr.uri"); - let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri"); + let defaultURI = gDefaultPref.getCharPref("network.trr.uri"); gDefaultPref.setCharPref( - "network.trr.default_provider_uri", + "network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6` ); await new TRRDNSListener("domainA.example.org.", "3.4.5.6"); @@ -544,7 +544,7 @@ add_task(async function test_detected_uri() { `https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4` ); await new TRRDNSListener("domainB.example.org.", "1.2.3.4"); - gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI); + gDefaultPref.setCharPref("network.trr.uri", defaultURI); // With a user-set doh uri this time. dns.clearCache(true); @@ -562,7 +562,7 @@ add_task(async function test_detected_uri() { Services.prefs.setIntPref("network.trr.mode", 3); Services.prefs.clearUserPref("network.trr.uri"); gDefaultPref.setCharPref( - "network.trr.default_provider_uri", + "network.trr.uri", `https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6` ); await new TRRDNSListener("domainA.example.org.", "3.4.5.6"); @@ -584,15 +584,15 @@ add_task(async function test_detected_uri() { await new TRRDNSListener("domainC.example.org.", "3.4.5.6"); - gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI); + gDefaultPref.setCharPref("network.trr.uri", defaultURI); }); add_task(async function test_pref_changes() { info("Testing pref change handling"); Services.prefs.clearUserPref("network.trr.uri"); - let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri"); + let defaultURI = gDefaultPref.getCharPref("network.trr.uri"); - async function doThenCheckURI(closure, expectedURI, expectChange = true) { + async function doThenCheckURI(closure, expectedURI, expectChange = false) { let uriChanged; if (expectChange) { uriChanged = topicObserved("network:trr-uri-changed"); @@ -607,7 +607,7 @@ add_task(async function test_pref_changes() { // setting the default value of the pref should be reflected in the URI await doThenCheckURI(() => { gDefaultPref.setCharPref( - "network.trr.default_provider_uri", + "network.trr.uri", `https://foo.example.com:${h2Port}/doh?default` ); }, `https://foo.example.com:${h2Port}/doh?default`); @@ -690,7 +690,7 @@ add_task(async function test_pref_changes() { ); // Restore the pref - gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI); + gDefaultPref.setCharPref("network.trr.uri", defaultURI); }); add_task(async function test_dohrollout_mode() { diff --git a/netwerk/test/unit/test_trr_confirmation.js b/netwerk/test/unit/test_trr_confirmation.js index 26b05c1a9895..bfcac9791d50 100644 --- a/netwerk/test/unit/test_trr_confirmation.js +++ b/netwerk/test/unit/test_trr_confirmation.js @@ -371,11 +371,9 @@ add_task(async function test_uri_pref_change() { add_task(async function test_autodetected_uri() { const defaultPrefBranch = Services.prefs.getDefaultBranch(""); - let defaultURI = defaultPrefBranch.getCharPref( - "network.trr.default_provider_uri" - ); + let defaultURI = defaultPrefBranch.getCharPref("network.trr.uri"); defaultPrefBranch.setCharPref( - "network.trr.default_provider_uri", + "network.trr.uri", `https://foo.example.com:${trrServer.port}/dns-query?changed` ); // For setDetectedTrrURI to work we must pretend we are using the default. @@ -396,5 +394,5 @@ add_task(async function test_autodetected_uri() { ); // reset the default URI - defaultPrefBranch.setCharPref("network.trr.default_provider_uri", defaultURI); + defaultPrefBranch.setCharPref("network.trr.uri", defaultURI); });