/* 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/. */
async function test_A_record() {
info("Verifying a basic A record");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2"); // TRR-first
await new TRRDNSListener("bar.example.com", "2.2.2.2");
info("Verifying a basic A record - without bootstrapping");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=3.3.3.3"); // TRR-only
// Clear bootstrap address and add DoH endpoint hostname to local domains
Services.prefs.clearUserPref("network.trr.bootstrapAddr");
Services.prefs.setCharPref("network.dns.localDomains", TRR_Domain);
await new TRRDNSListener("bar.example.com", "3.3.3.3");
info("Verify that the cached record is used when DoH endpoint is down"); // Don't clear the cache. That is what we're checking.
setModeAndURI(3, "404");
await new TRRDNSListener("bar.example.com", "3.3.3.3");
info("verify working credentials in DOH request");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=4.4.4.4&auth=true");
Services.prefs.setCharPref("network.trr.credentials", "user:password");
await new TRRDNSListener("bar.example.com", "4.4.4.4");
let { inStatus } = await new TRRDNSListener( "wrong.example.com",
undefined, false
); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
await new TRRDNSListener("aaaa.example.com", "2020:2020::2020");
}
async function test_RFC1918() {
info("Verifying that RFC1918 address from the server is rejected by default");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=192.168.0.1");
let { inStatus } = await new TRRDNSListener( "rfc1918.example.com",
undefined, false
);
Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
setModeAndURI(3, "doh?responseIP=::ffff:192.168.0.1");
({ inStatus } = await new TRRDNSListener( "rfc1918-ipv6.example.com",
undefined, false
)); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
info("Verify RFC1918 address from the server is fine when told so");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=192.168.0.1");
Services.prefs.setBoolPref("network.trr.allow-rfc1918", true);
await new TRRDNSListener("rfc1918.example.com", "192.168.0.1");
setModeAndURI(3, "doh?responseIP=::ffff:192.168.0.1");
await new TRRDNSListener("rfc1918-ipv6.example.com", "::ffff:192.168.0.1");
async function test_GET_ECS() {
info("Verifying resolution via GET with ECS disabled");
Services.dns.clearCache(true); // The template part should be discarded
setModeAndURI(3, "doh{?dns}");
Services.prefs.setBoolPref("network.trr.useGET", true);
Services.prefs.setBoolPref("network.trr.disable-ECS", true);
await new TRRDNSListener("ecs.example.com", "5.5.5.5");
info("Verifying resolution via GET with ECS enabled");
Services.dns.clearCache(true);
setModeAndURI(3, "doh");
Services.prefs.setBoolPref("network.trr.disable-ECS", false);
await new TRRDNSListener("get.example.com", "5.5.5.5");
async function test_timeout_mode3() {
info("Verifying that a short timeout causes failure with a slow server");
Services.dns.clearCache(true); // First, mode 3.
setModeAndURI(3, "doh?noResponse=true");
Services.prefs.setIntPref("network.trr.request_timeout_ms", 10);
Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10);
let { inStatus } = await new TRRDNSListener( "timeout.example.com",
undefined, false
); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
// Now for mode 2
Services.dns.clearCache(true);
setModeAndURI(2, "doh?noResponse=true");
await new TRRDNSListener("timeout.example.com", "127.0.0.1"); // Should fallback
let { inStatus } = await new TRRDNSListener( "timeout.example.com",
undefined, false
); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
Services.dns.clearCache(true);
await new TRRDNSListener("timeout.example.com", undefined, false);
info("Now a connection error");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2");
Services.prefs.clearUserPref("network.trr.request_timeout_ms");
Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");
Services.prefs.clearUserPref( "network.trr.strict_fallback_request_timeout_ms"
);
({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false)); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
info("Now a decode error");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2&corruptedAnswer=true");
({ inStatus } = await new TRRDNSListener( "bar.example.com",
undefined, false
)); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
if (!mozinfo.socketprocess_networking) { // Confirmation state isn't passed cross-process.
info("Now with confirmation failed - should fallback");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2&corruptedAnswer=true");
Services.prefs.setCharPref("network.trr.confirmationNS", "example.com");
await TestUtils.waitForCondition( // 3 => CONFIRM_FAILED, 4 => CONFIRM_TRYING_FAILED
() =>
Services.dns.currentTrrConfirmationState == 3 ||
Services.dns.currentTrrConfirmationState == 4,
`Timed out waiting for confirmation failure. Currently ${Services.dns.currentTrrConfirmationState}`,
1,
5000
);
await new TRRDNSListener("bar.example.com", "127.0.0.1"); // Should fallback
}
info("Now a successful case.");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2"); if (!mozinfo.socketprocess_networking) { // Only need to reset confirmation state if we messed with it before.
Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
await TestUtils.waitForCondition( // 5 => CONFIRM_DISABLED
() => Services.dns.currentTrrConfirmationState == 5,
`Timed out waiting for confirmation disabled. Currently ${Services.dns.currentTrrConfirmationState}`,
1,
5000
);
}
await new TRRDNSListener("bar.example.com", "2.2.2.2");
await new TRRDNSListener("timeout.example.com", "127.0.0.1"); // Should fallback
info("Now a connection error");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2");
Services.prefs.clearUserPref("network.trr.request_timeout_ms");
Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");
Services.prefs.clearUserPref( "network.trr.strict_fallback_request_timeout_ms"
);
await new TRRDNSListener("closeme.com", "127.0.0.1"); // Should fallback
info("Now a decode error");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2&corruptedAnswer=true");
await new TRRDNSListener("bar.example.com", "127.0.0.1"); // Should fallback
async function test_no_answers_fallback() {
info("Verfiying that we correctly fallback to Do53 when no answers from DoH");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=none"); // TRR-first
await new TRRDNSListener("confirm.example.com", "127.0.0.1");
info("Now in strict mode - no fallback");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", true);
Services.dns.clearCache(true);
await new TRRDNSListener("confirm.example.com", "127.0.0.1");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", false);
}
async function test_404_fallback() {
info("Verfiying that we correctly fallback to Do53 when DoH sends 404");
Services.dns.clearCache(true);
setModeAndURI(2, "404"); // TRR-first
await new TRRDNSListener("test404.example.com", "127.0.0.1");
info("Now in strict mode - no fallback");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", true);
Services.dns.clearCache(true);
let { inStatus } = await new TRRDNSListener("test404.example.com", {
expectedSuccess: false,
}); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
Services.prefs.setBoolPref("network.trr.strict_native_fallback", false);
}
async function test_mode_1_and_4() {
info("Verifying modes 1 and 4 are treated as TRR-off"); for (let mode of [1, 4]) {
Services.dns.clearCache(true);
setModeAndURI(mode, "doh?responseIP=2.2.2.2"); Assert.equal(
Services.dns.currentTrrMode,
5, "Effective TRR mode should be 5"
);
}
}
async function test_CNAME() {
info("Checking that we follow a CNAME correctly");
Services.dns.clearCache(true); // The dns-cname path alternates between sending us a CNAME pointing to // another domain, and an A record. If we follow the cname correctly, doing // a lookup with this path as the DoH URI should resolve to that A record.
setModeAndURI(3, "dns-cname");
await new TRRDNSListener("cname.example.com", "99.88.77.66");
info("Verifying that we bail out when we're thrown into a CNAME loop");
Services.dns.clearCache(true); // First mode 3.
setModeAndURI(3, "doh?responseIP=none&cnameloop=true");
let { inStatus } = await new TRRDNSListener( "test18.example.com",
undefined, false
); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
// Now mode 2.
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=none&cnameloop=true");
await new TRRDNSListener("test20.example.com", "127.0.0.1"); // Should fallback
info("Check that we correctly handle CNAME bundled with an A record");
Services.dns.clearCache(true); // "dns-cname-a" path causes server to send a CNAME as well as an A record
setModeAndURI(3, "dns-cname-a");
await new TRRDNSListener("cname-a.example.com", "9.8.7.6");
}
async function test_name_mismatch() {
info("Verify that records that don't match the requested name are rejected");
Services.dns.clearCache(true); // Setting hostname param tells server to always send record for bar.example.com // regardless of what was requested.
setModeAndURI(3, "doh?hostname=mismatch.example.com");
let { inStatus } = await new TRRDNSListener( "bar.example.com",
undefined, false
); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
}
async function test_mode_2() {
info("Checking that TRR result is used in mode 2");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=192.192.192.192");
Services.prefs.setCharPref("network.trr.excluded-domains", "");
Services.prefs.setCharPref("network.trr.builtin-excluded-domains", "");
await new TRRDNSListener("bar.example.com", "192.192.192.192");
info("Now in strict mode");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", true);
Services.dns.clearCache(true);
await new TRRDNSListener("bar.example.com", "192.192.192.192");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", false);
}
async function test_excluded_domains() {
info("Checking that Do53 is used for names in excluded-domains list"); for (let strictMode of [true, false]) {
info("Strict mode: " + strictMode);
Services.prefs.setBoolPref( "network.trr.strict_native_fallback",
strictMode
);
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=192.192.192.192");
Services.prefs.setCharPref( "network.trr.excluded-domains", "bar.example.com"
);
await new TRRDNSListener("bar.example.com", "127.0.0.1"); // Do53 result
// The captive portal has to have used native DNS, otherwise creating // a socket to a non-local IP would trigger a crash.
await cpPromise; // Simply resolving the captive portal domain should still use TRR
await new TRRDNSListener("detectportal.firefox.com", "2.2.2.2");
await new Promise(resolve => cpServer.stop(resolve));
}
}
async function test_parentalcontrols() {
info("Check that DoH isn't used when parental controls are enabled");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2");
await SetParentalControlEnabled(true);
await new TRRDNSListener("www.example.com", "127.0.0.1");
await SetParentalControlEnabled(false);
info("Now in strict mode");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", true);
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2");
await SetParentalControlEnabled(true);
await new TRRDNSListener("www.example.com", "127.0.0.1");
await SetParentalControlEnabled(false);
Services.prefs.setBoolPref("network.trr.strict_native_fallback", false);
}
async function test_builtin_excluded_domains() {
info("Verifying Do53 is used for domains in builtin-excluded-domians list"); for (let strictMode of [true, false]) {
info("Strict mode: " + strictMode);
Services.prefs.setBoolPref( "network.trr.strict_native_fallback",
strictMode
);
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2");
Services.prefs.setCharPref("network.trr.excluded-domains", "");
Services.prefs.setCharPref( "network.trr.builtin-excluded-domains", "bar.example.com"
);
await new TRRDNSListener("bar.example.com", "127.0.0.1");
Services.dns.clearCache(true);
Services.prefs.setCharPref( "network.trr.builtin-excluded-domains", "example.com"
);
await new TRRDNSListener("bar.example.com", "127.0.0.1");
Services.dns.clearCache(true);
Services.prefs.setCharPref( "network.trr.builtin-excluded-domains", "foo.test.com, bar.example.com"
);
await new TRRDNSListener("bar.example.com", "127.0.0.1");
await new TRRDNSListener("foo.test.com", "127.0.0.1");
}
}
async function test_excluded_domains_mode3() {
info("Checking Do53 is used for names in excluded-domains list in mode 3");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=192.192.192.192");
Services.prefs.setCharPref("network.trr.excluded-domains", "");
Services.prefs.setCharPref("network.trr.builtin-excluded-domains", "");
await new TRRDNSListener("excluded", "192.192.192.192", true);
await new TRRDNSListener("excluded", "127.0.0.1");
// Test .local
Services.dns.clearCache(true);
Services.prefs.setCharPref("network.trr.excluded-domains", "excluded,local");
await new TRRDNSListener("test.local", "127.0.0.1");
// Test .other
Services.dns.clearCache(true);
Services.prefs.setCharPref( "network.trr.excluded-domains", "excluded,local,other"
);
await new TRRDNSListener("domain.other", "127.0.0.1");
}
async function test25e() {
info("Check captivedetect.canonicalURL is resolved via native DNS in mode 3");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=192.192.192.192");
// The captive portal has to have used native DNS, otherwise creating // a socket to a non-local IP would trigger a crash.
await cpPromise; // // Simply resolving the captive portal domain should still use TRR
await new TRRDNSListener("detectportal.firefox.com", "192.192.192.192");
await new Promise(resolve => cpServer.stop(resolve));
}
async function test_parentalcontrols_mode3() {
info("Check DoH isn't used when parental controls are enabled in mode 3");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=192.192.192.192");
await SetParentalControlEnabled(true);
await new TRRDNSListener("www.example.com", "127.0.0.1");
await SetParentalControlEnabled(false);
}
async function test_builtin_excluded_domains_mode3() {
info("Check Do53 used for domains in builtin-excluded-domians list, mode 3");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=192.192.192.192");
Services.prefs.setCharPref("network.trr.excluded-domains", "");
Services.prefs.setCharPref( "network.trr.builtin-excluded-domains", "excluded"
);
await new TRRDNSListener("excluded", "127.0.0.1");
// Test .local
Services.dns.clearCache(true);
Services.prefs.setCharPref( "network.trr.builtin-excluded-domains", "excluded,local"
);
await new TRRDNSListener("test.local", "127.0.0.1");
// Test .other
Services.dns.clearCache(true);
Services.prefs.setCharPref( "network.trr.builtin-excluded-domains", "excluded,local,other"
);
await new TRRDNSListener("domain.other", "127.0.0.1");
}
async function count_cookies() {
info("Check that none of the requests have set any cookies."); Assert.equal(Services.cookies.countCookiesFromHost("example.com"), 0); Assert.equal(Services.cookies.countCookiesFromHost("foo.example.com."), 0);
}
async function test_connection_closed() {
info("Check we handle it correctly when the connection is closed");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=2.2.2.2");
Services.prefs.setCharPref("network.trr.excluded-domains", ""); // We don't need to wait for 30 seconds for the request to fail
Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 500); // bootstrap
Services.prefs.clearUserPref("network.dns.localDomains");
Services.prefs.setCharPref("network.trr.bootstrapAddr", "127.0.0.1");
await new TRRDNSListener("bar.example.com", "2.2.2.2");
// makes the TRR connection shut down.
let { inStatus } = await new TRRDNSListener("closeme.com", undefined, false); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
await new TRRDNSListener("bar2.example.com", "2.2.2.2");
// No bootstrap this time
Services.prefs.clearUserPref("network.trr.bootstrapAddr");
await new TRRDNSListener("bar.example.com", "2.2.2.2");
// makes the TRR connection shut down.
({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false)); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
await new TRRDNSListener("bar2.example.com", "2.2.2.2");
// No local domains either
Services.dns.clearCache(true);
Services.prefs.setCharPref("network.trr.excluded-domains", "excluded");
Services.prefs.clearUserPref("network.dns.localDomains");
Services.prefs.clearUserPref("network.trr.bootstrapAddr");
await new TRRDNSListener("bar.example.com", "2.2.2.2");
// makes the TRR connection shut down.
({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false)); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
await new TRRDNSListener("bar2.example.com", "2.2.2.2");
// Now make sure that even in mode 3 without a bootstrap address // we are able to restart the TRR connection if it drops - the TRR service // channel will use regular DNS to resolve the TRR address.
Services.dns.clearCache(true);
Services.prefs.setCharPref("network.trr.excluded-domains", "");
Services.prefs.setCharPref("network.trr.builtin-excluded-domains", "");
Services.prefs.clearUserPref("network.dns.localDomains");
Services.prefs.clearUserPref("network.trr.bootstrapAddr");
await new TRRDNSListener("bar.example.com", "2.2.2.2");
// makes the TRR connection shut down.
({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false)); Assert.ok(
!Components.isSuccessCode(inStatus),
`${inStatus} should be an error code`
);
Services.dns.clearCache(true);
await new TRRDNSListener("bar2.example.com", "2.2.2.2");
// This test exists to document what happens when we're in TRR only mode // and we don't set a bootstrap address. We use DNS to resolve the // initial URI, but if the connection fails, we don't fallback to DNS
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=9.9.9.9");
Services.prefs.setCharPref("network.dns.localDomains", "closeme.com");
Services.prefs.clearUserPref("network.trr.bootstrapAddr");
await new TRRDNSListener("bar.example.com", "9.9.9.9");
// makes the TRR connection shut down. Should fallback to DNS
await new TRRDNSListener("closeme.com", "127.0.0.1"); // TRR should be back up again
await new TRRDNSListener("bar2.example.com", "9.9.9.9");
}
async function test_fetch_time() {
info("Verifying timing");
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2&delayIPv4=20");
await new TRRDNSListener("bar_time.example.com", "2.2.2.2", true, 20);
// gets an error from DoH. It will fall back to regular DNS. The TRR timing should be 0.
Services.dns.clearCache(true);
setModeAndURI(2, "404&delayIPv4=20");
await new TRRDNSListener("bar_time1.example.com", "127.0.0.1", true, 0);
// check an excluded domain. It should fall back to regular DNS. The TRR timing should be 0.
Services.prefs.setCharPref( "network.trr.excluded-domains", "bar_time2.example.com"
); for (let strictMode of [true, false]) {
info("Strict mode: " + strictMode);
Services.prefs.setBoolPref( "network.trr.strict_native_fallback",
strictMode
);
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=2.2.2.2&delayIPv4=20");
await new TRRDNSListener("bar_time2.example.com", "127.0.0.1", true, 0);
}
// verify RFC1918 address from the server is rejected and the TRR timing will be not set because the response will be from the native resolver.
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=192.168.0.1&delayIPv4=20");
await new TRRDNSListener("rfc1918_time.example.com", "127.0.0.1", true, 0);
}
async function test_fqdn() {
info("Test that we handle FQDN encoding and decoding properly");
Services.dns.clearCache(true);
setModeAndURI(3, "doh?responseIP=9.8.7.6");
await new TRRDNSListener("fqdn.example.org.", "9.8.7.6");
// GET
Services.dns.clearCache(true);
Services.prefs.setBoolPref("network.trr.useGET", true);
await new TRRDNSListener("fqdn_get.example.org.", "9.8.7.6");
// Should not fallback to Do53 because A request for ipv6.host.com returns // 4.4.4.4
let { inStatus } = await new TRRDNSListener("ipv6.host.com", {
flags: Ci.nsIDNSService.RESOLVE_DISABLE_IPV4,
expectedSuccess: false,
});
equal(inStatus, Cr.NS_ERROR_UNKNOWN_HOST);
// This time both requests fail, so we do fall back
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=none");
await new TRRDNSListener("ipv6.host.com", "1:1::2");
info("In strict mode, the lookup should fail when both reqs fail.");
Services.dns.clearCache(true);
Services.prefs.setBoolPref("network.trr.strict_native_fallback", true);
setModeAndURI(2, "doh?responseIP=none");
await new TRRDNSListener("ipv6.host.com", "1:1::2");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", false);
override.clearOverrides();
}
async function test_ipv4_trr_fallback() {
info("Testing fallback with ipv4");
Services.dns.clearCache(true);
// Should not fallback to Do53 because A request for ipv4.host.com returns // 1:2::3
let { inStatus } = await new TRRDNSListener("ipv4.host.com", {
flags: Ci.nsIDNSService.RESOLVE_DISABLE_IPV6,
expectedSuccess: false,
});
equal(inStatus, Cr.NS_ERROR_UNKNOWN_HOST);
// This time both requests fail, so we do fall back
Services.dns.clearCache(true);
setModeAndURI(2, "doh?responseIP=none");
await new TRRDNSListener("ipv4.host.com", "3.4.5.6");
// No fallback with strict mode.
Services.dns.clearCache(true);
Services.prefs.setBoolPref("network.trr.strict_native_fallback", true);
setModeAndURI(2, "doh?responseIP=none");
await new TRRDNSListener("ipv4.host.com", "3.4.5.6");
Services.prefs.setBoolPref("network.trr.strict_native_fallback", false);
override.clearOverrides();
}
async function test_no_retry_without_doh() {
info("Bug 1648147 - if the TRR returns 0.0.0.0 we should not retry with DNS");
Services.prefs.setBoolPref("network.trr.fallback-on-zero-response", false);
Services.prefs.setBoolPref("network.socket.ip_addr_any.disabled", false);
Services.prefs.setBoolPref("network.trr.allow-rfc1918", true);
async function test(url, ip) {
setModeAndURI(2, `doh?responseIP=${ip}`);
// Requests to 0.0.0.0 are usually directed to localhost, so let's use a port // we know isn't being used - 666 (Doom)
let chan = makeChan(url, Ci.nsIRequest.TRR_DEFAULT_MODE);
let statusCounter = {
statusCount: {},
QueryInterface: ChromeUtils.generateQI([ "nsIInterfaceRequestor", "nsIProgressEventSink",
]),
getInterface(iid) { returnthis.QueryInterface(iid);
},
onProgress() {},
onStatus(request, status) { this.statusCount[status] = 1 + (this.statusCount[status] || 0);
},
};
chan.notificationCallbacks = statusCounter;
await new Promise(resolve =>
chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE))
);
equal(
statusCounter.statusCount[0x4b000b],
1, "Expecting only one instance of NS_NET_STATUS_RESOLVED_HOST"
);
equal(
statusCounter.statusCount[0x4b0007],
1, "Expecting only one instance of NS_NET_STATUS_CONNECTING_TO"
);
}
setModeAndURI(2, `doh?responseIP=9.8.7.6`);
Services.prefs.setBoolPref("network.trr.strict_native_fallback", true);
Services.prefs.setCharPref("network.trr.confirmationNS", "example.com");
await TestUtils.waitForCondition( // 2 => CONFIRM_OK
() => Services.dns.currentTrrConfirmationState == 2,
`Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
1,
5000
);
// Setting conncycle=true in the URI. Server will start logging reqs. // We will do a specific sequence of lookups, then fetch the log from // the server and check that it matches what we'd expect.
setModeAndURI(2, `doh?responseIP=9.8.7.6&conncycle=true`);
await TestUtils.waitForCondition( // 2 => CONFIRM_OK
() => Services.dns.currentTrrConfirmationState == 2,
`Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
1,
5000
); // Confirmation upon uri-change will have created one req.
// Two reqs for each bar1 and bar2 - A + AAAA.
await new TRRDNSListener("bar1.example.org.", "9.8.7.6");
await new TRRDNSListener("bar2.example.org.", "9.8.7.6"); // Total so far: (1) + 2 + 2 = 5
// Two reqs that fail, one Confirmation req, two retried reqs that succeed.
await new TRRDNSListener("newconn.example.org.", "9.8.7.6");
await TestUtils.waitForCondition( // 2 => CONFIRM_OK
() => Services.dns.currentTrrConfirmationState == 2,
`Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
1,
5000
); // Total so far: (5) + 2 + 1 + 2 = 10
// Two reqs for each bar3 and bar4 .
await new TRRDNSListener("bar3.example.org.", "9.8.7.6");
await new TRRDNSListener("bar4.example.org.", "9.8.7.6"); // Total so far: (10) + 2 + 2 = 14.
// Two reqs that fail, one Confirmation req, two retried reqs that succeed.
await new TRRDNSListener("newconn2.example.org.", "9.8.7.6");
await TestUtils.waitForCondition( // 2 => CONFIRM_OK
() => Services.dns.currentTrrConfirmationState == 2,
`Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
1,
5000
); // Total so far: (14) + 2 + 1 + 2 = 19
// Two reqs for each bar5 and bar6 .
await new TRRDNSListener("bar5.example.org.", "9.8.7.6");
await new TRRDNSListener("bar6.example.org.", "9.8.7.6"); // Total so far: (19) + 2 + 2 = 23
let chan = makeChan(
`https://foo.example.com:${h2Port}/get-doh-req-port-log`,
Ci.nsIRequest.TRR_DISABLED_MODE
);
let dohReqPortLog = await new Promise(resolve =>
chan.asyncOpen( new ChannelListener((stuff, buffer) => {
resolve(JSON.parse(buffer));
})
)
);
// Since the actual ports seen will vary at runtime, we use placeholders // instead in our expected output definition. For example, if two entries // both have "port1", it means they both should have the same port in the // server's log. // For reqs that fail and trigger a Confirmation + retry, the retried reqs // might not re-use the new connection created for Confirmation due to a // race, so we have an extra alternate expected port for them. This lets // us test that they use *a* new port even if it's not *the* new port. // Subsequent lookups are not affected, they will use the same conn as // the Confirmation req.
let expectedLogTemplate = [
["example.com", "port1"],
["bar1.example.org", "port1"],
["bar1.example.org", "port1"],
["bar2.example.org", "port1"],
["bar2.example.org", "port1"],
["newconn.example.org", "port1"],
["newconn.example.org", "port1"],
["example.com", "port2"],
["newconn.example.org", "port2"],
["newconn.example.org", "port2"],
["bar3.example.org", "port2"],
["bar3.example.org", "port2"],
["bar4.example.org", "port2"],
["bar4.example.org", "port2"],
["newconn2.example.org", "port2"],
["newconn2.example.org", "port2"],
["example.com", "port3"],
["newconn2.example.org", "port3"],
["newconn2.example.org", "port3"],
["bar5.example.org", "port3"],
["bar5.example.org", "port3"],
["bar6.example.org", "port3"],
["bar6.example.org", "port3"],
];
if (expectedLogTemplate.length != dohReqPortLog.length) { // This shouldn't happen, and if it does, we'll fail the assertion // below. But first dump the whole server-side log to help with // debugging should we see a failure. Most likely cause would be // that another consumer of TRR happened to make a request while // the test was running and polluted the log.
info(dohReqPortLog);
}
equal(
expectedLogTemplate.length,
dohReqPortLog.length, "Correct number of req log entries"
);
let seenPorts = new Set(); // This is essentially a symbol table - as we iterate through the log // we will assign the actual seen port numbers to the placeholders.
let seenPortsByExpectedPort = new Map();
for (let i = 0; i < expectedLogTemplate.length; i++) {
let expectedName = expectedLogTemplate[i][0];
let expectedPort = expectedLogTemplate[i][1];
let seenName = dohReqPortLog[i][0];
let seenPort = dohReqPortLog[i][1];
info(`Checking log entry. Name: ${seenName}, Port: ${seenPort}`);
equal(expectedName, seenName, "Name matches for entry " + i); if (!seenPortsByExpectedPort.has(expectedPort)) {
ok(!seenPorts.has(seenPort), "Port should not have been previously used");
seenPorts.add(seenPort);
seenPortsByExpectedPort.set(expectedPort, seenPort);
} else {
equal(
seenPort,
seenPortsByExpectedPort.get(expectedPort), "Connection was reused as expected"
);
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.