Bug 1807268 - Re-enable verifyShowClipboardSuggestionsToggleTest UI test r=jajohnson
[gecko.git] / netwerk / test / unit / test_trr.js
blob1d5d9cd971bae1362a35cde318d4abe1d26b4c31
1 "use strict";
3 /* import-globals-from trr_common.js */
5 const gDefaultPref = Services.prefs.getDefaultBranch("");
7 SetParentalControlEnabled(false);
9 function setup() {
10   Services.prefs.setBoolPref("network.dns.get-ttl", false);
11   h2Port = trr_test_setup();
14 setup();
15 registerCleanupFunction(async () => {
16   trr_clear_prefs();
17   Services.prefs.clearUserPref("network.dns.get-ttl");
18 });
20 async function waitForConfirmation(expectedResponseIP, confirmationShouldFail) {
21   // Check that the confirmation eventually completes.
22   let count = 100;
23   while (count > 0) {
24     if (count == 50 || count == 10) {
25       // At these two points we do a longer timeout to account for a slow
26       // response on the server side. This is usually a problem on the Android
27       // because of the increased delay between the emulator and host.
28       await new Promise(resolve => do_timeout(100 * (100 / count), resolve));
29     }
30     let { inRecord } = await new TRRDNSListener(
31       `ip${count}.example.org`,
32       undefined,
33       false
34     );
35     inRecord.QueryInterface(Ci.nsIDNSAddrRecord);
36     let responseIP = inRecord.getNextAddrAsString();
37     Assert.ok(true, responseIP);
38     if (responseIP == expectedResponseIP) {
39       break;
40     }
41     count--;
42   }
44   if (confirmationShouldFail) {
45     Assert.equal(count, 0, "Confirmation did not finish after 100 iterations");
46     return;
47   }
49   Assert.greater(count, 0, "Finished confirmation before 100 iterations");
52 function setModeAndURI(mode, path) {
53   Services.prefs.setIntPref("network.trr.mode", mode);
54   Services.prefs.setCharPref(
55     "network.trr.uri",
56     `https://${TRR_Domain}:${h2Port}/${path}`
57   );
60 function makeChan(url, mode) {
61   let chan = NetUtil.newChannel({
62     uri: url,
63     loadUsingSystemPrincipal: true,
64   }).QueryInterface(Ci.nsIHttpChannel);
65   chan.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
66   chan.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
67   chan.setTRRMode(mode);
68   return chan;
71 add_task(async function test_server_up() {
72   // This test checks that moz-http2.js running in node is working.
73   // This should always be the first test in this file (except for setup)
74   // otherwise we may encounter random failures when the http2 server is down.
76   await NodeServer.execute("bad_id", `"hello"`)
77     .then(() => ok(false, "expecting to throw"))
78     .catch(e => equal(e.message, "Error: could not find id"));
79 });
81 add_task(async function test_trr_flags() {
82   Services.prefs.setBoolPref("network.trr.fallback-on-zero-response", true);
83   Services.prefs.setIntPref("network.trr.request_timeout_ms", 10000);
84   Services.prefs.setIntPref(
85     "network.trr.request_timeout_mode_trronly_ms",
86     10000
87   );
89   let httpserv = new HttpServer();
90   httpserv.registerPathHandler("/", function handler(metadata, response) {
91     let content = "ok";
92     response.setHeader("Content-Length", `${content.length}`);
93     response.bodyOutputStream.write(content, content.length);
94   });
95   httpserv.start(-1);
97   const URL = `http://example.com:${httpserv.identity.primaryPort}/`;
99   for (let mode of [0, 1, 2, 3, 4, 5]) {
100     setModeAndURI(mode, "doh?responseIP=127.0.0.1");
101     for (let flag of [
102       Ci.nsIRequest.TRR_DEFAULT_MODE,
103       Ci.nsIRequest.TRR_DISABLED_MODE,
104       Ci.nsIRequest.TRR_FIRST_MODE,
105       Ci.nsIRequest.TRR_ONLY_MODE,
106     ]) {
107       Services.dns.clearCache(true);
108       let chan = makeChan(URL, flag);
109       let expectTRR =
110         ([2, 3].includes(mode) && flag != Ci.nsIRequest.TRR_DISABLED_MODE) ||
111         (mode == 0 &&
112           [Ci.nsIRequest.TRR_FIRST_MODE, Ci.nsIRequest.TRR_ONLY_MODE].includes(
113             flag
114           ));
116       await new Promise(resolve =>
117         chan.asyncOpen(new ChannelListener(resolve))
118       );
120       equal(chan.getTRRMode(), flag);
121       equal(
122         expectTRR,
123         chan.QueryInterface(Ci.nsIHttpChannelInternal).isResolvedByTRR
124       );
125     }
126   }
128   await new Promise(resolve => httpserv.stop(resolve));
129   Services.prefs.clearUserPref("network.trr.fallback-on-zero-response");
130   Services.prefs.clearUserPref("network.trr.request_timeout_ms");
131   Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");
134 add_task(test_A_record);
136 add_task(async function test_push() {
137   info("Verify DOH push");
138   Services.dns.clearCache(true);
139   info("Asking server to push us a record");
140   setModeAndURI(3, "doh?responseIP=5.5.5.5&push=true");
142   await new TRRDNSListener("first.example.com", "5.5.5.5");
144   // At this point the second host name should've been pushed and we can resolve it using
145   // cache only. Set back the URI to a path that fails.
146   // Don't clear the cache, otherwise we lose the pushed record.
147   setModeAndURI(3, "404");
149   await new TRRDNSListener("push.example.org", "2018::2018");
152 add_task(test_AAAA_records);
154 add_task(test_RFC1918);
156 add_task(test_GET_ECS);
158 add_task(test_timeout_mode3);
160 add_task(test_trr_retry);
162 add_task(test_strict_native_fallback);
164 add_task(test_no_answers_fallback);
166 add_task(test_404_fallback);
168 add_task(test_mode_1_and_4);
170 add_task(test_CNAME);
172 add_task(test_name_mismatch);
174 add_task(test_mode_2);
176 add_task(test_excluded_domains);
178 add_task(test_captiveportal_canonicalURL);
180 add_task(test_parentalcontrols);
182 // TRR-first check that DNS result is used if domain is part of the builtin-excluded-domains pref
183 add_task(test_builtin_excluded_domains);
185 add_task(test_excluded_domains_mode3);
187 add_task(test25e);
189 add_task(test_parentalcontrols_mode3);
191 add_task(test_builtin_excluded_domains_mode3);
193 add_task(count_cookies);
195 add_task(test_connection_closed);
197 add_task(async function test_clearCacheOnURIChange() {
198   info("Check that the TRR cache should be cleared by a pref change.");
199   Services.dns.clearCache(true);
200   Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", true);
201   setModeAndURI(2, "doh?responseIP=7.7.7.7");
203   await new TRRDNSListener("bar.example.com", "7.7.7.7");
205   // The TRR cache should be cleared by this pref change.
206   Services.prefs.setCharPref(
207     "network.trr.uri",
208     `https://localhost:${h2Port}/doh?responseIP=8.8.8.8`
209   );
211   await new TRRDNSListener("bar.example.com", "8.8.8.8");
212   Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", false);
215 add_task(async function test_dnsSuffix() {
216   info("Checking that domains matching dns suffix list use Do53");
217   async function checkDnsSuffixInMode(mode) {
218     Services.dns.clearCache(true);
219     setModeAndURI(mode, "doh?responseIP=1.2.3.4&push=true");
220     await new TRRDNSListener("example.org", "1.2.3.4");
221     await new TRRDNSListener("push.example.org", "2018::2018");
222     await new TRRDNSListener("test.com", "1.2.3.4");
224     let networkLinkService = {
225       dnsSuffixList: ["example.org"],
226       QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]),
227     };
228     Services.obs.notifyObservers(
229       networkLinkService,
230       "network:dns-suffix-list-updated"
231     );
232     await new TRRDNSListener("test.com", "1.2.3.4");
233     if (Services.prefs.getBoolPref("network.trr.split_horizon_mitigations")) {
234       await new TRRDNSListener("example.org", "127.0.0.1");
235       // Also test that we don't use the pushed entry.
236       await new TRRDNSListener("push.example.org", "127.0.0.1");
237     } else {
238       await new TRRDNSListener("example.org", "1.2.3.4");
239       await new TRRDNSListener("push.example.org", "2018::2018");
240     }
242     // Attempt to clean up, just in case
243     networkLinkService.dnsSuffixList = [];
244     Services.obs.notifyObservers(
245       networkLinkService,
246       "network:dns-suffix-list-updated"
247     );
248   }
250   Services.prefs.setBoolPref("network.trr.split_horizon_mitigations", true);
251   await checkDnsSuffixInMode(2);
252   Services.prefs.setCharPref("network.trr.bootstrapAddr", "127.0.0.1");
253   await checkDnsSuffixInMode(3);
254   Services.prefs.setBoolPref("network.trr.split_horizon_mitigations", false);
255   // Test again with mitigations off
256   await checkDnsSuffixInMode(2);
257   await checkDnsSuffixInMode(3);
258   Services.prefs.clearUserPref("network.trr.split_horizon_mitigations");
259   Services.prefs.clearUserPref("network.trr.bootstrapAddr");
262 add_task(async function test_async_resolve_with_trr_server() {
263   info("Checking asyncResolveWithTrrServer");
264   Services.dns.clearCache(true);
265   Services.prefs.setIntPref("network.trr.mode", 0); // TRR-disabled
267   await new TRRDNSListener(
268     "bar_with_trr1.example.com",
269     "2.2.2.2",
270     true,
271     undefined,
272     `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2`
273   );
275   // Test request without trr server, it should return a native dns response.
276   await new TRRDNSListener("bar_with_trr1.example.com", "127.0.0.1");
278   // Mode 2
279   Services.dns.clearCache(true);
280   setModeAndURI(2, "doh?responseIP=2.2.2.2");
282   await new TRRDNSListener(
283     "bar_with_trr2.example.com",
284     "3.3.3.3",
285     true,
286     undefined,
287     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`
288   );
290   // Test request without trr server, it should return a response from trr server defined in the pref.
291   await new TRRDNSListener("bar_with_trr2.example.com", "2.2.2.2");
293   // Mode 3
294   Services.dns.clearCache(true);
295   setModeAndURI(3, "doh?responseIP=2.2.2.2");
297   await new TRRDNSListener(
298     "bar_with_trr3.example.com",
299     "3.3.3.3",
300     true,
301     undefined,
302     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`
303   );
305   // Test request without trr server, it should return a response from trr server defined in the pref.
306   await new TRRDNSListener("bar_with_trr3.example.com", "2.2.2.2");
308   // Mode 5
309   Services.dns.clearCache(true);
310   setModeAndURI(5, "doh?responseIP=2.2.2.2");
312   // When dns is resolved in socket process, we can't set |expectEarlyFail| to true.
313   let inSocketProcess = mozinfo.socketprocess_networking;
314   await new TRRDNSListener(
315     "bar_with_trr3.example.com",
316     undefined,
317     false,
318     undefined,
319     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`,
320     !inSocketProcess
321   );
323   // Call normal AsyncOpen, it will return result from the native resolver.
324   await new TRRDNSListener("bar_with_trr3.example.com", "127.0.0.1");
326   // Check that cache is ignored when server is different
327   Services.dns.clearCache(true);
328   setModeAndURI(3, "doh?responseIP=2.2.2.2");
330   await new TRRDNSListener("bar_with_trr4.example.com", "2.2.2.2", true);
332   // The record will be fetch again.
333   await new TRRDNSListener(
334     "bar_with_trr4.example.com",
335     "3.3.3.3",
336     true,
337     undefined,
338     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`
339   );
341   // The record will be fetch again.
342   await new TRRDNSListener(
343     "bar_with_trr5.example.com",
344     "4.4.4.4",
345     true,
346     undefined,
347     `https://foo.example.com:${h2Port}/doh?responseIP=4.4.4.4`
348   );
350   // Check no fallback and no blocklisting upon failure
351   Services.dns.clearCache(true);
352   setModeAndURI(2, "doh?responseIP=2.2.2.2");
354   let { inStatus } = await new TRRDNSListener(
355     "bar_with_trr6.example.com",
356     undefined,
357     false,
358     undefined,
359     `https://foo.example.com:${h2Port}/404`
360   );
361   Assert.ok(
362     !Components.isSuccessCode(inStatus),
363     `${inStatus} should be an error code`
364   );
366   await new TRRDNSListener("bar_with_trr6.example.com", "2.2.2.2", true);
368   // Check that DoH push doesn't work
369   Services.dns.clearCache(true);
370   setModeAndURI(2, "doh?responseIP=2.2.2.2");
372   await new TRRDNSListener(
373     "bar_with_trr7.example.com",
374     "3.3.3.3",
375     true,
376     undefined,
377     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3&push=true`
378   );
380   // AsyncResoleWithTrrServer rejects server pushes and the entry for push.example.org
381   // shouldn't be neither in the default cache not in AsyncResoleWithTrrServer cache.
382   setModeAndURI(2, "404");
384   await new TRRDNSListener(
385     "push.example.org",
386     "3.3.3.3",
387     true,
388     undefined,
389     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3&push=true`
390   );
392   await new TRRDNSListener("push.example.org", "127.0.0.1");
394   // Check confirmation is ignored
395   Services.dns.clearCache(true);
396   setModeAndURI(2, "doh?responseIP=1::ffff");
397   Services.prefs.clearUserPref("network.trr.useGET");
398   Services.prefs.clearUserPref("network.trr.disable-ECS");
399   Services.prefs.setCharPref(
400     "network.trr.confirmationNS",
401     "confirm.example.com"
402   );
404   // AsyncResoleWithTrrServer will succeed
405   await new TRRDNSListener(
406     "bar_with_trr8.example.com",
407     "3.3.3.3",
408     true,
409     undefined,
410     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`
411   );
413   Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
415   // Bad port
416   Services.dns.clearCache(true);
417   setModeAndURI(2, "doh?responseIP=2.2.2.2");
419   ({ inStatus } = await new TRRDNSListener(
420     "only_once.example.com",
421     undefined,
422     false,
423     undefined,
424     `https://target.example.com:666/404`
425   ));
426   Assert.ok(
427     !Components.isSuccessCode(inStatus),
428     `${inStatus} should be an error code`
429   );
431   // // MOZ_LOG=sync,timestamp,nsHostResolver:5 We should not keep resolving only_once.example.com
432   // // TODO: find a way of automating this
433   // await new Promise(resolve => {});
436 add_task(test_fetch_time);
438 add_task(async function test_content_encoding_gzip() {
439   info("Checking gzip content encoding");
440   Services.dns.clearCache(true);
441   Services.prefs.setBoolPref(
442     "network.trr.send_empty_accept-encoding_headers",
443     false
444   );
445   setModeAndURI(3, "doh?responseIP=2.2.2.2");
447   await new TRRDNSListener("bar.example.com", "2.2.2.2");
448   Services.prefs.clearUserPref(
449     "network.trr.send_empty_accept-encoding_headers"
450   );
453 add_task(async function test_redirect() {
454   info("Check handling of redirect");
456   // GET
457   Services.dns.clearCache(true);
458   setModeAndURI(3, "doh?redirect=4.4.4.4{&dns}");
459   Services.prefs.setBoolPref("network.trr.useGET", true);
460   Services.prefs.setBoolPref("network.trr.disable-ECS", true);
462   await new TRRDNSListener("ecs.example.com", "4.4.4.4");
464   // POST
465   Services.dns.clearCache(true);
466   Services.prefs.setBoolPref("network.trr.useGET", false);
467   setModeAndURI(3, "doh?redirect=4.4.4.4");
469   await new TRRDNSListener("bar.example.com", "4.4.4.4");
471   Services.prefs.clearUserPref("network.trr.useGET");
472   Services.prefs.clearUserPref("network.trr.disable-ECS");
475 // confirmationNS set without confirmed NS yet
476 // checks that we properly fall back to DNS is confirmation is not ready yet,
477 // and wait-for-confirmation pref is true
478 add_task(async function test_confirmation() {
479   info("Checking that we fall back correctly when confirmation is pending");
480   Services.dns.clearCache(true);
481   Services.prefs.setBoolPref("network.trr.wait-for-confirmation", true);
482   setModeAndURI(2, "doh?responseIP=7.7.7.7&slowConfirm=true");
483   Services.prefs.setCharPref(
484     "network.trr.confirmationNS",
485     "confirm.example.com"
486   );
488   await new TRRDNSListener("example.org", "127.0.0.1");
489   await new Promise(resolve => do_timeout(1000, resolve));
490   await waitForConfirmation("7.7.7.7");
492   // Reset between each test to force re-confirm
493   Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
495   info("Check that confirmation is skipped in mode 3");
496   // This is just a smoke test to make sure lookups succeed immediately
497   // in mode 3 without waiting for confirmation.
498   Services.dns.clearCache(true);
499   setModeAndURI(3, "doh?responseIP=1::ffff&slowConfirm=true");
500   Services.prefs.setCharPref(
501     "network.trr.confirmationNS",
502     "confirm.example.com"
503   );
505   await new TRRDNSListener("skipConfirmationForMode3.example.com", "1::ffff");
507   // Reset between each test to force re-confirm
508   Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
510   Services.dns.clearCache(true);
511   Services.prefs.setBoolPref("network.trr.wait-for-confirmation", false);
512   setModeAndURI(2, "doh?responseIP=7.7.7.7&slowConfirm=true");
513   Services.prefs.setCharPref(
514     "network.trr.confirmationNS",
515     "confirm.example.com"
516   );
518   // DoH available immediately
519   await new TRRDNSListener("example.org", "7.7.7.7");
521   // Reset between each test to force re-confirm
522   Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
524   // Fallback when confirmation fails
525   Services.dns.clearCache(true);
526   Services.prefs.setBoolPref("network.trr.wait-for-confirmation", true);
527   setModeAndURI(2, "404");
528   Services.prefs.setCharPref(
529     "network.trr.confirmationNS",
530     "confirm.example.com"
531   );
533   await waitForConfirmation("7.7.7.7", true);
535   await new TRRDNSListener("example.org", "127.0.0.1");
537   // Reset
538   Services.prefs.setCharPref("network.trr.confirmationNS", "skip");
539   Services.prefs.clearUserPref("network.trr.wait-for-confirmation");
542 add_task(test_fqdn);
544 add_task(async function test_detected_uri() {
545   info("Test setDetectedTrrURI");
546   Services.dns.clearCache(true);
547   Services.prefs.setIntPref("network.trr.mode", 3);
548   Services.prefs.clearUserPref("network.trr.uri");
549   let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri");
550   gDefaultPref.setCharPref(
551     "network.trr.default_provider_uri",
552     `https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6`
553   );
554   await new TRRDNSListener("domainA.example.org.", "3.4.5.6");
555   Services.dns.setDetectedTrrURI(
556     `https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4`
557   );
558   await new TRRDNSListener("domainB.example.org.", "1.2.3.4");
559   gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI);
561   // With a user-set doh uri this time.
562   Services.dns.clearCache(true);
563   setModeAndURI(2, "doh?responseIP=4.5.6.7");
564   await new TRRDNSListener("domainA.example.org.", "4.5.6.7");
566   // This should be a no-op, since we have a user-set URI
567   Services.dns.setDetectedTrrURI(
568     `https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4`
569   );
570   await new TRRDNSListener("domainB.example.org.", "4.5.6.7");
572   // Test network link status change
573   Services.dns.clearCache(true);
574   Services.prefs.setIntPref("network.trr.mode", 3);
575   Services.prefs.clearUserPref("network.trr.uri");
576   gDefaultPref.setCharPref(
577     "network.trr.default_provider_uri",
578     `https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6`
579   );
580   await new TRRDNSListener("domainA.example.org.", "3.4.5.6");
581   Services.dns.setDetectedTrrURI(
582     `https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4`
583   );
584   await new TRRDNSListener("domainB.example.org.", "1.2.3.4");
586   let networkLinkService = {
587     platformDNSIndications: 0,
588     QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]),
589   };
591   Services.obs.notifyObservers(
592     networkLinkService,
593     "network:link-status-changed",
594     "changed"
595   );
597   await new TRRDNSListener("domainC.example.org.", "3.4.5.6");
599   gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI);
602 add_task(async function test_pref_changes() {
603   info("Testing pref change handling");
604   Services.prefs.clearUserPref("network.trr.uri");
605   let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri");
607   async function doThenCheckURI(closure, expectedURI, expectChange = true) {
608     let uriChanged;
609     if (expectChange) {
610       uriChanged = topicObserved("network:trr-uri-changed");
611     }
612     closure();
613     if (expectChange) {
614       await uriChanged;
615     }
616     equal(Services.dns.currentTrrURI, expectedURI);
617   }
619   // setting the default value of the pref should be reflected in the URI
620   await doThenCheckURI(() => {
621     gDefaultPref.setCharPref(
622       "network.trr.default_provider_uri",
623       `https://foo.example.com:${h2Port}/doh?default`
624     );
625   }, `https://foo.example.com:${h2Port}/doh?default`);
627   // the user set value should be reflected in the URI
628   await doThenCheckURI(() => {
629     Services.prefs.setCharPref(
630       "network.trr.uri",
631       `https://foo.example.com:${h2Port}/doh?user`
632     );
633   }, `https://foo.example.com:${h2Port}/doh?user`);
635   // A user set pref is selected, so it should be chosen instead of the rollout
636   await doThenCheckURI(
637     () => {
638       Services.prefs.setCharPref(
639         "doh-rollout.uri",
640         `https://foo.example.com:${h2Port}/doh?rollout`
641       );
642     },
643     `https://foo.example.com:${h2Port}/doh?user`,
644     false
645   );
647   // There is no user set pref, so we go to the rollout pref
648   await doThenCheckURI(() => {
649     Services.prefs.clearUserPref("network.trr.uri");
650   }, `https://foo.example.com:${h2Port}/doh?rollout`);
652   // When the URI is set by the rollout addon, detection is allowed
653   await doThenCheckURI(() => {
654     Services.dns.setDetectedTrrURI(
655       `https://foo.example.com:${h2Port}/doh?detected`
656     );
657   }, `https://foo.example.com:${h2Port}/doh?detected`);
659   // Should switch back to the default provided by the rollout addon
660   await doThenCheckURI(() => {
661     let networkLinkService = {
662       platformDNSIndications: 0,
663       QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]),
664     };
665     Services.obs.notifyObservers(
666       networkLinkService,
667       "network:link-status-changed",
668       "changed"
669     );
670   }, `https://foo.example.com:${h2Port}/doh?rollout`);
672   // Again the user set pref should be chosen
673   await doThenCheckURI(() => {
674     Services.prefs.setCharPref(
675       "network.trr.uri",
676       `https://foo.example.com:${h2Port}/doh?user`
677     );
678   }, `https://foo.example.com:${h2Port}/doh?user`);
680   // Detection should not work with a user set pref
681   await doThenCheckURI(
682     () => {
683       Services.dns.setDetectedTrrURI(
684         `https://foo.example.com:${h2Port}/doh?detected`
685       );
686     },
687     `https://foo.example.com:${h2Port}/doh?user`,
688     false
689   );
691   // Should stay the same on network changes
692   await doThenCheckURI(
693     () => {
694       let networkLinkService = {
695         platformDNSIndications: 0,
696         QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]),
697       };
698       Services.obs.notifyObservers(
699         networkLinkService,
700         "network:link-status-changed",
701         "changed"
702       );
703     },
704     `https://foo.example.com:${h2Port}/doh?user`,
705     false
706   );
708   // Restore the pref
709   gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI);
712 add_task(async function test_dohrollout_mode() {
713   info("Testing doh-rollout.mode");
714   Services.prefs.clearUserPref("network.trr.mode");
715   Services.prefs.clearUserPref("doh-rollout.mode");
717   equal(Services.dns.currentTrrMode, 0);
719   async function doThenCheckMode(trrMode, rolloutMode, expectedMode, message) {
720     let modeChanged;
721     if (Services.dns.currentTrrMode != expectedMode) {
722       modeChanged = topicObserved("network:trr-mode-changed");
723     }
725     if (trrMode != undefined) {
726       Services.prefs.setIntPref("network.trr.mode", trrMode);
727     }
729     if (rolloutMode != undefined) {
730       Services.prefs.setIntPref("doh-rollout.mode", rolloutMode);
731     }
733     if (modeChanged) {
734       await modeChanged;
735     }
736     equal(Services.dns.currentTrrMode, expectedMode, message);
737   }
739   await doThenCheckMode(2, undefined, 2);
740   await doThenCheckMode(3, undefined, 3);
741   await doThenCheckMode(5, undefined, 5);
742   await doThenCheckMode(2, undefined, 2);
743   await doThenCheckMode(0, undefined, 0);
744   await doThenCheckMode(1, undefined, 5);
745   await doThenCheckMode(6, undefined, 5);
747   await doThenCheckMode(2, 0, 2);
748   await doThenCheckMode(2, 1, 2);
749   await doThenCheckMode(2, 2, 2);
750   await doThenCheckMode(2, 3, 2);
751   await doThenCheckMode(2, 5, 2);
752   await doThenCheckMode(3, 2, 3);
753   await doThenCheckMode(5, 2, 5);
755   Services.prefs.clearUserPref("network.trr.mode");
756   Services.prefs.clearUserPref("doh-rollout.mode");
758   await doThenCheckMode(undefined, 2, 2);
759   await doThenCheckMode(undefined, 3, 3);
761   // All modes that are not 0,2,3 are treated as 5
762   await doThenCheckMode(undefined, 5, 5);
763   await doThenCheckMode(undefined, 4, 5);
764   await doThenCheckMode(undefined, 6, 5);
766   await doThenCheckMode(undefined, 2, 2);
767   await doThenCheckMode(3, undefined, 3);
769   Services.prefs.clearUserPref("network.trr.mode");
770   equal(Services.dns.currentTrrMode, 2);
771   Services.prefs.clearUserPref("doh-rollout.mode");
772   equal(Services.dns.currentTrrMode, 0);
775 add_task(test_ipv6_trr_fallback);
777 add_task(test_ipv4_trr_fallback);
779 add_task(test_no_retry_without_doh);
781 // This test checks that normally when the TRR mode goes from ON -> OFF
782 // we purge the DNS cache (including TRR), so the entries aren't used on
783 // networks where they shouldn't. For example - turning on a VPN.
784 add_task(async function test_purge_trr_cache_on_mode_change() {
785   info("Checking that we purge cache when TRR is turned off");
786   Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", true);
788   Services.prefs.setIntPref("network.trr.mode", 0);
789   Services.prefs.setIntPref("doh-rollout.mode", 2);
790   Services.prefs.setCharPref(
791     "network.trr.uri",
792     `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`
793   );
795   await new TRRDNSListener("cached.example.com", "3.3.3.3");
796   Services.prefs.clearUserPref("doh-rollout.mode");
798   await new TRRDNSListener("cached.example.com", "127.0.0.1");
800   Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", false);
801   Services.prefs.clearUserPref("doh-rollout.mode");
804 add_task(async function test_old_bootstrap_pref() {
805   Services.dns.clearCache(true);
806   // Note this is a remote address. Setting this pref should have no effect,
807   // as this is the old name for the bootstrap pref.
808   // If this were to be used, the test would crash when accessing a non-local
809   // IP address.
810   Services.prefs.setCharPref("network.trr.bootstrapAddress", "1.1.1.1");
811   setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh?responseIP=4.4.4.4`);
812   await new TRRDNSListener("testytest.com", "4.4.4.4");
815 add_task(async function test_padding() {
816   setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh`);
817   async function CheckPadding(
818     pad_length,
819     request,
820     none,
821     ecs,
822     padding,
823     ecsPadding
824   ) {
825     Services.prefs.setIntPref("network.trr.padding.length", pad_length);
826     Services.dns.clearCache(true);
827     Services.prefs.setBoolPref("network.trr.padding", false);
828     Services.prefs.setBoolPref("network.trr.disable-ECS", false);
829     await new TRRDNSListener(request, none);
831     Services.dns.clearCache(true);
832     Services.prefs.setBoolPref("network.trr.padding", false);
833     Services.prefs.setBoolPref("network.trr.disable-ECS", true);
834     await new TRRDNSListener(request, ecs);
836     Services.dns.clearCache(true);
837     Services.prefs.setBoolPref("network.trr.padding", true);
838     Services.prefs.setBoolPref("network.trr.disable-ECS", false);
839     await new TRRDNSListener(request, padding);
841     Services.dns.clearCache(true);
842     Services.prefs.setBoolPref("network.trr.padding", true);
843     Services.prefs.setBoolPref("network.trr.disable-ECS", true);
844     await new TRRDNSListener(request, ecsPadding);
845   }
847   // short domain name
848   await CheckPadding(
849     16,
850     "a.pd",
851     "2.2.0.22",
852     "2.2.0.41",
853     "1.1.0.48",
854     "1.1.0.48"
855   );
856   await CheckPadding(256, "a.pd", "2.2.0.22", "2.2.0.41", "1.1.1.0", "1.1.1.0");
858   // medium domain name
859   await CheckPadding(
860     16,
861     "has-padding.pd",
862     "2.2.0.32",
863     "2.2.0.51",
864     "1.1.0.48",
865     "1.1.0.64"
866   );
867   await CheckPadding(
868     128,
869     "has-padding.pd",
870     "2.2.0.32",
871     "2.2.0.51",
872     "1.1.0.128",
873     "1.1.0.128"
874   );
875   await CheckPadding(
876     80,
877     "has-padding.pd",
878     "2.2.0.32",
879     "2.2.0.51",
880     "1.1.0.80",
881     "1.1.0.80"
882   );
884   // long domain name
885   await CheckPadding(
886     16,
887     "abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.pd",
888     "2.2.0.131",
889     "2.2.0.150",
890     "1.1.0.160",
891     "1.1.0.160"
892   );
893   await CheckPadding(
894     128,
895     "abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.pd",
896     "2.2.0.131",
897     "2.2.0.150",
898     "1.1.1.0",
899     "1.1.1.0"
900   );
901   await CheckPadding(
902     80,
903     "abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.pd",
904     "2.2.0.131",
905     "2.2.0.150",
906     "1.1.0.160",
907     "1.1.0.160"
908   );
911 add_task(test_connection_reuse_and_cycling);
913 // Can't test for socket process since telemetry is captured in different process.
914 add_task(
915   { skip_if: () => mozinfo.socketprocess_networking },
916   async function test_trr_pb_telemetry() {
917     setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh`);
918     Services.dns.clearCache(true);
919     Services.fog.initializeFOG();
920     Services.fog.testResetFOG();
921     await new TRRDNSListener("testytest.com", { expectedAnswer: "5.5.5.5" });
923     Assert.equal(
924       await Glean.networking.trrRequestCount.regular.testGetValue(),
925       2
926     ); // One for IPv4 and one for IPv6.
927     Assert.equal(
928       await Glean.networking.trrRequestCount.private.testGetValue(),
929       null
930     );
932     await new TRRDNSListener("testytest.com", {
933       expectedAnswer: "5.5.5.5",
934       originAttributes: { privateBrowsingId: 1 },
935     });
937     Assert.equal(
938       await Glean.networking.trrRequestCount.regular.testGetValue(),
939       2
940     );
941     Assert.equal(
942       await Glean.networking.trrRequestCount.private.testGetValue(),
943       2
944     );
945   }