test_trr.js (31966B)
1 "use strict"; 2 3 /* import-globals-from trr_common.js */ 4 /* import-globals-from head_trr.js */ 5 6 const gDefaultPref = Services.prefs.getDefaultBranch(""); 7 8 const { NodeServer } = ChromeUtils.importESModule( 9 "resource://testing-common/NodeServer.sys.mjs" 10 ); 11 12 SetParentalControlEnabled(false); 13 14 let trrServer; 15 add_setup(async function setup() { 16 Services.prefs.setBoolPref("network.dns.get-ttl", false); 17 trr_test_setup(); 18 trrServer = new TRRServer(); 19 await trrServer.start(); 20 h2Port = trrServer.port(); 21 22 registerCleanupFunction(async () => { 23 trr_clear_prefs(); 24 Services.prefs.clearUserPref("network.dns.get-ttl"); 25 Services.prefs.clearUserPref("network.dns.disableIPv6"); 26 if (trrServer) { 27 await trrServer.stop(); 28 } 29 }); 30 }); 31 32 async function waitForConfirmation(expectedResponseIP, confirmationShouldFail) { 33 // Check that the confirmation eventually completes. 34 let count = 100; 35 while (count > 0) { 36 if (count == 50 || count == 10) { 37 // At these two points we do a longer timeout to account for a slow 38 // response on the server side. This is usually a problem on the Android 39 // because of the increased delay between the emulator and host. 40 await new Promise(resolve => do_timeout(100 * (100 / count), resolve)); 41 } 42 let { inRecord } = await new TRRDNSListener( 43 `ip${count}.example.org`, 44 undefined, 45 false 46 ); 47 inRecord.QueryInterface(Ci.nsIDNSAddrRecord); 48 let responseIP = inRecord.getNextAddrAsString(); 49 Assert.ok(true, responseIP); 50 if (responseIP == expectedResponseIP) { 51 break; 52 } 53 count--; 54 } 55 56 if (confirmationShouldFail) { 57 Assert.equal(count, 0, "Confirmation did not finish after 100 iterations"); 58 return; 59 } 60 61 Assert.greater(count, 0, "Finished confirmation before 100 iterations"); 62 } 63 64 function setModeAndURI(mode, path) { 65 Services.prefs.setIntPref("network.trr.mode", mode); 66 Services.prefs.setCharPref( 67 "network.trr.uri", 68 `https://${TRR_Domain}:${h2Port}/${path}` 69 ); 70 } 71 72 function makeChan(url, mode) { 73 let chan = NetUtil.newChannel({ 74 uri: url, 75 loadUsingSystemPrincipal: true, 76 }).QueryInterface(Ci.nsIHttpChannel); 77 chan.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; 78 chan.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; 79 chan.setTRRMode(mode); 80 return chan; 81 } 82 83 add_task(async function test_server_up() { 84 // This test checks that moz-http2.js running in node is working. 85 // This should always be the first test in this file (except for setup) 86 // otherwise we may encounter random failures when the http2 server is down. 87 88 await NodeServer.execute("bad_id", `"hello"`) 89 .then(() => ok(false, "expecting to throw")) 90 .catch(e => equal(e.message, "Error: could not find id")); 91 }); 92 93 add_task(async function test_trr_flags() { 94 Services.prefs.setBoolPref("network.trr.fallback-on-zero-response", true); 95 Services.prefs.setIntPref("network.trr.request_timeout_ms", 10000); 96 Services.prefs.setIntPref( 97 "network.trr.request_timeout_mode_trronly_ms", 98 10000 99 ); 100 101 let httpserv = new HttpServer(); 102 httpserv.registerPathHandler("/", function handler(metadata, response) { 103 let content = "ok"; 104 response.setHeader("Content-Length", `${content.length}`); 105 response.bodyOutputStream.write(content, content.length); 106 }); 107 httpserv.start(-1); 108 109 const URL = `http://example.com:${httpserv.identity.primaryPort}/`; 110 111 for (let mode of [0, 1, 2, 3, 4, 5]) { 112 setModeAndURI(mode, "doh?responseIP=127.0.0.1"); 113 for (let flag of [ 114 Ci.nsIRequest.TRR_DEFAULT_MODE, 115 Ci.nsIRequest.TRR_DISABLED_MODE, 116 Ci.nsIRequest.TRR_FIRST_MODE, 117 Ci.nsIRequest.TRR_ONLY_MODE, 118 ]) { 119 Services.dns.clearCache(true); 120 let chan = makeChan(URL, flag); 121 let expectTRR = 122 ([2, 3].includes(mode) && flag != Ci.nsIRequest.TRR_DISABLED_MODE) || 123 (mode == 0 && 124 [Ci.nsIRequest.TRR_FIRST_MODE, Ci.nsIRequest.TRR_ONLY_MODE].includes( 125 flag 126 )); 127 128 await new Promise(resolve => 129 chan.asyncOpen(new ChannelListener(resolve)) 130 ); 131 132 equal(chan.getTRRMode(), flag); 133 equal( 134 expectTRR, 135 chan.QueryInterface(Ci.nsIHttpChannelInternal).isResolvedByTRR 136 ); 137 } 138 } 139 140 await new Promise(resolve => httpserv.stop(resolve)); 141 Services.prefs.clearUserPref("network.trr.fallback-on-zero-response"); 142 Services.prefs.clearUserPref("network.trr.request_timeout_ms"); 143 Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms"); 144 }); 145 146 add_task(test_A_record); 147 148 add_task(test_AAAA_records); 149 150 add_task(test_RFC1918); 151 152 add_task(test_GET_ECS); 153 154 add_task(test_timeout_mode3); 155 156 add_task(test_trr_retry); 157 158 add_task(test_strict_native_fallback); 159 160 add_task(test_no_answers_fallback); 161 162 add_task(test_404_fallback); 163 164 add_task(test_mode_1_and_4); 165 166 add_task(test_CNAME); 167 168 add_task(test_name_mismatch); 169 170 add_task(test_mode_2); 171 172 add_task(test_excluded_domains); 173 174 add_task(test_captiveportal_canonicalURL); 175 176 add_task(test_parentalcontrols); 177 178 // TRR-first check that DNS result is used if domain is part of the builtin-excluded-domains pref 179 add_task(test_builtin_excluded_domains); 180 181 add_task(test_excluded_domains_mode3); 182 183 add_task(test25e); 184 185 add_task(test_parentalcontrols_mode3); 186 187 add_task(test_builtin_excluded_domains_mode3); 188 189 add_task(count_cookies); 190 191 add_task(test_connection_closed); 192 193 add_task(async function test_clearCacheOnURIChange() { 194 info("Check that the TRR cache should be cleared by a pref change."); 195 Services.dns.clearCache(true); 196 Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", true); 197 setModeAndURI(2, "doh?responseIP=7.7.7.7"); 198 199 await new TRRDNSListener("bar.example.com", "7.7.7.7"); 200 201 // The TRR cache should be cleared by this pref change. 202 Services.prefs.setCharPref( 203 "network.trr.uri", 204 `https://localhost:${h2Port}/doh?responseIP=8.8.8.8` 205 ); 206 207 await new TRRDNSListener("bar.example.com", "8.8.8.8"); 208 Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", false); 209 }); 210 211 add_task(async function test_dnsSuffix() { 212 info("Checking that domains matching dns suffix list use Do53"); 213 async function checkDnsSuffixInMode(mode) { 214 Services.dns.clearCache(true); 215 setModeAndURI(mode, "doh?responseIP=1.2.3.4"); 216 await new TRRDNSListener("example.org", "1.2.3.4"); 217 await new TRRDNSListener("test.com", "1.2.3.4"); 218 219 let networkLinkService = { 220 dnsSuffixList: ["example.org"], 221 QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]), 222 }; 223 Services.obs.notifyObservers( 224 networkLinkService, 225 "network:dns-suffix-list-updated" 226 ); 227 await new TRRDNSListener("test.com", "1.2.3.4"); 228 if (Services.prefs.getBoolPref("network.trr.split_horizon_mitigations")) { 229 await new TRRDNSListener("example.org", "127.0.0.1"); 230 } else { 231 await new TRRDNSListener("example.org", "1.2.3.4"); 232 } 233 234 // Attempt to clean up, just in case 235 networkLinkService.dnsSuffixList = []; 236 Services.obs.notifyObservers( 237 networkLinkService, 238 "network:dns-suffix-list-updated" 239 ); 240 } 241 242 Services.prefs.setBoolPref("network.trr.split_horizon_mitigations", true); 243 await checkDnsSuffixInMode(2); 244 Services.prefs.setCharPref("network.trr.bootstrapAddr", "127.0.0.1"); 245 await checkDnsSuffixInMode(3); 246 Services.prefs.setBoolPref("network.trr.split_horizon_mitigations", false); 247 // Test again with mitigations off 248 await checkDnsSuffixInMode(2); 249 await checkDnsSuffixInMode(3); 250 Services.prefs.clearUserPref("network.trr.split_horizon_mitigations"); 251 Services.prefs.clearUserPref("network.trr.bootstrapAddr"); 252 }); 253 254 add_task(async function test_async_resolve_with_trr_server() { 255 info("Checking asyncResolveWithTrrServer"); 256 Services.dns.clearCache(true); 257 Services.prefs.setIntPref("network.trr.mode", 0); // TRR-disabled 258 259 await new TRRDNSListener( 260 "bar_with_trr1.example.com", 261 "2.2.2.2", 262 true, 263 undefined, 264 `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2` 265 ); 266 267 // Test request without trr server, it should return a native dns response. 268 await new TRRDNSListener("bar_with_trr1.example.com", "127.0.0.1"); 269 270 // Mode 2 271 Services.dns.clearCache(true); 272 setModeAndURI(2, "doh?responseIP=2.2.2.2"); 273 274 await new TRRDNSListener( 275 "bar_with_trr2.example.com", 276 "3.3.3.3", 277 true, 278 undefined, 279 `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3` 280 ); 281 282 // Test request without trr server, it should return a response from trr server defined in the pref. 283 await new TRRDNSListener("bar_with_trr2.example.com", "2.2.2.2"); 284 285 // Mode 3 286 Services.dns.clearCache(true); 287 setModeAndURI(3, "doh?responseIP=2.2.2.2"); 288 289 await new TRRDNSListener( 290 "bar_with_trr3.example.com", 291 "3.3.3.3", 292 true, 293 undefined, 294 `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3` 295 ); 296 297 // Test request without trr server, it should return a response from trr server defined in the pref. 298 await new TRRDNSListener("bar_with_trr3.example.com", "2.2.2.2"); 299 300 // Mode 5 301 Services.dns.clearCache(true); 302 setModeAndURI(5, "doh?responseIP=2.2.2.2"); 303 304 // When dns is resolved in socket process, we can't set |expectEarlyFail| to true. 305 let inSocketProcess = mozinfo.socketprocess_networking; 306 await new TRRDNSListener( 307 "bar_with_trr3.example.com", 308 undefined, 309 false, 310 undefined, 311 `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3`, 312 !inSocketProcess 313 ); 314 315 // Call normal AsyncOpen, it will return result from the native resolver. 316 await new TRRDNSListener("bar_with_trr3.example.com", "127.0.0.1"); 317 318 // Check that cache is ignored when server is different 319 Services.dns.clearCache(true); 320 setModeAndURI(3, "doh?responseIP=2.2.2.2"); 321 322 await new TRRDNSListener("bar_with_trr4.example.com", "2.2.2.2", true); 323 324 // The record will be fetch again. 325 await new TRRDNSListener( 326 "bar_with_trr4.example.com", 327 "3.3.3.3", 328 true, 329 undefined, 330 `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3` 331 ); 332 333 // The record will be fetch again. 334 await new TRRDNSListener( 335 "bar_with_trr5.example.com", 336 "4.4.4.4", 337 true, 338 undefined, 339 `https://foo.example.com:${h2Port}/doh?responseIP=4.4.4.4` 340 ); 341 342 // Check no fallback and no blocklisting upon failure 343 Services.dns.clearCache(true); 344 setModeAndURI(2, "doh?responseIP=2.2.2.2"); 345 346 let { inStatus } = await new TRRDNSListener( 347 "bar_with_trr6.example.com", 348 undefined, 349 false, 350 undefined, 351 `https://foo.example.com:${h2Port}/404` 352 ); 353 Assert.ok( 354 !Components.isSuccessCode(inStatus), 355 `${inStatus} should be an error code` 356 ); 357 358 await new TRRDNSListener("bar_with_trr6.example.com", "2.2.2.2", true); 359 360 // Check that DoH push doesn't work 361 Services.dns.clearCache(true); 362 setModeAndURI(2, "doh?responseIP=2.2.2.2"); 363 364 await new TRRDNSListener( 365 "bar_with_trr7.example.com", 366 "3.3.3.3", 367 true, 368 undefined, 369 `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3` 370 ); 371 372 // Check confirmation is ignored 373 Services.dns.clearCache(true); 374 setModeAndURI(2, "doh?responseIP=1::ffff"); 375 Services.prefs.clearUserPref("network.trr.useGET"); 376 Services.prefs.clearUserPref("network.trr.disable-ECS"); 377 Services.prefs.setCharPref( 378 "network.trr.confirmationNS", 379 "confirm.example.com" 380 ); 381 382 // AsyncResoleWithTrrServer will succeed 383 await new TRRDNSListener( 384 "bar_with_trr8.example.com", 385 "3.3.3.3", 386 true, 387 undefined, 388 `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3` 389 ); 390 391 Services.prefs.setCharPref("network.trr.confirmationNS", "skip"); 392 393 // Bad port 394 Services.dns.clearCache(true); 395 setModeAndURI(2, "doh?responseIP=2.2.2.2"); 396 397 ({ inStatus } = await new TRRDNSListener( 398 "only_once.example.com", 399 undefined, 400 false, 401 undefined, 402 `https://target.example.com:666/404` 403 )); 404 Assert.ok( 405 !Components.isSuccessCode(inStatus), 406 `${inStatus} should be an error code` 407 ); 408 409 // // MOZ_LOG=sync,timestamp,nsHostResolver:5 We should not keep resolving only_once.example.com 410 // // TODO: find a way of automating this 411 // await new Promise(resolve => {}); 412 }); 413 414 add_task(test_fetch_time); 415 416 add_task(async function test_content_encoding_gzip() { 417 info("Checking gzip content encoding"); 418 Services.dns.clearCache(true); 419 Services.prefs.setBoolPref( 420 "network.trr.send_empty_accept-encoding_headers", 421 false 422 ); 423 setModeAndURI(3, "doh?responseIP=2.2.2.2"); 424 425 await new TRRDNSListener("bar.example.com", "2.2.2.2"); 426 Services.prefs.clearUserPref( 427 "network.trr.send_empty_accept-encoding_headers" 428 ); 429 }); 430 431 add_task(async function test_redirect() { 432 info("Check handling of redirect"); 433 434 // GET 435 Services.dns.clearCache(true); 436 setModeAndURI(3, "doh?redirect=4.4.4.4{&dns}"); 437 Services.prefs.setBoolPref("network.trr.useGET", true); 438 Services.prefs.setBoolPref("network.trr.disable-ECS", true); 439 440 await new TRRDNSListener("ecs.example.com", "4.4.4.4"); 441 442 // POST 443 Services.dns.clearCache(true); 444 Services.prefs.setBoolPref("network.trr.useGET", false); 445 setModeAndURI(3, "doh?redirect=4.4.4.4"); 446 447 await new TRRDNSListener("bar.example.com", "4.4.4.4"); 448 449 Services.prefs.clearUserPref("network.trr.useGET"); 450 Services.prefs.clearUserPref("network.trr.disable-ECS"); 451 }); 452 453 // confirmationNS set without confirmed NS yet 454 // checks that we properly fall back to DNS is confirmation is not ready yet, 455 // and wait-for-confirmation pref is true 456 add_task(async function test_confirmation() { 457 info("Checking that we fall back correctly when confirmation is pending"); 458 Services.dns.clearCache(true); 459 Services.prefs.setBoolPref("network.trr.wait-for-confirmation", true); 460 setModeAndURI(2, "doh?responseIP=7.7.7.7&slowConfirm=true"); 461 Services.prefs.setCharPref( 462 "network.trr.confirmationNS", 463 "confirm.example.com" 464 ); 465 466 await new TRRDNSListener("example.org", "127.0.0.1"); 467 await new Promise(resolve => do_timeout(1000, resolve)); 468 await waitForConfirmation("7.7.7.7"); 469 470 // Reset between each test to force re-confirm 471 Services.prefs.setCharPref("network.trr.confirmationNS", "skip"); 472 473 info("Check that confirmation is skipped in mode 3"); 474 // This is just a smoke test to make sure lookups succeed immediately 475 // in mode 3 without waiting for confirmation. 476 Services.dns.clearCache(true); 477 setModeAndURI(3, "doh?responseIP=1::ffff&slowConfirm=true"); 478 Services.prefs.setCharPref( 479 "network.trr.confirmationNS", 480 "confirm.example.com" 481 ); 482 483 await new TRRDNSListener("skipConfirmationForMode3.example.com", "1::ffff"); 484 485 // Reset between each test to force re-confirm 486 Services.prefs.setCharPref("network.trr.confirmationNS", "skip"); 487 488 Services.dns.clearCache(true); 489 Services.prefs.setBoolPref("network.trr.wait-for-confirmation", false); 490 setModeAndURI(2, "doh?responseIP=7.7.7.7&slowConfirm=true"); 491 Services.prefs.setCharPref( 492 "network.trr.confirmationNS", 493 "confirm.example.com" 494 ); 495 496 // DoH available immediately 497 await new TRRDNSListener("example.org", "7.7.7.7"); 498 499 // Reset between each test to force re-confirm 500 Services.prefs.setCharPref("network.trr.confirmationNS", "skip"); 501 502 // Fallback when confirmation fails 503 Services.dns.clearCache(true); 504 Services.prefs.setBoolPref("network.trr.wait-for-confirmation", true); 505 setModeAndURI(2, "404"); 506 Services.prefs.setCharPref( 507 "network.trr.confirmationNS", 508 "confirm.example.com" 509 ); 510 511 await waitForConfirmation("7.7.7.7", true); 512 513 await new TRRDNSListener("example.org", "127.0.0.1"); 514 515 // Reset 516 Services.prefs.setCharPref("network.trr.confirmationNS", "skip"); 517 Services.prefs.clearUserPref("network.trr.wait-for-confirmation"); 518 }); 519 520 add_task(test_fqdn); 521 522 add_task(async function test_detected_uri() { 523 info("Test setDetectedTrrURI"); 524 Services.dns.clearCache(true); 525 Services.prefs.setIntPref("network.trr.mode", 3); 526 Services.prefs.clearUserPref("network.trr.uri"); 527 let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri"); 528 gDefaultPref.setCharPref( 529 "network.trr.default_provider_uri", 530 `https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6` 531 ); 532 await new TRRDNSListener("domainA.example.org.", "3.4.5.6"); 533 Services.dns.setDetectedTrrURI( 534 `https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4` 535 ); 536 await new TRRDNSListener("domainB.example.org.", "1.2.3.4"); 537 gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI); 538 539 // With a user-set doh uri this time. 540 Services.dns.clearCache(true); 541 setModeAndURI(2, "doh?responseIP=4.5.6.7"); 542 await new TRRDNSListener("domainA.example.org.", "4.5.6.7"); 543 544 // This should be a no-op, since we have a user-set URI 545 Services.dns.setDetectedTrrURI( 546 `https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4` 547 ); 548 await new TRRDNSListener("domainB.example.org.", "4.5.6.7"); 549 550 // Test network link status change 551 Services.dns.clearCache(true); 552 Services.prefs.setIntPref("network.trr.mode", 3); 553 Services.prefs.clearUserPref("network.trr.uri"); 554 gDefaultPref.setCharPref( 555 "network.trr.default_provider_uri", 556 `https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6` 557 ); 558 await new TRRDNSListener("domainA.example.org.", "3.4.5.6"); 559 Services.dns.setDetectedTrrURI( 560 `https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4` 561 ); 562 await new TRRDNSListener("domainB.example.org.", "1.2.3.4"); 563 564 let networkLinkService = { 565 platformDNSIndications: 0, 566 QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]), 567 }; 568 569 Services.obs.notifyObservers( 570 networkLinkService, 571 "network:link-status-changed", 572 "changed" 573 ); 574 575 await new TRRDNSListener("domainC.example.org.", "3.4.5.6"); 576 577 gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI); 578 }); 579 580 add_task(async function test_pref_changes() { 581 info("Testing pref change handling"); 582 Services.prefs.clearUserPref("network.trr.uri"); 583 let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri"); 584 585 async function doThenCheckURI(closure, expectedURI, expectChange = true) { 586 let uriChanged; 587 if (expectChange) { 588 uriChanged = topicObserved("network:trr-uri-changed"); 589 } 590 closure(); 591 if (expectChange) { 592 await uriChanged; 593 } 594 equal(Services.dns.currentTrrURI, expectedURI); 595 } 596 597 // setting the default value of the pref should be reflected in the URI 598 await doThenCheckURI(() => { 599 gDefaultPref.setCharPref( 600 "network.trr.default_provider_uri", 601 `https://foo.example.com:${h2Port}/doh?default` 602 ); 603 }, `https://foo.example.com:${h2Port}/doh?default`); 604 605 // the user set value should be reflected in the URI 606 await doThenCheckURI(() => { 607 Services.prefs.setCharPref( 608 "network.trr.uri", 609 `https://foo.example.com:${h2Port}/doh?user` 610 ); 611 }, `https://foo.example.com:${h2Port}/doh?user`); 612 613 // A user set pref is selected, so it should be chosen instead of the rollout 614 await doThenCheckURI( 615 () => { 616 Services.prefs.setCharPref( 617 "doh-rollout.uri", 618 `https://foo.example.com:${h2Port}/doh?rollout` 619 ); 620 }, 621 `https://foo.example.com:${h2Port}/doh?user`, 622 false 623 ); 624 625 // There is no user set pref, so we go to the rollout pref 626 await doThenCheckURI(() => { 627 Services.prefs.clearUserPref("network.trr.uri"); 628 }, `https://foo.example.com:${h2Port}/doh?rollout`); 629 630 // When the URI is set by the rollout addon, detection is allowed 631 await doThenCheckURI(() => { 632 Services.dns.setDetectedTrrURI( 633 `https://foo.example.com:${h2Port}/doh?detected` 634 ); 635 }, `https://foo.example.com:${h2Port}/doh?detected`); 636 637 // Should switch back to the default provided by the rollout addon 638 await doThenCheckURI(() => { 639 let networkLinkService = { 640 platformDNSIndications: 0, 641 QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]), 642 }; 643 Services.obs.notifyObservers( 644 networkLinkService, 645 "network:link-status-changed", 646 "changed" 647 ); 648 }, `https://foo.example.com:${h2Port}/doh?rollout`); 649 650 // Again the user set pref should be chosen 651 await doThenCheckURI(() => { 652 Services.prefs.setCharPref( 653 "network.trr.uri", 654 `https://foo.example.com:${h2Port}/doh?user` 655 ); 656 }, `https://foo.example.com:${h2Port}/doh?user`); 657 658 // Detection should not work with a user set pref 659 await doThenCheckURI( 660 () => { 661 Services.dns.setDetectedTrrURI( 662 `https://foo.example.com:${h2Port}/doh?detected` 663 ); 664 }, 665 `https://foo.example.com:${h2Port}/doh?user`, 666 false 667 ); 668 669 // Should stay the same on network changes 670 await doThenCheckURI( 671 () => { 672 let networkLinkService = { 673 platformDNSIndications: 0, 674 QueryInterface: ChromeUtils.generateQI(["nsINetworkLinkService"]), 675 }; 676 Services.obs.notifyObservers( 677 networkLinkService, 678 "network:link-status-changed", 679 "changed" 680 ); 681 }, 682 `https://foo.example.com:${h2Port}/doh?user`, 683 false 684 ); 685 686 // Restore the pref 687 gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI); 688 }); 689 690 add_task(async function test_dohrollout_mode() { 691 info("Testing doh-rollout.mode"); 692 Services.prefs.clearUserPref("network.trr.mode"); 693 Services.prefs.clearUserPref("doh-rollout.mode"); 694 695 equal(Services.dns.currentTrrMode, 0); 696 697 async function doThenCheckMode(trrMode, rolloutMode, expectedMode, message) { 698 let modeChanged; 699 if (Services.dns.currentTrrMode != expectedMode) { 700 modeChanged = topicObserved("network:trr-mode-changed"); 701 } 702 703 if (trrMode != undefined) { 704 Services.prefs.setIntPref("network.trr.mode", trrMode); 705 } 706 707 if (rolloutMode != undefined) { 708 Services.prefs.setIntPref("doh-rollout.mode", rolloutMode); 709 } 710 711 if (modeChanged) { 712 await modeChanged; 713 } 714 equal(Services.dns.currentTrrMode, expectedMode, message); 715 } 716 717 await doThenCheckMode(2, undefined, 2); 718 await doThenCheckMode(3, undefined, 3); 719 await doThenCheckMode(5, undefined, 5); 720 await doThenCheckMode(2, undefined, 2); 721 await doThenCheckMode(0, undefined, 0); 722 await doThenCheckMode(1, undefined, 5); 723 await doThenCheckMode(6, undefined, 5); 724 725 await doThenCheckMode(2, 0, 2); 726 await doThenCheckMode(2, 1, 2); 727 await doThenCheckMode(2, 2, 2); 728 await doThenCheckMode(2, 3, 2); 729 await doThenCheckMode(2, 5, 2); 730 await doThenCheckMode(3, 2, 3); 731 await doThenCheckMode(5, 2, 5); 732 733 Services.prefs.clearUserPref("network.trr.mode"); 734 Services.prefs.clearUserPref("doh-rollout.mode"); 735 736 await doThenCheckMode(undefined, 2, 2); 737 await doThenCheckMode(undefined, 3, 3); 738 739 // All modes that are not 0,2,3 are treated as 5 740 await doThenCheckMode(undefined, 5, 5); 741 await doThenCheckMode(undefined, 4, 5); 742 await doThenCheckMode(undefined, 6, 5); 743 744 await doThenCheckMode(undefined, 2, 2); 745 await doThenCheckMode(3, undefined, 3); 746 747 Services.prefs.clearUserPref("network.trr.mode"); 748 equal(Services.dns.currentTrrMode, 2); 749 Services.prefs.clearUserPref("doh-rollout.mode"); 750 equal(Services.dns.currentTrrMode, 0); 751 }); 752 753 add_task(test_ipv6_trr_fallback); 754 755 add_task(test_ipv4_trr_fallback); 756 757 add_task(test_no_retry_without_doh); 758 759 // This test checks that normally when the TRR mode goes from ON -> OFF 760 // we purge the DNS cache (including TRR), so the entries aren't used on 761 // networks where they shouldn't. For example - turning on a VPN. 762 add_task(async function test_purge_trr_cache_on_mode_change() { 763 info("Checking that we purge cache when TRR is turned off"); 764 Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", true); 765 766 Services.prefs.setIntPref("network.trr.mode", 0); 767 Services.prefs.setIntPref("doh-rollout.mode", 2); 768 Services.prefs.setCharPref( 769 "network.trr.uri", 770 `https://foo.example.com:${h2Port}/doh?responseIP=3.3.3.3` 771 ); 772 773 await new TRRDNSListener("cached.example.com", "3.3.3.3"); 774 Services.prefs.clearUserPref("doh-rollout.mode"); 775 776 await new TRRDNSListener("cached.example.com", "127.0.0.1"); 777 778 Services.prefs.setBoolPref("network.trr.clear-cache-on-pref-change", false); 779 Services.prefs.clearUserPref("doh-rollout.mode"); 780 }); 781 782 add_task(async function test_old_bootstrap_pref() { 783 Services.dns.clearCache(true); 784 // Note this is a remote address. Setting this pref should have no effect, 785 // as this is the old name for the bootstrap pref. 786 // If this were to be used, the test would crash when accessing a non-local 787 // IP address. 788 Services.prefs.setCharPref("network.trr.bootstrapAddress", "1.1.1.1"); 789 setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh?responseIP=4.4.4.4`); 790 await new TRRDNSListener("testytest.com", "4.4.4.4"); 791 }); 792 793 add_task(async function test_padding() { 794 setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh`); 795 async function CheckPadding( 796 pad_length, 797 request, 798 none, 799 ecs, 800 padding, 801 ecsPadding 802 ) { 803 Services.prefs.setIntPref("network.trr.padding.length", pad_length); 804 Services.dns.clearCache(true); 805 Services.prefs.setBoolPref("network.trr.padding", false); 806 Services.prefs.setBoolPref("network.trr.disable-ECS", false); 807 await new TRRDNSListener(request, none); 808 809 Services.dns.clearCache(true); 810 Services.prefs.setBoolPref("network.trr.padding", false); 811 Services.prefs.setBoolPref("network.trr.disable-ECS", true); 812 await new TRRDNSListener(request, ecs); 813 814 Services.dns.clearCache(true); 815 Services.prefs.setBoolPref("network.trr.padding", true); 816 Services.prefs.setBoolPref("network.trr.disable-ECS", false); 817 await new TRRDNSListener(request, padding); 818 819 Services.dns.clearCache(true); 820 Services.prefs.setBoolPref("network.trr.padding", true); 821 Services.prefs.setBoolPref("network.trr.disable-ECS", true); 822 await new TRRDNSListener(request, ecsPadding); 823 } 824 825 // short domain name 826 await CheckPadding( 827 16, 828 "a.pd", 829 "2.2.0.22", 830 "2.2.0.41", 831 "1.1.0.48", 832 "1.1.0.48" 833 ); 834 await CheckPadding(256, "a.pd", "2.2.0.22", "2.2.0.41", "1.1.1.0", "1.1.1.0"); 835 836 // medium domain name 837 await CheckPadding( 838 16, 839 "has-padding.pd", 840 "2.2.0.32", 841 "2.2.0.51", 842 "1.1.0.48", 843 "1.1.0.64" 844 ); 845 await CheckPadding( 846 128, 847 "has-padding.pd", 848 "2.2.0.32", 849 "2.2.0.51", 850 "1.1.0.128", 851 "1.1.0.128" 852 ); 853 await CheckPadding( 854 80, 855 "has-padding.pd", 856 "2.2.0.32", 857 "2.2.0.51", 858 "1.1.0.80", 859 "1.1.0.80" 860 ); 861 862 // long domain name 863 await CheckPadding( 864 16, 865 "abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.pd", 866 "2.2.0.131", 867 "2.2.0.150", 868 "1.1.0.160", 869 "1.1.0.160" 870 ); 871 await CheckPadding( 872 128, 873 "abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.pd", 874 "2.2.0.131", 875 "2.2.0.150", 876 "1.1.1.0", 877 "1.1.1.0" 878 ); 879 await CheckPadding( 880 80, 881 "abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.abcdefghijklmnopqrstuvwxyz0123456789.pd", 882 "2.2.0.131", 883 "2.2.0.150", 884 "1.1.0.160", 885 "1.1.0.160" 886 ); 887 }); 888 889 // Can't test for socket process since telemetry is captured in different process. 890 add_task( 891 { skip_if: () => mozinfo.socketprocess_networking }, 892 async function test_trr_pb_telemetry() { 893 setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh`); 894 Services.dns.clearCache(true); 895 Services.fog.initializeFOG(); 896 Services.fog.testResetFOG(); 897 await new TRRDNSListener("testytest.com", { expectedAnswer: "5.5.5.5" }); 898 899 Assert.equal( 900 await Glean.networking.trrRequestCount.regular.testGetValue(), 901 2 902 ); // One for IPv4 and one for IPv6. 903 Assert.equal( 904 await Glean.networking.trrRequestCount.private.testGetValue(), 905 null 906 ); 907 908 await new TRRDNSListener("testytest.com", { 909 expectedAnswer: "5.5.5.5", 910 originAttributes: { privateBrowsingId: 1 }, 911 }); 912 913 Assert.equal( 914 await Glean.networking.trrRequestCount.regular.testGetValue(), 915 2 916 ); 917 Assert.equal( 918 await Glean.networking.trrRequestCount.private.testGetValue(), 919 2 920 ); 921 // We've made 4 TRR requests. 922 Assert.equal( 923 await Glean.networking.trrRequestSize.other.testGetValue().count, 924 4 925 ); 926 Assert.equal( 927 await Glean.networking.trrResponseSize.other.testGetValue().count, 928 4 929 ); 930 } 931 ); 932 933 add_task( 934 { skip_if: () => mozinfo.socketprocess_networking }, 935 async function test_trr_timing_telemetry() { 936 setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh`); 937 Services.dns.clearCache(true); 938 939 // Close the previous TRR connection. 940 Services.obs.notifyObservers(null, "net:cancel-all-connections"); 941 await new Promise(r => do_timeout(3000, r)); 942 943 Services.fog.testResetFOG(); 944 // Disable IPv6, so we only send one TRR request. 945 Services.prefs.setBoolPref("network.dns.disableIPv6", true); 946 await new TRRDNSListener("timing.com", { expectedAnswer: "5.5.5.5" }); 947 948 await new Promise(r => do_timeout(100, r)); 949 950 let dnsStart = await Glean.networking.trrDnsStart.other.testGetValue(); 951 let dnsEnd = await Glean.networking.trrDnsEnd.other.testGetValue(); 952 let tcpConnection = 953 await Glean.networking.trrTcpConnection.other.testGetValue(); 954 let tlsHandshake = 955 await Glean.networking.trrTlsHandshake.other.testGetValue(); 956 let openToFirstSent = 957 await Glean.networking.trrOpenToFirstSent.other.testGetValue(); 958 let firstSentToLastReceived = 959 await Glean.networking.trrFirstSentToLastReceived.other.testGetValue(); 960 let openToFirstReceived = 961 await Glean.networking.trrOpenToFirstReceived.other.testGetValue(); 962 let completeLoad = 963 await Glean.networking.trrCompleteLoad.other.testGetValue(); 964 965 info("dnsStart=" + JSON.stringify(dnsStart)); 966 info("dnsEnd=" + JSON.stringify(dnsEnd)); 967 info("tcpConnection=" + JSON.stringify(tcpConnection)); 968 info("tlsHandshake=" + JSON.stringify(tlsHandshake)); 969 info("openToFirstSent=" + JSON.stringify(openToFirstSent)); 970 info("firstSentToLastReceived=" + JSON.stringify(firstSentToLastReceived)); 971 info("openToFirstReceived=" + JSON.stringify(openToFirstReceived)); 972 info("completeLoad=" + JSON.stringify(completeLoad)); 973 974 Assert.equal(dnsStart.count, 1); 975 Assert.equal(dnsEnd.count, 1); 976 Assert.equal(tcpConnection.count, 1); 977 Assert.equal(tlsHandshake.count, 1); 978 Assert.equal(openToFirstSent.count, 1); 979 Assert.equal(firstSentToLastReceived.count, 1); 980 Assert.equal(openToFirstReceived.count, 1); 981 Assert.equal(completeLoad.count, 1); 982 983 function getValue(obj) { 984 const keys = Object.keys(obj); 985 return keys.length ? +keys[0] : 0; 986 } 987 Assert.greaterOrEqual( 988 getValue(openToFirstReceived.values), 989 getValue(openToFirstSent.values), 990 "openToFirstReceived >= openToFirstSent" 991 ); 992 Assert.greaterOrEqual( 993 getValue(completeLoad.values), 994 getValue(openToFirstReceived.values), 995 "completeLoad >= openToFirstReceived" 996 ); 997 } 998 ); 999 1000 add_task( 1001 { skip_if: () => mozinfo.socketprocess_networking }, 1002 async function test_trr_request_per_conn_telemetry() { 1003 setModeAndURI(Ci.nsIDNSService.MODE_TRRONLY, `doh`); 1004 Services.dns.clearCache(true); 1005 1006 // Close the previous TRR connection. 1007 Services.obs.notifyObservers(null, "net:cancel-all-connections"); 1008 await new Promise(r => do_timeout(3000, r)); 1009 1010 Services.fog.testResetFOG(); 1011 Services.prefs.setBoolPref("network.dns.disableIPv6", false); 1012 await new TRRDNSListener("timing.com", { expectedAnswer: "5.5.5.5" }); 1013 1014 // Close the TRR connection again, so trr_request_count_per_conn 1015 // can be recorded. 1016 Services.obs.notifyObservers(null, "net:cancel-all-connections"); 1017 await new Promise(r => do_timeout(3000, r)); 1018 1019 let requestPerConn = 1020 await Glean.networking.trrRequestCountPerConn.other.testGetValue(); 1021 1022 info("requestPerConn=" + JSON.stringify(requestPerConn)); 1023 1024 Assert.greaterOrEqual(requestPerConn, 2); 1025 } 1026 );