summaryrefslogtreecommitdiffstats
path: root/netwerk/test/unit/test_trr_confirmation.js
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/unit/test_trr_confirmation.js')
-rw-r--r--netwerk/test/unit/test_trr_confirmation.js401
1 files changed, 401 insertions, 0 deletions
diff --git a/netwerk/test/unit/test_trr_confirmation.js b/netwerk/test/unit/test_trr_confirmation.js
new file mode 100644
index 0000000000..f7e50418b9
--- /dev/null
+++ b/netwerk/test/unit/test_trr_confirmation.js
@@ -0,0 +1,401 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+
+async function waitForConfirmationState(state, msToWait = 0) {
+ await TestUtils.waitForCondition(
+ () => Services.dns.currentTrrConfirmationState == state,
+ `Timed out waiting for ${state}. Currently ${Services.dns.currentTrrConfirmationState}`,
+ 1,
+ msToWait
+ );
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ state,
+ "expected confirmation state"
+ );
+}
+
+const CONFIRM_OFF = 0;
+const CONFIRM_TRYING_OK = 1;
+const CONFIRM_OK = 2;
+const CONFIRM_FAILED = 3;
+const CONFIRM_TRYING_FAILED = 4;
+const CONFIRM_DISABLED = 5;
+
+function setup() {
+ trr_test_setup();
+ Services.prefs.setBoolPref("network.trr.skip-check-for-blocked-host", true);
+}
+
+setup();
+registerCleanupFunction(async () => {
+ trr_clear_prefs();
+ Services.prefs.clearUserPref("network.trr.skip-check-for-blocked-host");
+});
+
+let trrServer = null;
+add_task(async function start_trr_server() {
+ trrServer = new TRRServer();
+ registerCleanupFunction(async () => {
+ await trrServer.stop();
+ });
+ await trrServer.start();
+ dump(`port = ${trrServer.port}\n`);
+
+ await trrServer.registerDoHAnswers(`faily.com`, "NS", {
+ answers: [
+ {
+ name: "faily.com",
+ ttl: 55,
+ type: "NS",
+ flush: false,
+ data: "ns.faily.com",
+ },
+ ],
+ });
+
+ for (let i = 0; i < 15; i++) {
+ await trrServer.registerDoHAnswers(`failing-domain${i}.faily.com`, "A", {
+ error: 600,
+ });
+ await trrServer.registerDoHAnswers(`failing-domain${i}.faily.com`, "AAAA", {
+ error: 600,
+ });
+ }
+});
+
+function trigger15Failures() {
+ // We need to clear the cache in case a previous call to this method
+ // put the results in the DNS cache.
+ Services.dns.clearCache(true);
+
+ let dnsRequests = [];
+ // There are actually two TRR requests sent for A and AAAA records, so doing
+ // DNS query 10 times should be enough to trigger confirmation process.
+ for (let i = 0; i < 10; i++) {
+ dnsRequests.push(
+ new TRRDNSListener(`failing-domain${i}.faily.com`, {
+ expectedAnswer: "127.0.0.1",
+ })
+ );
+ }
+
+ return Promise.all(dnsRequests);
+}
+
+async function registerNS(delay) {
+ return trrServer.registerDoHAnswers("confirm.example.com", "NS", {
+ answers: [
+ {
+ name: "confirm.example.com",
+ ttl: 55,
+ type: "NS",
+ flush: false,
+ data: "test.com",
+ },
+ ],
+ delay,
+ });
+}
+
+add_task(async function confirm_off() {
+ Services.prefs.setCharPref(
+ "network.trr.confirmationNS",
+ "confirm.example.com"
+ );
+ Services.prefs.setIntPref(
+ "network.trr.mode",
+ Ci.nsIDNSService.MODE_NATIVEONLY
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OFF);
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRROFF);
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OFF);
+});
+
+add_task(async function confirm_disabled() {
+ Services.prefs.setCharPref(
+ "network.trr.confirmationNS",
+ "confirm.example.com"
+ );
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRONLY);
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_DISABLED);
+ Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_DISABLED);
+});
+
+add_task(async function confirm_ok() {
+ Services.dns.clearCache(true);
+ Services.prefs.setCharPref(
+ "network.trr.confirmationNS",
+ "confirm.example.com"
+ );
+ await registerNS(0);
+ await trrServer.registerDoHAnswers("example.com", "A", {
+ answers: [
+ {
+ name: "example.com",
+ ttl: 55,
+ type: "A",
+ flush: false,
+ data: "1.2.3.4",
+ },
+ ],
+ });
+ Services.prefs.setCharPref(
+ "network.trr.uri",
+ `https://foo.example.com:${trrServer.port}/dns-query`
+ );
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await new TRRDNSListener("example.com", { expectedAnswer: "1.2.3.4" });
+ equal(await trrServer.requestCount("example.com", "A"), 1);
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+
+ await registerNS(500);
+ Services.prefs.setIntPref(
+ "network.trr.mode",
+ Ci.nsIDNSService.MODE_NATIVEONLY
+ );
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await new Promise(resolve => do_timeout(100, resolve));
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Confirmation should still be pending"
+ );
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+});
+
+add_task(async function confirm_timeout() {
+ Services.prefs.setIntPref(
+ "network.trr.mode",
+ Ci.nsIDNSService.MODE_NATIVEONLY
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OFF);
+ await registerNS(7000);
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await waitForConfirmationState(CONFIRM_FAILED, 7500);
+ // After the confirmation fails, a timer will periodically trigger a retry
+ // causing the state to go into CONFIRM_TRYING_FAILED.
+ await waitForConfirmationState(CONFIRM_TRYING_FAILED, 500);
+});
+
+add_task(async function confirm_fail_fast() {
+ Services.prefs.setIntPref(
+ "network.trr.mode",
+ Ci.nsIDNSService.MODE_NATIVEONLY
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OFF);
+ await trrServer.registerDoHAnswers("confirm.example.com", "NS", {
+ error: 404,
+ });
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await waitForConfirmationState(CONFIRM_FAILED, 100);
+});
+
+add_task(async function multiple_failures() {
+ Services.prefs.setIntPref(
+ "network.trr.mode",
+ Ci.nsIDNSService.MODE_NATIVEONLY
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OFF);
+
+ await registerNS(100);
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+ await registerNS(4000);
+ let failures = trigger15Failures();
+ await waitForConfirmationState(CONFIRM_TRYING_OK, 3000);
+ await failures;
+ // Check that failures during confirmation are ignored.
+ await trigger15Failures();
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await waitForConfirmationState(CONFIRM_OK, 4500);
+});
+
+add_task(async function test_connectivity_change() {
+ await registerNS(100);
+ Services.prefs.setIntPref(
+ "network.trr.mode",
+ Ci.nsIDNSService.MODE_NATIVEONLY
+ );
+ let confirmationCount = await trrServer.requestCount(
+ "confirm.example.com",
+ "NS"
+ );
+ Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST);
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+ equal(
+ await trrServer.requestCount("confirm.example.com", "NS"),
+ confirmationCount + 1
+ );
+ Services.obs.notifyObservers(
+ null,
+ "network:captive-portal-connectivity",
+ "clear"
+ );
+ // This means a CP check completed successfully. But no CP was previously
+ // detected, so this is mostly a no-op.
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OK);
+
+ Services.obs.notifyObservers(
+ null,
+ "network:captive-portal-connectivity",
+ "captive"
+ );
+ // This basically a successful CP login event. Wasn't captive before.
+ // Still treating as a no-op.
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OK);
+
+ // This makes the TRR service set mCaptiveIsPassed=false
+ Services.obs.notifyObservers(
+ null,
+ "captive-portal-login",
+ "{type: 'captive-portal-login', id: 0, url: 'http://localhost/'}"
+ );
+
+ await registerNS(500);
+ let failures = trigger15Failures();
+ // The failure should cause us to go into CONFIRM_TRYING_OK and do an NS req
+ await waitForConfirmationState(CONFIRM_TRYING_OK, 3000);
+ await failures;
+
+ // The notification sets mCaptiveIsPassed=true then triggers an entirely new
+ // confirmation.
+ Services.obs.notifyObservers(
+ null,
+ "network:captive-portal-connectivity",
+ "clear"
+ );
+ // The notification should cause us to send a new confirmation request
+ equal(
+ Services.dns.currentTrrConfirmationState,
+ CONFIRM_TRYING_OK,
+ "Should be CONFIRM_TRYING_OK"
+ );
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+ // two extra confirmation events should have been received by the server
+ equal(
+ await trrServer.requestCount("confirm.example.com", "NS"),
+ confirmationCount + 3
+ );
+});
+
+add_task(async function test_network_change() {
+ let confirmationCount = await trrServer.requestCount(
+ "confirm.example.com",
+ "NS"
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OK);
+
+ Services.obs.notifyObservers(null, "network:link-status-changed", "up");
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OK);
+ equal(
+ await trrServer.requestCount("confirm.example.com", "NS"),
+ confirmationCount
+ );
+
+ let failures = trigger15Failures();
+ // The failure should cause us to go into CONFIRM_TRYING_OK and do an NS req
+ await waitForConfirmationState(CONFIRM_TRYING_OK, 3000);
+ await failures;
+ // The network up event should reset the confirmation to TRYING_OK and do
+ // another NS req
+ Services.obs.notifyObservers(null, "network:link-status-changed", "up");
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_TRYING_OK);
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+ // two extra confirmation events should have been received by the server
+ equal(
+ await trrServer.requestCount("confirm.example.com", "NS"),
+ confirmationCount + 2
+ );
+});
+
+add_task(async function test_uri_pref_change() {
+ let confirmationCount = await trrServer.requestCount(
+ "confirm.example.com",
+ "NS"
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_OK);
+ Services.prefs.setCharPref(
+ "network.trr.uri",
+ `https://foo.example.com:${trrServer.port}/dns-query?changed`
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_TRYING_OK);
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+ equal(
+ await trrServer.requestCount("confirm.example.com", "NS"),
+ confirmationCount + 1
+ );
+});
+
+add_task(async function test_autodetected_uri() {
+ const defaultPrefBranch = Services.prefs.getDefaultBranch("");
+ let defaultURI = defaultPrefBranch.getCharPref(
+ "network.trr.default_provider_uri"
+ );
+ defaultPrefBranch.setCharPref(
+ "network.trr.default_provider_uri",
+ `https://foo.example.com:${trrServer.port}/dns-query?changed`
+ );
+ // For setDetectedTrrURI to work we must pretend we are using the default.
+ Services.prefs.clearUserPref("network.trr.uri");
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+ let confirmationCount = await trrServer.requestCount(
+ "confirm.example.com",
+ "NS"
+ );
+ Services.dns.setDetectedTrrURI(
+ `https://foo.example.com:${trrServer.port}/dns-query?changed2`
+ );
+ equal(Services.dns.currentTrrConfirmationState, CONFIRM_TRYING_OK);
+ await waitForConfirmationState(CONFIRM_OK, 1000);
+ equal(
+ await trrServer.requestCount("confirm.example.com", "NS"),
+ confirmationCount + 1
+ );
+
+ // reset the default URI
+ defaultPrefBranch.setCharPref("network.trr.default_provider_uri", defaultURI);
+});