test_trr_https_fallback.js (30991B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { TestUtils } = ChromeUtils.importESModule( 8 "resource://testing-common/TestUtils.sys.mjs" 9 ); 10 11 let h2Port; 12 let h3Port; 13 let h3NoResponsePort; 14 let trrServer; 15 16 const certOverrideService = Cc[ 17 "@mozilla.org/security/certoverride;1" 18 ].getService(Ci.nsICertOverrideService); 19 20 add_setup(async function setup() { 21 trr_test_setup(); 22 23 h2Port = Services.env.get("MOZHTTP2_PORT"); 24 Assert.notEqual(h2Port, null); 25 Assert.notEqual(h2Port, ""); 26 27 h3Port = Services.env.get("MOZHTTP3_PORT"); 28 Assert.notEqual(h3Port, null); 29 Assert.notEqual(h3Port, ""); 30 31 h3NoResponsePort = Services.env.get("MOZHTTP3_PORT_NO_RESPONSE"); 32 Assert.notEqual(h3NoResponsePort, null); 33 Assert.notEqual(h3NoResponsePort, ""); 34 35 Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true); 36 Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true); 37 Services.prefs.setBoolPref("network.dns.echconfig.enabled", true); 38 Services.prefs.setBoolPref( 39 "network.dns.https_rr.check_record_with_cname", 40 false 41 ); 42 43 registerCleanupFunction(async () => { 44 trr_clear_prefs(); 45 Services.prefs.clearUserPref("network.dns.upgrade_with_https_rr"); 46 Services.prefs.clearUserPref("network.dns.use_https_rr_as_altsvc"); 47 Services.prefs.clearUserPref("network.dns.echconfig.enabled"); 48 Services.prefs.clearUserPref( 49 "network.dns.echconfig.fallback_to_origin_when_all_failed" 50 ); 51 Services.prefs.clearUserPref("network.dns.httpssvc.reset_exclustion_list"); 52 Services.prefs.clearUserPref("network.http.http3.enable"); 53 Services.prefs.clearUserPref( 54 "network.dns.httpssvc.http3_fast_fallback_timeout" 55 ); 56 Services.prefs.clearUserPref("network.http.speculative-parallel-limit"); 57 Services.prefs.clearUserPref("network.dns.localDomains"); 58 Services.prefs.clearUserPref("network.dns.http3_echconfig.enabled"); 59 Services.prefs.clearUserPref( 60 "network.dns.https_rr.check_record_with_cname" 61 ); 62 if (trrServer) { 63 await trrServer.stop(); 64 } 65 }); 66 67 if (mozinfo.socketprocess_networking) { 68 Services.dns; // Needed to trigger socket process. 69 await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched); 70 } 71 72 Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRFIRST); 73 }); 74 75 function makeChan(url) { 76 let chan = NetUtil.newChannel({ 77 uri: url, 78 loadUsingSystemPrincipal: true, 79 contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, 80 }).QueryInterface(Ci.nsIHttpChannel); 81 return chan; 82 } 83 84 function channelOpenPromise(chan, flags) { 85 return new Promise(resolve => { 86 function finish(req, buffer) { 87 resolve([req, buffer]); 88 certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( 89 false 90 ); 91 } 92 certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( 93 true 94 ); 95 chan.asyncOpen(new ChannelListener(finish, null, flags)); 96 }); 97 } 98 99 // Test if we can fallback to the last record sucessfully. 100 add_task(async function testFallbackToTheLastRecord() { 101 trrServer = new TRRServer(); 102 await trrServer.start(); 103 104 Services.prefs.setIntPref("network.trr.mode", 3); 105 Services.prefs.setCharPref( 106 "network.trr.uri", 107 `https://foo.example.com:${trrServer.port()}/dns-query` 108 ); 109 110 // Only the last record is valid to use. 111 await trrServer.registerDoHAnswers( 112 `_${h2Port}._https.test.fallback.com`, 113 "HTTPS", 114 { 115 answers: [ 116 { 117 name: `_${h2Port}._https.test.fallback.com`, 118 ttl: 55, 119 type: "HTTPS", 120 flush: false, 121 data: { 122 priority: 1, 123 name: "test.fallback1.com", 124 values: [ 125 { key: "alpn", value: ["h2", "h3-26"] }, 126 { key: "echconfig", value: "123..." }, 127 ], 128 }, 129 }, 130 { 131 name: `_${h2Port}._https.test.fallback.com`, 132 ttl: 55, 133 type: "HTTPS", 134 flush: false, 135 data: { 136 priority: 4, 137 name: "foo.example.com", 138 values: [ 139 { key: "alpn", value: ["h2", "h3-26"] }, 140 { key: "port", value: h2Port }, 141 { key: "echconfig", value: "456..." }, 142 ], 143 }, 144 }, 145 { 146 name: `_${h2Port}._https.test.fallback.com`, 147 ttl: 55, 148 type: "HTTPS", 149 flush: false, 150 data: { 151 priority: 3, 152 name: "test.fallback3.com", 153 values: [ 154 { key: "alpn", value: ["h2", "h3-26"] }, 155 { key: "echconfig", value: "456..." }, 156 ], 157 }, 158 }, 159 { 160 name: `_${h2Port}._https.test.fallback.com`, 161 ttl: 55, 162 type: "HTTPS", 163 flush: false, 164 data: { 165 priority: 2, 166 name: "test.fallback2.com", 167 values: [ 168 { key: "alpn", value: ["h2", "h3-26"] }, 169 { key: "echconfig", value: "456..." }, 170 ], 171 }, 172 }, 173 ], 174 } 175 ); 176 177 await new TRRDNSListener("test.fallback.com", { 178 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 179 port: h2Port, 180 }); 181 182 let chan = makeChan(`https://test.fallback.com:${h2Port}/server-timing`); 183 let [req] = await channelOpenPromise(chan); 184 // Test if this request is done by h2. 185 Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); 186 187 await trrServer.stop(); 188 }); 189 190 add_task(async function testFallbackToTheOrigin() { 191 trrServer = new TRRServer(); 192 await trrServer.start(); 193 Services.prefs.setIntPref("network.trr.mode", 3); 194 Services.prefs.setBoolPref( 195 "network.dns.echconfig.fallback_to_origin_when_all_failed", 196 true 197 ); 198 Services.prefs.setCharPref( 199 "network.trr.uri", 200 `https://foo.example.com:${trrServer.port()}/dns-query` 201 ); 202 203 // All records are not able to use to connect, so we fallback to the origin 204 // one. 205 await trrServer.registerDoHAnswers("test.foo.com", "HTTPS", { 206 answers: [ 207 { 208 name: "test.foo.com", 209 ttl: 55, 210 type: "HTTPS", 211 flush: false, 212 data: { 213 priority: 1, 214 name: "test.foo1.com", 215 values: [ 216 { key: "alpn", value: ["h2", "h3-26"] }, 217 { key: "echconfig", value: "123..." }, 218 ], 219 }, 220 }, 221 { 222 name: "test.foo.com", 223 ttl: 55, 224 type: "HTTPS", 225 flush: false, 226 data: { 227 priority: 3, 228 name: "test.foo3.com", 229 values: [ 230 { key: "alpn", value: ["h2", "h3-26"] }, 231 { key: "echconfig", value: "456..." }, 232 ], 233 }, 234 }, 235 { 236 name: "test.foo.com", 237 ttl: 55, 238 type: "HTTPS", 239 flush: false, 240 data: { 241 priority: 2, 242 name: "test.foo2.com", 243 values: [ 244 { key: "alpn", value: ["h2", "h3-26"] }, 245 { key: "echconfig", value: "456..." }, 246 ], 247 }, 248 }, 249 ], 250 }); 251 252 await trrServer.registerDoHAnswers("test.foo.com", "A", { 253 answers: [ 254 { 255 name: "test.foo.com", 256 ttl: 55, 257 type: "A", 258 flush: false, 259 data: "127.0.0.1", 260 }, 261 ], 262 }); 263 264 await new TRRDNSListener("test.foo.com", { 265 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 266 }); 267 268 let chan = makeChan(`https://test.foo.com:${h2Port}/server-timing`); 269 let [req] = await channelOpenPromise(chan); 270 // Test if this request is done by h2. 271 Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); 272 273 await trrServer.stop(); 274 }); 275 276 // Test when all records are failed and network.dns.echconfig.fallback_to_origin 277 // is false. In this case, the connection is always failed. 278 add_task(async function testAllRecordsFailed() { 279 trrServer = new TRRServer(); 280 await trrServer.start(); 281 Services.prefs.setIntPref("network.trr.mode", 3); 282 Services.prefs.setCharPref( 283 "network.trr.uri", 284 `https://foo.example.com:${trrServer.port()}/dns-query` 285 ); 286 Services.prefs.setBoolPref( 287 "network.dns.echconfig.fallback_to_origin_when_all_failed", 288 false 289 ); 290 291 await trrServer.registerDoHAnswers("test.bar.com", "HTTPS", { 292 answers: [ 293 { 294 name: "test.bar.com", 295 ttl: 55, 296 type: "HTTPS", 297 flush: false, 298 data: { 299 priority: 1, 300 name: "test.bar1.com", 301 values: [ 302 { key: "alpn", value: ["h2", "h3-26"] }, 303 { key: "echconfig", value: "123..." }, 304 ], 305 }, 306 }, 307 { 308 name: "test.bar.com", 309 ttl: 55, 310 type: "HTTPS", 311 flush: false, 312 data: { 313 priority: 3, 314 name: "test.bar3.com", 315 values: [ 316 { key: "alpn", value: ["h2", "h3-26"] }, 317 { key: "echconfig", value: "456..." }, 318 ], 319 }, 320 }, 321 { 322 name: "test.bar.com", 323 ttl: 55, 324 type: "HTTPS", 325 flush: false, 326 data: { 327 priority: 2, 328 name: "test.bar2.com", 329 values: [ 330 { key: "alpn", value: ["h2", "h3-26"] }, 331 { key: "echconfig", value: "456..." }, 332 ], 333 }, 334 }, 335 ], 336 }); 337 338 await new TRRDNSListener("test.bar.com", { 339 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 340 }); 341 342 // This channel should be failed. 343 let chan = makeChan(`https://test.bar.com:${h2Port}/server-timing`); 344 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 345 346 await trrServer.stop(); 347 }); 348 349 // Test when all records have no echConfig, we directly fallback to the origin 350 // one. 351 add_task(async function testFallbackToTheOrigin2() { 352 trrServer = new TRRServer(); 353 await trrServer.start(); 354 Services.prefs.setIntPref("network.trr.mode", 3); 355 Services.prefs.setCharPref( 356 "network.trr.uri", 357 `https://foo.example.com:${trrServer.port()}/dns-query` 358 ); 359 360 await trrServer.registerDoHAnswers("test.example.com", "HTTPS", { 361 answers: [ 362 { 363 name: "test.example.com", 364 ttl: 55, 365 type: "HTTPS", 366 flush: false, 367 data: { 368 priority: 1, 369 name: "test.example1.com", 370 values: [{ key: "alpn", value: ["h2", "h3-26"] }], 371 }, 372 }, 373 { 374 name: "test.example.com", 375 ttl: 55, 376 type: "HTTPS", 377 flush: false, 378 data: { 379 priority: 3, 380 name: "test.example3.com", 381 values: [{ key: "alpn", value: ["h2", "h3-26"] }], 382 }, 383 }, 384 ], 385 }); 386 387 await new TRRDNSListener("test.example.com", { 388 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 389 }); 390 391 let chan = makeChan(`https://test.example.com:${h2Port}/server-timing`); 392 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 393 394 await trrServer.registerDoHAnswers("test.example.com", "A", { 395 answers: [ 396 { 397 name: "test.example.com", 398 ttl: 55, 399 type: "A", 400 flush: false, 401 data: "127.0.0.1", 402 }, 403 ], 404 }); 405 406 chan = makeChan(`https://test.example.com:${h2Port}/server-timing`); 407 await channelOpenPromise(chan); 408 409 await trrServer.stop(); 410 }); 411 412 // Test when some records have echConfig and some not, we directly fallback to 413 // the origin one. 414 add_task(async function testFallbackToTheOrigin3() { 415 Services.dns.clearCache(true); 416 417 trrServer = new TRRServer(); 418 await trrServer.start(); 419 Services.prefs.setIntPref("network.trr.mode", 3); 420 Services.prefs.setCharPref( 421 "network.trr.uri", 422 `https://foo.example.com:${trrServer.port()}/dns-query` 423 ); 424 425 await trrServer.registerDoHAnswers("vulnerable.com", "A", { 426 answers: [ 427 { 428 name: "vulnerable.com", 429 ttl: 55, 430 type: "A", 431 flush: false, 432 data: "127.0.0.1", 433 }, 434 ], 435 }); 436 437 await trrServer.registerDoHAnswers("vulnerable.com", "HTTPS", { 438 answers: [ 439 { 440 name: "vulnerable.com", 441 ttl: 55, 442 type: "HTTPS", 443 flush: false, 444 data: { 445 priority: 1, 446 name: "vulnerable1.com", 447 values: [ 448 { key: "alpn", value: ["h2", "h3-26"] }, 449 { key: "echconfig", value: "456..." }, 450 ], 451 }, 452 }, 453 { 454 name: "vulnerable.com", 455 ttl: 55, 456 type: "HTTPS", 457 flush: false, 458 data: { 459 priority: 2, 460 name: "vulnerable2.com", 461 values: [ 462 { key: "alpn", value: ["h2", "h3-26"] }, 463 { key: "echconfig", value: "456..." }, 464 ], 465 }, 466 }, 467 { 468 name: "vulnerable.com", 469 ttl: 55, 470 type: "HTTPS", 471 flush: false, 472 data: { 473 priority: 3, 474 name: "vulnerable3.com", 475 values: [{ key: "alpn", value: ["h2", "h3-26"] }], 476 }, 477 }, 478 ], 479 }); 480 481 await new TRRDNSListener("vulnerable.com", { 482 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 483 }); 484 485 let chan = makeChan(`https://vulnerable.com:${h2Port}/server-timing`); 486 await channelOpenPromise(chan); 487 488 await trrServer.stop(); 489 }); 490 491 add_task(async function testResetExclusionList() { 492 trrServer = new TRRServer(); 493 await trrServer.start(); 494 Services.prefs.setIntPref("network.trr.mode", 3); 495 Services.prefs.setCharPref( 496 "network.trr.uri", 497 `https://foo.example.com:${trrServer.port()}/dns-query` 498 ); 499 Services.prefs.setBoolPref( 500 "network.dns.httpssvc.reset_exclustion_list", 501 false 502 ); 503 504 await trrServer.registerDoHAnswers( 505 `_${h2Port}._https.test.reset.com`, 506 "HTTPS", 507 { 508 answers: [ 509 { 510 name: `_${h2Port}._https.test.reset.com`, 511 ttl: 55, 512 type: "HTTPS", 513 flush: false, 514 data: { 515 priority: 1, 516 name: "test.reset1.com", 517 values: [ 518 { key: "alpn", value: ["h2", "h3-26"] }, 519 { key: "port", value: h2Port }, 520 { key: "echconfig", value: "456..." }, 521 ], 522 }, 523 }, 524 { 525 name: `_${h2Port}._https.test.reset.com`, 526 ttl: 55, 527 type: "HTTPS", 528 flush: false, 529 data: { 530 priority: 2, 531 name: "test.reset2.com", 532 values: [ 533 { key: "alpn", value: ["h2", "h3-26"] }, 534 { key: "echconfig", value: "456..." }, 535 ], 536 }, 537 }, 538 ], 539 } 540 ); 541 542 await new TRRDNSListener("test.reset.com", { 543 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 544 port: h2Port, 545 }); 546 547 // After this request, test.reset1.com and test.reset2.com should be both in 548 // the exclusion list. 549 let chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`); 550 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 551 552 // This request should be also failed, because all records are excluded. 553 chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`); 554 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 555 556 await trrServer.registerDoHAnswers("test.reset1.com", "A", { 557 answers: [ 558 { 559 name: "test.reset1.com", 560 ttl: 55, 561 type: "A", 562 flush: false, 563 data: "127.0.0.1", 564 }, 565 ], 566 }); 567 568 Services.prefs.setBoolPref( 569 "network.dns.httpssvc.reset_exclustion_list", 570 true 571 ); 572 573 // After enable network.dns.httpssvc.reset_exclustion_list and register 574 // A record for test.reset1.com, this request should be succeeded. 575 chan = makeChan(`https://test.reset.com:${h2Port}/server-timing`); 576 await channelOpenPromise(chan); 577 578 await trrServer.stop(); 579 }); 580 581 // Simply test if we can connect to H3 server. 582 add_task(async function testH3Connection() { 583 trrServer = new TRRServer(); 584 await trrServer.start(); 585 Services.prefs.setIntPref("network.trr.mode", 3); 586 Services.prefs.setCharPref( 587 "network.trr.uri", 588 `https://foo.example.com:${trrServer.port()}/dns-query` 589 ); 590 Services.prefs.setBoolPref("network.http.http3.enable", true); 591 592 Services.prefs.setIntPref( 593 "network.dns.httpssvc.http3_fast_fallback_timeout", 594 100 595 ); 596 597 await trrServer.registerDoHAnswers("test.h3.com", "HTTPS", { 598 answers: [ 599 { 600 name: "test.h3.com", 601 ttl: 55, 602 type: "HTTPS", 603 flush: false, 604 data: { 605 priority: 1, 606 name: "www.h3.com", 607 values: [ 608 { key: "alpn", value: "h3" }, 609 { key: "port", value: h3Port }, 610 { key: "echconfig", value: "456..." }, 611 ], 612 }, 613 }, 614 ], 615 }); 616 617 await trrServer.registerDoHAnswers("www.h3.com", "A", { 618 answers: [ 619 { 620 name: "www.h3.com", 621 ttl: 55, 622 type: "A", 623 flush: false, 624 data: "127.0.0.1", 625 }, 626 ], 627 }); 628 629 await new TRRDNSListener("test.h3.com", { 630 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 631 }); 632 633 let chan = makeChan(`https://test.h3.com`); 634 let [req] = await channelOpenPromise(chan); 635 Assert.equal(req.protocolVersion, "h3"); 636 let internal = req.QueryInterface(Ci.nsIHttpChannelInternal); 637 Assert.equal(internal.remotePort, h3Port); 638 639 await trrServer.stop(); 640 }); 641 642 add_task(async function testFastfallbackToH2() { 643 trrServer = new TRRServer(); 644 await trrServer.start(); 645 Services.prefs.setIntPref("network.trr.mode", 3); 646 Services.prefs.setCharPref( 647 "network.trr.uri", 648 `https://foo.example.com:${trrServer.port()}/dns-query` 649 ); 650 Services.prefs.setBoolPref("network.http.http3.enable", true); 651 // Use a short timeout to make sure the fast fallback timer will be triggered. 652 Services.prefs.setIntPref( 653 "network.dns.httpssvc.http3_fast_fallback_timeout", 654 1 655 ); 656 Services.prefs.setCharPref( 657 "network.dns.localDomains", 658 "test.fastfallback1.com" 659 ); 660 661 await trrServer.registerDoHAnswers("test.fastfallback.com", "HTTPS", { 662 answers: [ 663 { 664 name: "test.fastfallback.com", 665 ttl: 55, 666 type: "HTTPS", 667 flush: false, 668 data: { 669 priority: 1, 670 name: "test.fastfallback1.com", 671 values: [ 672 { key: "alpn", value: "h3" }, 673 { key: "port", value: h3NoResponsePort }, 674 { key: "echconfig", value: "456..." }, 675 ], 676 }, 677 }, 678 { 679 name: "test.fastfallback.com", 680 ttl: 55, 681 type: "HTTPS", 682 flush: false, 683 data: { 684 priority: 2, 685 name: "test.fastfallback2.com", 686 values: [ 687 { key: "alpn", value: "h2" }, 688 { key: "port", value: h2Port }, 689 { key: "echconfig", value: "456..." }, 690 ], 691 }, 692 }, 693 ], 694 }); 695 696 await trrServer.registerDoHAnswers("test.fastfallback2.com", "A", { 697 answers: [ 698 { 699 name: "test.fastfallback2.com", 700 ttl: 55, 701 type: "A", 702 flush: false, 703 data: "127.0.0.1", 704 }, 705 ], 706 }); 707 708 await new TRRDNSListener("test.fastfallback.com", { 709 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 710 }); 711 712 let chan = makeChan(`https://test.fastfallback.com/server-timing`); 713 let [req] = await channelOpenPromise(chan); 714 Assert.equal(req.protocolVersion, "h2"); 715 let internal = req.QueryInterface(Ci.nsIHttpChannelInternal); 716 Assert.equal(internal.remotePort, h2Port); 717 718 // Use a longer timeout to test the case that the timer is canceled. 719 Services.prefs.setIntPref( 720 "network.dns.httpssvc.http3_fast_fallback_timeout", 721 5000 722 ); 723 724 chan = makeChan(`https://test.fastfallback.com/server-timing`); 725 [req] = await channelOpenPromise(chan); 726 Assert.equal(req.protocolVersion, "h2"); 727 internal = req.QueryInterface(Ci.nsIHttpChannelInternal); 728 Assert.equal(internal.remotePort, h2Port); 729 730 await trrServer.stop(); 731 }); 732 733 // Test when we fail to establish H3 connection. 734 add_task(async function testFailedH3Connection() { 735 trrServer = new TRRServer(); 736 await trrServer.start(); 737 Services.dns.clearCache(true); 738 Services.prefs.setIntPref("network.trr.mode", 3); 739 Services.prefs.setCharPref( 740 "network.trr.uri", 741 `https://foo.example.com:${trrServer.port()}/dns-query` 742 ); 743 Services.prefs.setBoolPref("network.http.http3.enable", true); 744 Services.prefs.setIntPref( 745 "network.dns.httpssvc.http3_fast_fallback_timeout", 746 0 747 ); 748 749 await trrServer.registerDoHAnswers("test.h3.org", "HTTPS", { 750 answers: [ 751 { 752 name: "test.h3.org", 753 ttl: 55, 754 type: "HTTPS", 755 flush: false, 756 data: { 757 priority: 1, 758 name: "www.h3.org", 759 values: [ 760 { key: "alpn", value: "h3" }, 761 { key: "port", value: h3Port }, 762 { key: "echconfig", value: "456..." }, 763 ], 764 }, 765 }, 766 ], 767 }); 768 769 await new TRRDNSListener("test.h3.org", { 770 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 771 }); 772 773 let chan = makeChan(`https://test.h3.org`); 774 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 775 776 await trrServer.stop(); 777 }); 778 779 // Test we don't use the service mode record whose domain is in 780 // http3 excluded list. 781 add_task(async function testHttp3ExcludedList() { 782 trrServer = new TRRServer(); 783 await trrServer.start(); 784 Services.dns.clearCache(true); 785 Services.prefs.setIntPref("network.trr.mode", 3); 786 Services.prefs.setCharPref( 787 "network.trr.uri", 788 `https://foo.example.com:${trrServer.port()}/dns-query` 789 ); 790 Services.prefs.setBoolPref("network.http.http3.enable", true); 791 Services.prefs.setIntPref( 792 "network.dns.httpssvc.http3_fast_fallback_timeout", 793 0 794 ); 795 796 Services.prefs.setCharPref( 797 "network.http.http3.alt-svc-mapping-for-testing", 798 "www.h3_fail.org;h3=:" + h3Port 799 ); 800 801 // This will fail because there is no address record for www.h3_fail.org. 802 let chan = makeChan(`https://www.h3_fail.org`); 803 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 804 805 // Now www.h3_fail.org should be already excluded, so the second record 806 // foo.example.com will be selected. 807 await trrServer.registerDoHAnswers("test.h3_excluded.org", "HTTPS", { 808 answers: [ 809 { 810 name: "test.h3_excluded.org", 811 ttl: 55, 812 type: "HTTPS", 813 flush: false, 814 data: { 815 priority: 1, 816 name: "www.h3_fail.org", 817 values: [ 818 { key: "alpn", value: "h3" }, 819 { key: "no-default-alpn" }, 820 { key: "port", value: h3Port }, 821 ], 822 }, 823 }, 824 { 825 name: "test.h3_excluded.org", 826 ttl: 55, 827 type: "HTTPS", 828 flush: false, 829 data: { 830 priority: 2, 831 name: "foo.example.com", 832 values: [ 833 { key: "alpn", value: "h3" }, 834 { key: "port", value: h3Port }, 835 ], 836 }, 837 }, 838 ], 839 }); 840 841 await new TRRDNSListener("test.h3_excluded.org", { 842 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 843 }); 844 845 chan = makeChan(`https://test.h3_excluded.org`); 846 let [req] = await channelOpenPromise(chan); 847 Assert.equal(req.protocolVersion, "h3"); 848 let internal = req.QueryInterface(Ci.nsIHttpChannelInternal); 849 Assert.equal(internal.remotePort, h3Port); 850 851 await trrServer.stop(); 852 }); 853 854 add_task(async function testAllRecordsInHttp3ExcludedList() { 855 trrServer = new TRRServer(); 856 await trrServer.start(); 857 Services.dns.clearCache(true); 858 Services.prefs.setIntPref("network.trr.mode", 3); 859 Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", true); 860 Services.prefs.setCharPref( 861 "network.trr.uri", 862 `https://foo.example.com:${trrServer.port()}/dns-query` 863 ); 864 Services.prefs.setBoolPref("network.http.http3.enable", true); 865 Services.prefs.setIntPref( 866 "network.dns.httpssvc.http3_fast_fallback_timeout", 867 0 868 ); 869 870 Services.prefs.setCharPref( 871 "network.http.http3.alt-svc-mapping-for-testing", 872 "_${h2Port}._https.www.h3_fail1.org;h3=:" + h3Port 873 ); 874 875 await trrServer.registerDoHAnswers(`www.h3_all_excluded.org`, "A", { 876 answers: [ 877 { 878 name: `www.h3_all_excluded.org`, 879 ttl: 55, 880 type: "A", 881 flush: false, 882 data: "127.0.0.1", 883 }, 884 ], 885 }); 886 887 // Test we can connect to www.h3_all_excluded.org sucessfully. 888 let chan = makeChan( 889 `https://www.h3_all_excluded.org:${h2Port}/server-timing` 890 ); 891 892 let [req] = await channelOpenPromise(chan); 893 894 // Test if this request is done by h2. 895 Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); 896 897 // This will fail because there is no address record for www.h3_fail1.org. 898 chan = makeChan(`https://www.h3_fail1.org`); 899 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 900 901 Services.prefs.setCharPref( 902 "network.http.http3.alt-svc-mapping-for-testing", 903 "_${h2Port}._https.www.h3_fail2.org;h3=:" + h3Port 904 ); 905 906 // This will fail because there is no address record for www.h3_fail2.org. 907 chan = makeChan(`https://www.h3_fail2.org`); 908 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 909 910 await trrServer.registerDoHAnswers( 911 `_${h2Port}._https.www.h3_all_excluded.org`, 912 "HTTPS", 913 { 914 answers: [ 915 { 916 name: `_${h2Port}._https.www.h3_all_excluded.org`, 917 ttl: 55, 918 type: "HTTPS", 919 flush: false, 920 data: { 921 priority: 1, 922 name: "www.h3_fail1.org", 923 values: [ 924 { key: "alpn", value: "h3" }, 925 { key: "no-default-alpn" }, 926 { key: "port", value: h3Port }, 927 { key: "echconfig", value: "456..." }, 928 ], 929 }, 930 }, 931 { 932 name: `_${h2Port}._https.www.h3_all_excluded.org`, 933 ttl: 55, 934 type: "HTTPS", 935 flush: false, 936 data: { 937 priority: 2, 938 name: "www.h3_fail2.org", 939 values: [ 940 { key: "alpn", value: "h3" }, 941 { key: "port", value: h3Port }, 942 { key: "echconfig", value: "456..." }, 943 ], 944 }, 945 }, 946 ], 947 } 948 ); 949 950 await new TRRDNSListener("www.h3_all_excluded.org", { 951 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 952 port: h2Port, 953 }); 954 955 Services.dns.clearCache(true); 956 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0); 957 Services.obs.notifyObservers(null, "net:prune-all-connections"); 958 959 // All HTTPS RRs are in http3 excluded list and all records are failed to 960 // connect, so don't fallback to the origin one. 961 chan = makeChan(`https://www.h3_all_excluded.org:${h2Port}/server-timing`); 962 await channelOpenPromise(chan, CL_EXPECT_LATE_FAILURE | CL_ALLOW_UNKNOWN_CL); 963 964 await trrServer.registerDoHAnswers("www.h3_fail1.org", "A", { 965 answers: [ 966 { 967 name: "www.h3_fail1.org", 968 ttl: 55, 969 type: "A", 970 flush: false, 971 data: "127.0.0.1", 972 }, 973 ], 974 }); 975 976 // The the case that when all records are in http3 excluded list, we still 977 // give the first record one more shot. 978 chan = makeChan(`https://www.h3_all_excluded.org:${h2Port}`); 979 [req] = await channelOpenPromise(chan); 980 Assert.equal(req.protocolVersion, "h3"); 981 let internal = req.QueryInterface(Ci.nsIHttpChannelInternal); 982 Assert.equal(internal.remotePort, h3Port); 983 984 await trrServer.stop(); 985 }); 986 987 WebSocketListener.prototype = { 988 onAcknowledge() {}, 989 onBinaryMessageAvailable() {}, 990 onMessageAvailable() {}, 991 onServerClose() {}, 992 onStart() { 993 this.finish(); 994 }, 995 onStop() {}, 996 }; 997 998 add_task(async function testUpgradeNotUsingHTTPSRR() { 999 trrServer = new TRRServer(); 1000 await trrServer.start(); 1001 Services.prefs.setIntPref("network.trr.mode", 3); 1002 Services.prefs.setCharPref( 1003 "network.trr.uri", 1004 `https://foo.example.com:${trrServer.port()}/dns-query` 1005 ); 1006 1007 await trrServer.registerDoHAnswers("test.ws.com", "HTTPS", { 1008 answers: [ 1009 { 1010 name: "test.ws.com", 1011 ttl: 55, 1012 type: "HTTPS", 1013 flush: false, 1014 data: { 1015 priority: 1, 1016 name: "test.ws1.com", 1017 values: [{ key: "port", value: ["8888"] }], 1018 }, 1019 }, 1020 ], 1021 }); 1022 1023 await new TRRDNSListener("test.ws.com", { 1024 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 1025 }); 1026 1027 await trrServer.registerDoHAnswers("test.ws.com", "A", { 1028 answers: [ 1029 { 1030 name: "test.ws.com", 1031 ttl: 55, 1032 type: "A", 1033 flush: false, 1034 data: "127.0.0.1", 1035 }, 1036 ], 1037 }); 1038 1039 let wssUri = "wss://test.ws.com:" + h2Port + "/websocket"; 1040 let chan = Cc["@mozilla.org/network/protocol;1?name=wss"].createInstance( 1041 Ci.nsIWebSocketChannel 1042 ); 1043 chan.initLoadInfo( 1044 null, // aLoadingNode 1045 Services.scriptSecurityManager.getSystemPrincipal(), 1046 null, // aTriggeringPrincipal 1047 Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, 1048 Ci.nsIContentPolicy.TYPE_DOCUMENT 1049 ); 1050 1051 var uri = Services.io.newURI(wssUri); 1052 var wsListener = new WebSocketListener(); 1053 certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( 1054 false 1055 ); 1056 await new Promise(resolve => { 1057 wsListener.finish = resolve; 1058 chan.asyncOpen(uri, wssUri, {}, 0, wsListener, null); 1059 certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData( 1060 true 1061 ); 1062 }); 1063 1064 await trrServer.stop(); 1065 }); 1066 1067 // Test if we fallback to h2 with echConfig. 1068 add_task(async function testFallbackToH2WithEchConfig() { 1069 trrServer = new TRRServer(); 1070 await trrServer.start(); 1071 Services.dns.clearCache(true); 1072 Services.prefs.setIntPref("network.trr.mode", 3); 1073 Services.prefs.setCharPref( 1074 "network.trr.uri", 1075 `https://foo.example.com:${trrServer.port()}/dns-query` 1076 ); 1077 Services.prefs.setBoolPref("network.http.http3.enable", true); 1078 Services.prefs.setIntPref( 1079 "network.dns.httpssvc.http3_fast_fallback_timeout", 1080 0 1081 ); 1082 1083 await trrServer.registerDoHAnswers("test.fallback.org", "HTTPS", { 1084 answers: [ 1085 { 1086 name: "test.fallback.org", 1087 ttl: 55, 1088 type: "HTTPS", 1089 flush: false, 1090 data: { 1091 priority: 1, 1092 name: "test.fallback.org", 1093 values: [ 1094 { key: "alpn", value: ["h2", "h3"] }, 1095 { key: "port", value: h2Port }, 1096 { key: "echconfig", value: "456..." }, 1097 ], 1098 }, 1099 }, 1100 ], 1101 }); 1102 1103 await trrServer.registerDoHAnswers("test.fallback.org", "A", { 1104 answers: [ 1105 { 1106 name: "test.fallback.org", 1107 ttl: 55, 1108 type: "A", 1109 flush: false, 1110 data: "127.0.0.1", 1111 }, 1112 ], 1113 }); 1114 1115 await new TRRDNSListener("test.fallback.org", { 1116 type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC, 1117 }); 1118 1119 await new TRRDNSListener("test.fallback.org", "127.0.0.1"); 1120 1121 let chan = makeChan(`https://test.fallback.org/server-timing`); 1122 let [req] = await channelOpenPromise(chan); 1123 // Test if this request is done by h2. 1124 Assert.equal(req.getResponseHeader("x-connection-http2"), "yes"); 1125 1126 await trrServer.stop(); 1127 });