tor-browser

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

test_http3_proxy_ipv6_fallback.js (5771B)


      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 var { setTimeout } = ChromeUtils.importESModule(
      8  "resource://gre/modules/Timer.sys.mjs"
      9 );
     10 
     11 const { Http3ProxyFilter, NodeHTTP2Server, NodeHTTP2ProxyServer } =
     12  ChromeUtils.importESModule("resource://testing-common/NodeServer.sys.mjs");
     13 
     14 let pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService();
     15 let trrServer;
     16 let proxyFilter;
     17 let proxyPort;
     18 let proxyHost;
     19 let serverPort;
     20 
     21 add_setup(async function setup() {
     22  trr_test_setup();
     23 
     24  if (mozinfo.socketprocess_networking) {
     25    Cc["@mozilla.org/network/protocol;1?name=http"].getService(
     26      Ci.nsIHttpProtocolHandler
     27    );
     28    Services.dns; // Needed to trigger socket process.
     29    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
     30    await new Promise(resolve => setTimeout(resolve, 1000));
     31  }
     32 
     33  Services.prefs.setBoolPref("network.http.http3.enable", true);
     34  Services.prefs.setBoolPref(
     35    "network.http.http3.block_loopback_ipv6_addr",
     36    true
     37  );
     38  Services.prefs.setBoolPref(
     39    "network.http.http3.retry_different_ip_family",
     40    false
     41  );
     42  Services.prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true);
     43  Services.prefs.setBoolPref("network.dns.get-ttl", false);
     44 
     45  let proxy = new NodeHTTP2ProxyServer();
     46  await proxy.startWithoutProxyFilter();
     47  proxyPort = proxy.port();
     48  proxyHost = "alt2.example.com";
     49 
     50  trrServer = new TRRServer();
     51  await trrServer.start();
     52 
     53  Services.prefs.setIntPref("network.trr.mode", 3);
     54  Services.prefs.setCharPref(
     55    "network.trr.uri",
     56    `https://foo.example.com:${trrServer.port()}/dns-query`
     57  );
     58 
     59  await trrServer.registerDoHAnswers(proxyHost, "AAAA", {
     60    answers: [
     61      {
     62        name: proxyHost,
     63        ttl: 55,
     64        type: "AAAA",
     65        flush: false,
     66        data: "::1",
     67      },
     68    ],
     69  });
     70  await trrServer.registerDoHAnswers(proxyHost, "A", {
     71    answers: [
     72      {
     73        name: proxyHost,
     74        ttl: 55,
     75        type: "A",
     76        flush: false,
     77        data: "127.0.0.1",
     78      },
     79    ],
     80  });
     81 
     82  await new TRRDNSListener(proxyHost, "::1");
     83 
     84  let server = new NodeHTTP2Server();
     85  await server.start();
     86  serverPort = server.port();
     87  info(`server port:${server.port()}`);
     88 
     89  // Register multiple endpoints
     90  await server.registerPathHandler("/concurrent1", (req, resp) => {
     91    resp.writeHead(200);
     92    resp.end("response1");
     93  });
     94  await server.registerPathHandler("/concurrent2", (req, resp) => {
     95    resp.writeHead(200);
     96    resp.end("response2");
     97  });
     98  await server.registerPathHandler("/concurrent3", (req, resp) => {
     99    resp.writeHead(200);
    100    resp.end("response3");
    101  });
    102 
    103  proxyFilter = new Http3ProxyFilter(
    104    proxyHost,
    105    proxyPort,
    106    0,
    107    "/.well-known/masque/udp/{target_host}/{target_port}/",
    108    ""
    109  );
    110 
    111  registerCleanupFunction(async () => {
    112    trr_clear_prefs();
    113    Services.prefs.clearUserPref(
    114      "network.http.http3.retry_different_ip_family"
    115    );
    116    Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
    117    Services.prefs.clearUserPref("network.http.http3.block_loopback_ipv6_addr");
    118    Services.prefs.clearUserPref("network.dns.get-ttl");
    119    Services.prefs.clearUserPref("network.proxy.allow_hijacking_localhost");
    120    if (trrServer) {
    121      await trrServer.stop();
    122    }
    123    await proxy.stop();
    124    await server.stop();
    125  });
    126 });
    127 
    128 function makeChan(url) {
    129  let chan = NetUtil.newChannel({
    130    uri: url,
    131    loadUsingSystemPrincipal: true,
    132    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
    133  }).QueryInterface(Ci.nsIHttpChannel);
    134  chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
    135  return chan;
    136 }
    137 
    138 function channelOpenPromise(chan, flags) {
    139  // eslint-disable-next-line no-async-promise-executor
    140  return new Promise(async resolve => {
    141    function finish(req, buffer) {
    142      resolve([req, buffer]);
    143    }
    144    chan.asyncOpen(new ChannelListener(finish, null, flags));
    145  });
    146 }
    147 
    148 // Test if we fallback to HTTP/2 proxy when IPv6 is blocked.
    149 add_task(async function test_fallback_with_speculative_connection() {
    150  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 6);
    151  pps.registerFilter(proxyFilter, 10);
    152 
    153  const promises = [];
    154  for (let i = 1; i <= 3; i++) {
    155    let chan = makeChan(
    156      `https://alt1.example.com:${serverPort}/concurrent${i}`
    157    );
    158    promises.push(channelOpenPromise(chan, CL_IGNORE_CL | CL_ALLOW_UNKNOWN_CL));
    159  }
    160 
    161  const results = await Promise.all(promises);
    162 
    163  // Verify all requests succeeded with correct responses
    164  for (let i = 0; i < 3; i++) {
    165    const [req, buf] = results[i];
    166    Assert.equal(req.status, Cr.NS_OK);
    167    Assert.equal(buf, `response${i + 1}`);
    168  }
    169 
    170  pps.unregisterFilter(proxyFilter);
    171 });
    172 
    173 add_task(async function test_fallback_without_speculative_connection() {
    174  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
    175 
    176  Services.obs.notifyObservers(null, "net:cancel-all-connections");
    177  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    178  await new Promise(resolve => setTimeout(resolve, 1000));
    179 
    180  pps.registerFilter(proxyFilter, 10);
    181 
    182  const promises = [];
    183  for (let i = 1; i <= 3; i++) {
    184    let chan = makeChan(
    185      `https://alt1.example.com:${serverPort}/concurrent${i}`
    186    );
    187    promises.push(channelOpenPromise(chan, CL_IGNORE_CL | CL_ALLOW_UNKNOWN_CL));
    188  }
    189 
    190  const results = await Promise.all(promises);
    191 
    192  // Verify all requests succeeded with correct responses
    193  for (let i = 0; i < 3; i++) {
    194    const [req, buf] = results[i];
    195    Assert.equal(req.status, Cr.NS_OK);
    196    Assert.equal(buf, `response${i + 1}`);
    197  }
    198 
    199  pps.unregisterFilter(proxyFilter);
    200 });