tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 });