Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/netwerk/test/unit/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 42 kB image not shown  

Quelle  trr_common.js   Sprache: JAVA

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


"use strict";

/* import-globals-from head_cache.js */
/* import-globals-from head_cookies.js */
/* import-globals-from head_trr.js */
/* import-globals-from head_http3.js */

const { TestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/TestUtils.sys.mjs"
);

const { HttpServer } = ChromeUtils.importESModule(
  "resource://testing-common/httpd.sys.mjs"
);

const TRR_Domain = "foo.example.com";

const { MockRegistrar } = ChromeUtils.importESModule(
  "resource://testing-common/MockRegistrar.sys.mjs"
);

const gOverride = Cc["@mozilla.org/network/native-dns-override;1"].getService(
  Ci.nsINativeDNSResolverOverride
);

async function SetParentalControlEnabled(aEnabled) {
  let parentalControlsService = {
    parentalControlsEnabled: aEnabled,
    QueryInterface: ChromeUtils.generateQI(["nsIParentalControlsService"]),
  };
  let cid = MockRegistrar.register(
    "@mozilla.org/parental-controls-service;1",
    parentalControlsService
  );
  Services.dns.reloadParentalControlEnabled();
  MockRegistrar.unregister(cid);
}

let runningOHTTPTests = false;
let h2Port;

function setModeAndURIForODoH(mode, path) {
  Services.prefs.setIntPref("network.trr.mode", mode);
  if (path.substr(0, 4) == "doh?") {
    path = path.replace("doh?""odoh?");
  }

  Services.prefs.setCharPref("network.trr.odoh.target_path", `${path}`);
}

function setModeAndURIForOHTTP(mode, path, domain) {
  Services.prefs.setIntPref("network.trr.mode", mode);
  if (domain) {
    Services.prefs.setCharPref(
      "network.trr.ohttp.uri",
      `https://${domain}:${h2Port}/${path}`
    );
  } else {
    Services.prefs.setCharPref(
      "network.trr.ohttp.uri",
      `https://${TRR_Domain}:${h2Port}/${path}`
    );
  }
}

function setModeAndURI(mode, path, domain) {
  if (runningOHTTPTests) {
    setModeAndURIForOHTTP(mode, path, domain);
  } else {
    Services.prefs.setIntPref("network.trr.mode", mode);
    if (domain) {
      Services.prefs.setCharPref(
        "network.trr.uri",
        `https://${domain}:${h2Port}/${path}`
      );
    } else {
      Services.prefs.setCharPref(
        "network.trr.uri",
        `https://${TRR_Domain}:${h2Port}/${path}`
      );
    }
  }
}

async function test_A_record() {
  info("Verifying a basic A record");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2"); // TRR-first
  await new TRRDNSListener("bar.example.com""2.2.2.2");

  info("Verifying a basic A record - without bootstrapping");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=3.3.3.3"); // TRR-only

  // Clear bootstrap address and add DoH endpoint hostname to local domains
  Services.prefs.clearUserPref("network.trr.bootstrapAddr");
  Services.prefs.setCharPref("network.dns.localDomains", TRR_Domain);

  await new TRRDNSListener("bar.example.com""3.3.3.3");

  Services.prefs.setCharPref("network.trr.bootstrapAddr""127.0.0.1");
  Services.prefs.clearUserPref("network.dns.localDomains");

  info("Verify that the cached record is used when DoH endpoint is down");
  // Don't clear the cache. That is what we're checking.
  setModeAndURI(3, "404");

  await new TRRDNSListener("bar.example.com""3.3.3.3");
  info("verify working credentials in DOH request");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=4.4.4.4&auth=true");
  Services.prefs.setCharPref("network.trr.credentials""user:password");

  await new TRRDNSListener("bar.example.com""4.4.4.4");

  info("Verify failing credentials in DOH request");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=4.4.4.4&auth=true");
  Services.prefs.setCharPref("network.trr.credentials""evil:person");

  let { inStatus } = await new TRRDNSListener(
    "wrong.example.com",
    undefined,
    false
  );
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );

  Services.prefs.clearUserPref("network.trr.credentials");
}

async function test_AAAA_records() {
  info("Verifying AAAA record");

  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=2020:2020::2020&delayIPv4=100");

  await new TRRDNSListener("aaaa.example.com""2020:2020::2020");

  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=2020:2020::2020&delayIPv6=100");

  await new TRRDNSListener("aaaa.example.com""2020:2020::2020");

  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=2020:2020::2020");

  await new TRRDNSListener("aaaa.example.com""2020:2020::2020");
}

async function test_RFC1918() {
  info("Verifying that RFC1918 address from the server is rejected by default");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=192.168.0.1");

  let { inStatus } = await new TRRDNSListener(
    "rfc1918.example.com",
    undefined,
    false
  );

  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
  setModeAndURI(3, "doh?responseIP=::ffff:192.168.0.1");
  ({ inStatus } = await new TRRDNSListener(
    "rfc1918-ipv6.example.com",
    undefined,
    false
  ));
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );

  info("Verify RFC1918 address from the server is fine when told so");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=192.168.0.1");
  Services.prefs.setBoolPref("network.trr.allow-rfc1918"true);
  await new TRRDNSListener("rfc1918.example.com""192.168.0.1");
  setModeAndURI(3, "doh?responseIP=::ffff:192.168.0.1");

  await new TRRDNSListener("rfc1918-ipv6.example.com""::ffff:192.168.0.1");

  Services.prefs.clearUserPref("network.trr.allow-rfc1918");
}

async function test_GET_ECS() {
  info("Verifying resolution via GET with ECS disabled");
  Services.dns.clearCache(true);
  // The template part should be discarded
  setModeAndURI(3, "doh{?dns}");
  Services.prefs.setBoolPref("network.trr.useGET"true);
  Services.prefs.setBoolPref("network.trr.disable-ECS"true);

  await new TRRDNSListener("ecs.example.com""5.5.5.5");

  info("Verifying resolution via GET with ECS enabled");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh");
  Services.prefs.setBoolPref("network.trr.disable-ECS"false);

  await new TRRDNSListener("get.example.com""5.5.5.5");

  Services.prefs.clearUserPref("network.trr.useGET");
  Services.prefs.clearUserPref("network.trr.disable-ECS");
}

async function test_timeout_mode3() {
  info("Verifying that a short timeout causes failure with a slow server");
  Services.dns.clearCache(true);
  // First, mode 3.
  setModeAndURI(3, "doh?noResponse=true");
  Services.prefs.setIntPref("network.trr.request_timeout_ms", 10);
  Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10);

  let { inStatus } = await new TRRDNSListener(
    "timeout.example.com",
    undefined,
    false
  );
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );

  // Now for mode 2
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?noResponse=true");

  await new TRRDNSListener("timeout.example.com""127.0.0.1"); // Should fallback

  Services.prefs.clearUserPref("network.trr.request_timeout_ms");
  Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");
}

async function test_trr_retry() {
  Services.dns.clearCache(true);
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);

  info("Test fallback to native");
  Services.prefs.setBoolPref("network.trr.retry_on_recoverable_errors"false);
  setModeAndURI(2, "doh?noResponse=true");
  Services.prefs.setIntPref("network.trr.request_timeout_ms", 10);
  Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10);

  await new TRRDNSListener("timeout.example.com", {
    expectedAnswer: "127.0.0.1",
  });

  Services.prefs.clearUserPref("network.trr.request_timeout_ms");
  Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");

  info("Test Retry Success");
  Services.prefs.setBoolPref("network.trr.retry_on_recoverable_errors"true);

  let chan = makeChan(
    `https://foo.example.com:${h2Port}/reset-doh-request-count`,
    Ci.nsIRequest.TRR_DISABLED_MODE
  );
  await new Promise(resolve =>
    chan.asyncOpen(new ChannelListener(resolve, null))
  );

  setModeAndURI(2, "doh?responseIP=2.2.2.2&retryOnDecodeFailure=true");
  await new TRRDNSListener("retry_ok.example.com""2.2.2.2");

  info("Test Retry Failed");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2&corruptedAnswer=true");
  await new TRRDNSListener("retry_ng.example.com""127.0.0.1");
}

async function test_strict_native_fallback() {
  Services.dns.clearCache(true);
  Services.prefs.setBoolPref("network.trr.retry_on_recoverable_errors"true);
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);

  info("First a timeout case");
  setModeAndURI(2, "doh?noResponse=true");
  Services.prefs.setIntPref("network.trr.request_timeout_ms", 10);
  Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10);
  Services.prefs.setIntPref(
    "network.trr.strict_fallback_request_timeout_ms",
    10
  );

  Services.prefs.setBoolPref(
    "network.trr.strict_native_fallback_allow_timeouts",
    false
  );

  let { inStatus } = await new TRRDNSListener(
    "timeout.example.com",
    undefined,
    false
  );
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
  Services.dns.clearCache(true);
  await new TRRDNSListener("timeout.example.com", undefined, false);

  Services.dns.clearCache(true);
  Services.prefs.setBoolPref(
    "network.trr.strict_native_fallback_allow_timeouts",
    true
  );
  await new TRRDNSListener("timeout.example.com", {
    expectedAnswer: "127.0.0.1",
  });

  Services.prefs.setBoolPref(
    "network.trr.strict_native_fallback_allow_timeouts",
    false
  );

  info("Now a connection error");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2");
  Services.prefs.clearUserPref("network.trr.request_timeout_ms");
  Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");
  Services.prefs.clearUserPref(
    "network.trr.strict_fallback_request_timeout_ms"
  );
  ({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false));
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );

  info("Now a decode error");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2&corruptedAnswer=true");
  ({ inStatus } = await new TRRDNSListener(
    "bar.example.com",
    undefined,
    false
  ));
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );

  if (!mozinfo.socketprocess_networking) {
    // Confirmation state isn't passed cross-process.
    info("Now with confirmation failed - should fallback");
    Services.dns.clearCache(true);
    setModeAndURI(2, "doh?responseIP=2.2.2.2&corruptedAnswer=true");
    Services.prefs.setCharPref("network.trr.confirmationNS""example.com");
    await TestUtils.waitForCondition(
      // 3 => CONFIRM_FAILED, 4 => CONFIRM_TRYING_FAILED
      () =>
        Services.dns.currentTrrConfirmationState == 3 ||
        Services.dns.currentTrrConfirmationState == 4,
      `Timed out waiting for confirmation failure. Currently ${Services.dns.currentTrrConfirmationState}`,
      1,
      5000
    );
    await new TRRDNSListener("bar.example.com""127.0.0.1"); // Should fallback
  }

  info("Now a successful case.");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2");
  if (!mozinfo.socketprocess_networking) {
    // Only need to reset confirmation state if we messed with it before.
    Services.prefs.setCharPref("network.trr.confirmationNS""skip");
    await TestUtils.waitForCondition(
      // 5 => CONFIRM_DISABLED
      () => Services.dns.currentTrrConfirmationState == 5,
      `Timed out waiting for confirmation disabled. Currently ${Services.dns.currentTrrConfirmationState}`,
      1,
      5000
    );
  }
  await new TRRDNSListener("bar.example.com""2.2.2.2");

  info("Now without strict fallback mode, timeout case");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?noResponse=true");
  Services.prefs.setIntPref("network.trr.request_timeout_ms", 10);
  Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 10);
  Services.prefs.setIntPref(
    "network.trr.strict_fallback_request_timeout_ms",
    10
  );
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);

  await new TRRDNSListener("timeout.example.com""127.0.0.1"); // Should fallback

  info("Now a connection error");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2");
  Services.prefs.clearUserPref("network.trr.request_timeout_ms");
  Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");
  Services.prefs.clearUserPref(
    "network.trr.strict_fallback_request_timeout_ms"
  );
  await new TRRDNSListener("closeme.com""127.0.0.1"); // Should fallback

  info("Now a decode error");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2&corruptedAnswer=true");
  await new TRRDNSListener("bar.example.com""127.0.0.1"); // Should fallback

  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);
  Services.prefs.clearUserPref("network.trr.request_timeout_ms");
  Services.prefs.clearUserPref("network.trr.request_timeout_mode_trronly_ms");
  Services.prefs.clearUserPref(
    "network.trr.strict_fallback_request_timeout_ms"
  );
}

async function test_no_answers_fallback() {
  info("Verfiying that we correctly fallback to Do53 when no answers from DoH");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=none"); // TRR-first

  await new TRRDNSListener("confirm.example.com""127.0.0.1");

  info("Now in strict mode - no fallback");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);
  Services.dns.clearCache(true);
  await new TRRDNSListener("confirm.example.com""127.0.0.1");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);
}

async function test_404_fallback() {
  info("Verfiying that we correctly fallback to Do53 when DoH sends 404");
  Services.dns.clearCache(true);
  setModeAndURI(2, "404"); // TRR-first

  await new TRRDNSListener("test404.example.com""127.0.0.1");

  info("Now in strict mode - no fallback");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);
  Services.dns.clearCache(true);
  let { inStatus } = await new TRRDNSListener("test404.example.com", {
    expectedSuccess: false,
  });
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);
}

async function test_mode_1_and_4() {
  info("Verifying modes 1 and 4 are treated as TRR-off");
  for (let mode of [1, 4]) {
    Services.dns.clearCache(true);
    setModeAndURI(mode, "doh?responseIP=2.2.2.2");
    Assert.equal(
      Services.dns.currentTrrMode,
      5,
      "Effective TRR mode should be 5"
    );
  }
}

async function test_CNAME() {
  info("Checking that we follow a CNAME correctly");
  Services.dns.clearCache(true);
  // The dns-cname path alternates between sending us a CNAME pointing to
  // another domain, and an A record. If we follow the cname correctly, doing
  // a lookup with this path as the DoH URI should resolve to that A record.
  setModeAndURI(3, "dns-cname");

  await new TRRDNSListener("cname.example.com""99.88.77.66");

  info("Verifying that we bail out when we're thrown into a CNAME loop");
  Services.dns.clearCache(true);
  // First mode 3.
  setModeAndURI(3, "doh?responseIP=none&cnameloop=true");

  let { inStatus } = await new TRRDNSListener(
    "test18.example.com",
    undefined,
    false
  );
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );

  // Now mode 2.
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=none&cnameloop=true");

  await new TRRDNSListener("test20.example.com""127.0.0.1"); // Should fallback

  info("Check that we correctly handle CNAME bundled with an A record");
  Services.dns.clearCache(true);
  // "dns-cname-a" path causes server to send a CNAME as well as an A record
  setModeAndURI(3, "dns-cname-a");

  await new TRRDNSListener("cname-a.example.com""9.8.7.6");
}

async function test_name_mismatch() {
  info("Verify that records that don't match the requested name are rejected");
  Services.dns.clearCache(true);
  // Setting hostname param tells server to always send record for bar.example.com
  // regardless of what was requested.
  setModeAndURI(3, "doh?hostname=mismatch.example.com");

  let { inStatus } = await new TRRDNSListener(
    "bar.example.com",
    undefined,
    false
  );
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
}

async function test_mode_2() {
  info("Checking that TRR result is used in mode 2");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=192.192.192.192");
  Services.prefs.setCharPref("network.trr.excluded-domains""");
  Services.prefs.setCharPref("network.trr.builtin-excluded-domains""");

  await new TRRDNSListener("bar.example.com""192.192.192.192");

  info("Now in strict mode");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);
  Services.dns.clearCache(true);
  await new TRRDNSListener("bar.example.com""192.192.192.192");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);
}

async function test_excluded_domains() {
  info("Checking that Do53 is used for names in excluded-domains list");
  for (let strictMode of [truefalse]) {
    info("Strict mode: " + strictMode);
    Services.prefs.setBoolPref(
      "network.trr.strict_native_fallback",
      strictMode
    );
    Services.dns.clearCache(true);
    setModeAndURI(2, "doh?responseIP=192.192.192.192");
    Services.prefs.setCharPref(
      "network.trr.excluded-domains",
      "bar.example.com"
    );

    await new TRRDNSListener("bar.example.com""127.0.0.1"); // Do53 result

    Services.dns.clearCache(true);
    Services.prefs.setCharPref("network.trr.excluded-domains""example.com");

    await new TRRDNSListener("bar.example.com""127.0.0.1");

    Services.dns.clearCache(true);
    Services.prefs.setCharPref(
      "network.trr.excluded-domains",
      "foo.test.com, bar.example.com"
    );
    await new TRRDNSListener("bar.example.com""127.0.0.1");

    Services.dns.clearCache(true);
    Services.prefs.setCharPref(
      "network.trr.excluded-domains",
      "bar.example.com, foo.test.com"
    );

    await new TRRDNSListener("bar.example.com""127.0.0.1");

    Services.prefs.clearUserPref("network.trr.excluded-domains");
  }
}

function topicObserved(topic) {
  return new Promise(resolve => {
    let observer = {
      QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
      observe(aSubject, aTopic, aData) {
        if (aTopic == topic) {
          Services.obs.removeObserver(observer, topic);
          resolve(aData);
        }
      },
    };
    Services.obs.addObserver(observer, topic);
  });
}

async function test_captiveportal_canonicalURL() {
  info("Check that captivedetect.canonicalURL is resolved via native DNS");
  for (let strictMode of [truefalse]) {
    info("Strict mode: " + strictMode);
    Services.prefs.setBoolPref(
      "network.trr.strict_native_fallback",
      strictMode
    );
    Services.dns.clearCache(true);
    setModeAndURI(2, "doh?responseIP=2.2.2.2");

    const cpServer = new HttpServer();
    cpServer.registerPathHandler(
      "/cp",
      function handleRawData(request, response) {
        response.setHeader("Content-Type""text/plain"false);
        response.setHeader("Cache-Control""no-cache"false);
        response.bodyOutputStream.write("data", 4);
      }
    );
    cpServer.start(-1);
    cpServer.identity.setPrimary(
      "http",
      "detectportal.firefox.com",
      cpServer.identity.primaryPort
    );
    let cpPromise = topicObserved("captive-portal-login");

    Services.prefs.setCharPref(
      "captivedetect.canonicalURL",
      `http://detectportal.firefox.com:${cpServer.identity.primaryPort}/cp`
    );
    Services.prefs.setBoolPref("network.captive-portal-service.testMode"true);
    Services.prefs.setBoolPref("network.captive-portal-service.enabled"true);

    // The captive portal has to have used native DNS, otherwise creating
    // a socket to a non-local IP would trigger a crash.
    await cpPromise;
    // Simply resolving the captive portal domain should still use TRR
    await new TRRDNSListener("detectportal.firefox.com""2.2.2.2");

    Services.prefs.clearUserPref("network.captive-portal-service.enabled");
    Services.prefs.clearUserPref("network.captive-portal-service.testMode");
    Services.prefs.clearUserPref("captivedetect.canonicalURL");

    await new Promise(resolve => cpServer.stop(resolve));
  }
}

async function test_parentalcontrols() {
  info("Check that DoH isn't used when parental controls are enabled");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2");
  await SetParentalControlEnabled(true);
  await new TRRDNSListener("www.example.com""127.0.0.1");
  await SetParentalControlEnabled(false);

  info("Now in strict mode");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2");
  await SetParentalControlEnabled(true);
  await new TRRDNSListener("www.example.com""127.0.0.1");
  await SetParentalControlEnabled(false);
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);
}

async function test_builtin_excluded_domains() {
  info("Verifying Do53 is used for domains in builtin-excluded-domians list");
  for (let strictMode of [truefalse]) {
    info("Strict mode: " + strictMode);
    Services.prefs.setBoolPref(
      "network.trr.strict_native_fallback",
      strictMode
    );
    Services.dns.clearCache(true);
    setModeAndURI(2, "doh?responseIP=2.2.2.2");

    Services.prefs.setCharPref("network.trr.excluded-domains""");
    Services.prefs.setCharPref(
      "network.trr.builtin-excluded-domains",
      "bar.example.com"
    );
    await new TRRDNSListener("bar.example.com""127.0.0.1");

    Services.dns.clearCache(true);
    Services.prefs.setCharPref(
      "network.trr.builtin-excluded-domains",
      "example.com"
    );
    await new TRRDNSListener("bar.example.com""127.0.0.1");

    Services.dns.clearCache(true);
    Services.prefs.setCharPref(
      "network.trr.builtin-excluded-domains",
      "foo.test.com, bar.example.com"
    );
    await new TRRDNSListener("bar.example.com""127.0.0.1");
    await new TRRDNSListener("foo.test.com""127.0.0.1");
  }
}

async function test_excluded_domains_mode3() {
  info("Checking Do53 is used for names in excluded-domains list in mode 3");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=192.192.192.192");
  Services.prefs.setCharPref("network.trr.excluded-domains""");
  Services.prefs.setCharPref("network.trr.builtin-excluded-domains""");

  await new TRRDNSListener("excluded""192.192.192.192"true);

  Services.dns.clearCache(true);
  Services.prefs.setCharPref("network.trr.excluded-domains""excluded");

  await new TRRDNSListener("excluded""127.0.0.1");

  // Test .local
  Services.dns.clearCache(true);
  Services.prefs.setCharPref("network.trr.excluded-domains""excluded,local");

  await new TRRDNSListener("test.local""127.0.0.1");

  // Test .other
  Services.dns.clearCache(true);
  Services.prefs.setCharPref(
    "network.trr.excluded-domains",
    "excluded,local,other"
  );

  await new TRRDNSListener("domain.other""127.0.0.1");
}

async function test25e() {
  info("Check captivedetect.canonicalURL is resolved via native DNS in mode 3");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=192.192.192.192");

  const cpServer = new HttpServer();
  cpServer.registerPathHandler(
    "/cp",
    function handleRawData(request, response) {
      response.setHeader("Content-Type""text/plain"false);
      response.setHeader("Cache-Control""no-cache"false);
      response.bodyOutputStream.write("data", 4);
    }
  );
  cpServer.start(-1);
  cpServer.identity.setPrimary(
    "http",
    "detectportal.firefox.com",
    cpServer.identity.primaryPort
  );
  let cpPromise = topicObserved("captive-portal-login");

  Services.prefs.setCharPref(
    "captivedetect.canonicalURL",
    `http://detectportal.firefox.com:${cpServer.identity.primaryPort}/cp`
  );
  Services.prefs.setBoolPref("network.captive-portal-service.testMode"true);
  Services.prefs.setBoolPref("network.captive-portal-service.enabled"true);

  // The captive portal has to have used native DNS, otherwise creating
  // a socket to a non-local IP would trigger a crash.
  await cpPromise;
  // // Simply resolving the captive portal domain should still use TRR
  await new TRRDNSListener("detectportal.firefox.com""192.192.192.192");

  Services.prefs.clearUserPref("network.captive-portal-service.enabled");
  Services.prefs.clearUserPref("network.captive-portal-service.testMode");
  Services.prefs.clearUserPref("captivedetect.canonicalURL");

  await new Promise(resolve => cpServer.stop(resolve));
}

async function test_parentalcontrols_mode3() {
  info("Check DoH isn't used when parental controls are enabled in mode 3");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=192.192.192.192");
  await SetParentalControlEnabled(true);
  await new TRRDNSListener("www.example.com""127.0.0.1");
  await SetParentalControlEnabled(false);
}

async function test_builtin_excluded_domains_mode3() {
  info("Check Do53 used for domains in builtin-excluded-domians list, mode 3");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=192.192.192.192");
  Services.prefs.setCharPref("network.trr.excluded-domains""");
  Services.prefs.setCharPref(
    "network.trr.builtin-excluded-domains",
    "excluded"
  );

  await new TRRDNSListener("excluded""127.0.0.1");

  // Test .local
  Services.dns.clearCache(true);
  Services.prefs.setCharPref(
    "network.trr.builtin-excluded-domains",
    "excluded,local"
  );

  await new TRRDNSListener("test.local""127.0.0.1");

  // Test .other
  Services.dns.clearCache(true);
  Services.prefs.setCharPref(
    "network.trr.builtin-excluded-domains",
    "excluded,local,other"
  );

  await new TRRDNSListener("domain.other""127.0.0.1");
}

async function count_cookies() {
  info("Check that none of the requests have set any cookies.");
  Assert.equal(Services.cookies.countCookiesFromHost("example.com"), 0);
  Assert.equal(Services.cookies.countCookiesFromHost("foo.example.com."), 0);
}

async function test_connection_closed() {
  info("Check we handle it correctly when the connection is closed");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=2.2.2.2");
  Services.prefs.setCharPref("network.trr.excluded-domains""");
  // We don't need to wait for 30 seconds for the request to fail
  Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 500);
  // bootstrap
  Services.prefs.clearUserPref("network.dns.localDomains");
  Services.prefs.setCharPref("network.trr.bootstrapAddr""127.0.0.1");

  await new TRRDNSListener("bar.example.com""2.2.2.2");

  // makes the TRR connection shut down.
  let { inStatus } = await new TRRDNSListener("closeme.com", undefined, false);
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
  await new TRRDNSListener("bar2.example.com""2.2.2.2");

  // No bootstrap this time
  Services.prefs.clearUserPref("network.trr.bootstrapAddr");

  Services.dns.clearCache(true);
  Services.prefs.setCharPref("network.trr.excluded-domains""excluded,local");
  Services.prefs.setCharPref("network.dns.localDomains", TRR_Domain);

  await new TRRDNSListener("bar.example.com""2.2.2.2");

  // makes the TRR connection shut down.
  ({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false));
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
  await new TRRDNSListener("bar2.example.com""2.2.2.2");

  // No local domains either
  Services.dns.clearCache(true);
  Services.prefs.setCharPref("network.trr.excluded-domains""excluded");
  Services.prefs.clearUserPref("network.dns.localDomains");
  Services.prefs.clearUserPref("network.trr.bootstrapAddr");

  await new TRRDNSListener("bar.example.com""2.2.2.2");

  // makes the TRR connection shut down.
  ({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false));
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
  await new TRRDNSListener("bar2.example.com""2.2.2.2");

  // Now make sure that even in mode 3 without a bootstrap address
  // we are able to restart the TRR connection if it drops - the TRR service
  // channel will use regular DNS to resolve the TRR address.
  Services.dns.clearCache(true);
  Services.prefs.setCharPref("network.trr.excluded-domains""");
  Services.prefs.setCharPref("network.trr.builtin-excluded-domains""");
  Services.prefs.clearUserPref("network.dns.localDomains");
  Services.prefs.clearUserPref("network.trr.bootstrapAddr");

  await new TRRDNSListener("bar.example.com""2.2.2.2");

  // makes the TRR connection shut down.
  ({ inStatus } = await new TRRDNSListener("closeme.com", undefined, false));
  Assert.ok(
    !Components.isSuccessCode(inStatus),
    `${inStatus} should be an error code`
  );
  Services.dns.clearCache(true);
  await new TRRDNSListener("bar2.example.com""2.2.2.2");

  // This test exists to document what happens when we're in TRR only mode
  // and we don't set a bootstrap address. We use DNS to resolve the
  // initial URI, but if the connection fails, we don't fallback to DNS
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=9.9.9.9");
  Services.prefs.setCharPref("network.dns.localDomains""closeme.com");
  Services.prefs.clearUserPref("network.trr.bootstrapAddr");

  await new TRRDNSListener("bar.example.com""9.9.9.9");

  // makes the TRR connection shut down. Should fallback to DNS
  await new TRRDNSListener("closeme.com""127.0.0.1");
  // TRR should be back up again
  await new TRRDNSListener("bar2.example.com""9.9.9.9");
}

async function test_fetch_time() {
  info("Verifying timing");
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=2.2.2.2&delayIPv4=20");

  await new TRRDNSListener("bar_time.example.com""2.2.2.2"true, 20);

  // gets an error from DoH. It will fall back to regular DNS. The TRR timing should be 0.
  Services.dns.clearCache(true);
  setModeAndURI(2, "404&delayIPv4=20");

  await new TRRDNSListener("bar_time1.example.com""127.0.0.1"true, 0);

  // check an excluded domain. It should fall back to regular DNS. The TRR timing should be 0.
  Services.prefs.setCharPref(
    "network.trr.excluded-domains",
    "bar_time2.example.com"
  );
  for (let strictMode of [truefalse]) {
    info("Strict mode: " + strictMode);
    Services.prefs.setBoolPref(
      "network.trr.strict_native_fallback",
      strictMode
    );
    Services.dns.clearCache(true);
    setModeAndURI(2, "doh?responseIP=2.2.2.2&delayIPv4=20");
    await new TRRDNSListener("bar_time2.example.com""127.0.0.1"true, 0);
  }

  Services.prefs.setCharPref("network.trr.excluded-domains""");

  // verify RFC1918 address from the server is rejected and the TRR timing will be not set because the response will be from the native resolver.
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=192.168.0.1&delayIPv4=20");
  await new TRRDNSListener("rfc1918_time.example.com""127.0.0.1"true, 0);
}

async function test_fqdn() {
  info("Test that we handle FQDN encoding and decoding properly");
  Services.dns.clearCache(true);
  setModeAndURI(3, "doh?responseIP=9.8.7.6");

  await new TRRDNSListener("fqdn.example.org.""9.8.7.6");

  // GET
  Services.dns.clearCache(true);
  Services.prefs.setBoolPref("network.trr.useGET"true);
  await new TRRDNSListener("fqdn_get.example.org.""9.8.7.6");

  Services.prefs.clearUserPref("network.trr.useGET");
}

async function test_ipv6_trr_fallback() {
  info("Testing fallback with ipv6");
  Services.dns.clearCache(true);

  setModeAndURI(2, "doh?responseIP=4.4.4.4");
  const override = Cc["@mozilla.org/network/native-dns-override;1"].getService(
    Ci.nsINativeDNSResolverOverride
  );
  gOverride.addIPOverride("ipv6.host.com""1:1::2");

  // Should not fallback to Do53 because A request for ipv6.host.com returns
  // 4.4.4.4
  let { inStatus } = await new TRRDNSListener("ipv6.host.com", {
    flags: Ci.nsIDNSService.RESOLVE_DISABLE_IPV4,
    expectedSuccess: false,
  });
  equal(inStatus, Cr.NS_ERROR_UNKNOWN_HOST);

  // This time both requests fail, so we do fall back
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=none");
  await new TRRDNSListener("ipv6.host.com""1:1::2");

  info("In strict mode, the lookup should fail when both reqs fail.");
  Services.dns.clearCache(true);
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);
  setModeAndURI(2, "doh?responseIP=none");
  await new TRRDNSListener("ipv6.host.com""1:1::2");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);

  override.clearOverrides();
}

async function test_ipv4_trr_fallback() {
  info("Testing fallback with ipv4");
  Services.dns.clearCache(true);

  setModeAndURI(2, "doh?responseIP=1:2::3");
  const override = Cc["@mozilla.org/network/native-dns-override;1"].getService(
    Ci.nsINativeDNSResolverOverride
  );
  gOverride.addIPOverride("ipv4.host.com""3.4.5.6");

  // Should not fallback to Do53 because A request for ipv4.host.com returns
  // 1:2::3
  let { inStatus } = await new TRRDNSListener("ipv4.host.com", {
    flags: Ci.nsIDNSService.RESOLVE_DISABLE_IPV6,
    expectedSuccess: false,
  });
  equal(inStatus, Cr.NS_ERROR_UNKNOWN_HOST);

  // This time both requests fail, so we do fall back
  Services.dns.clearCache(true);
  setModeAndURI(2, "doh?responseIP=none");
  await new TRRDNSListener("ipv4.host.com""3.4.5.6");

  // No fallback with strict mode.
  Services.dns.clearCache(true);
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);
  setModeAndURI(2, "doh?responseIP=none");
  await new TRRDNSListener("ipv4.host.com""3.4.5.6");
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"false);

  override.clearOverrides();
}

async function test_no_retry_without_doh() {
  info("Bug 1648147 - if the TRR returns 0.0.0.0 we should not retry with DNS");
  Services.prefs.setBoolPref("network.trr.fallback-on-zero-response"false);
  Services.prefs.setBoolPref("network.socket.ip_addr_any.disabled"false);
  Services.prefs.setBoolPref("network.trr.allow-rfc1918"true);

  async function test(url, ip) {
    setModeAndURI(2, `doh?responseIP=${ip}`);

    // Requests to 0.0.0.0 are usually directed to localhost, so let's use a port
    // we know isn't being used - 666 (Doom)
    let chan = makeChan(url, Ci.nsIRequest.TRR_DEFAULT_MODE);
    let statusCounter = {
      statusCount: {},
      QueryInterface: ChromeUtils.generateQI([
        "nsIInterfaceRequestor",
        "nsIProgressEventSink",
      ]),
      getInterface(iid) {
        return this.QueryInterface(iid);
      },
      onProgress() {},
      onStatus(request, status) {
        this.statusCount[status] = 1 + (this.statusCount[status] || 0);
      },
    };
    chan.notificationCallbacks = statusCounter;
    await new Promise(resolve =>
      chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE))
    );
    equal(
      statusCounter.statusCount[0x4b000b],
      1,
      "Expecting only one instance of NS_NET_STATUS_RESOLVED_HOST"
    );
    equal(
      statusCounter.statusCount[0x4b0007],
      1,
      "Expecting only one instance of NS_NET_STATUS_CONNECTING_TO"
    );
  }

  for (let strictMode of [truefalse]) {
    info("Strict mode: " + strictMode);
    Services.prefs.setBoolPref(
      "network.trr.strict_native_fallback",
      strictMode
    );
    await test(`http://unknown.ipv4.stuff:666/path`, "0.0.0.0");
    await test(`http://unknown.ipv6.stuff:666/path`, "::");
  }

  Services.prefs.clearUserPref("network.trr.allow-rfc1918");
  Services.prefs.clearUserPref("network.socket.ip_addr_any.disabled");
}

async function test_connection_reuse_and_cycling() {
  Services.dns.clearCache(true);
  Services.prefs.setIntPref("network.trr.request_timeout_ms", 500);
  Services.prefs.setIntPref(
    "network.trr.strict_fallback_request_timeout_ms",
    500
  );
  Services.prefs.setIntPref("network.trr.request_timeout_mode_trronly_ms", 500);

  setModeAndURI(2, `doh?responseIP=9.8.7.6`);
  Services.prefs.setBoolPref("network.trr.strict_native_fallback"true);
  Services.prefs.setCharPref("network.trr.confirmationNS""example.com");
  await TestUtils.waitForCondition(
    // 2 => CONFIRM_OK
    () => Services.dns.currentTrrConfirmationState == 2,
    `Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
    1,
    5000
  );

  // Setting conncycle=true in the URI. Server will start logging reqs.
  // We will do a specific sequence of lookups, then fetch the log from
  // the server and check that it matches what we'd expect.
  setModeAndURI(2, `doh?responseIP=9.8.7.6&conncycle=true`);
  await TestUtils.waitForCondition(
    // 2 => CONFIRM_OK
    () => Services.dns.currentTrrConfirmationState == 2,
    `Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
    1,
    5000
  );
  // Confirmation upon uri-change will have created one req.

  // Two reqs for each bar1 and bar2 - A + AAAA.
  await new TRRDNSListener("bar1.example.org.""9.8.7.6");
  await new TRRDNSListener("bar2.example.org.""9.8.7.6");
  // Total so far: (1) + 2 + 2 = 5

  // Two reqs that fail, one Confirmation req, two retried reqs that succeed.
  await new TRRDNSListener("newconn.example.org.""9.8.7.6");
  await TestUtils.waitForCondition(
    // 2 => CONFIRM_OK
    () => Services.dns.currentTrrConfirmationState == 2,
    `Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
    1,
    5000
  );
  // Total so far: (5) + 2 + 1 + 2 = 10

  // Two reqs for each bar3 and bar4 .
  await new TRRDNSListener("bar3.example.org.""9.8.7.6");
  await new TRRDNSListener("bar4.example.org.""9.8.7.6");
  // Total so far: (10) + 2 + 2 = 14.

  // Two reqs that fail, one Confirmation req, two retried reqs that succeed.
  await new TRRDNSListener("newconn2.example.org.""9.8.7.6");
  await TestUtils.waitForCondition(
    // 2 => CONFIRM_OK
    () => Services.dns.currentTrrConfirmationState == 2,
    `Timed out waiting for confirmation success. Currently ${Services.dns.currentTrrConfirmationState}`,
    1,
    5000
  );
  // Total so far: (14) + 2 + 1 + 2 = 19

  // Two reqs for each bar5 and bar6 .
  await new TRRDNSListener("bar5.example.org.""9.8.7.6");
  await new TRRDNSListener("bar6.example.org.""9.8.7.6");
  // Total so far: (19) + 2 + 2 = 23

  let chan = makeChan(
    `https://foo.example.com:${h2Port}/get-doh-req-port-log`,
    Ci.nsIRequest.TRR_DISABLED_MODE
  );
  let dohReqPortLog = await new Promise(resolve =>
    chan.asyncOpen(
      new ChannelListener((stuff, buffer) => {
        resolve(JSON.parse(buffer));
      })
    )
  );

  // Since the actual ports seen will vary at runtime, we use placeholders
  // instead in our expected output definition. For example, if two entries
  // both have "port1", it means they both should have the same port in the
  // server's log.
  // For reqs that fail and trigger a Confirmation + retry, the retried reqs
  // might not re-use the new connection created for Confirmation due to a
  // race, so we have an extra alternate expected port for them. This lets
  // us test that they use *a* new port even if it's not *the* new port.
  // Subsequent lookups are not affected, they will use the same conn as
  // the Confirmation req.
  let expectedLogTemplate = [
    ["example.com""port1"],
    ["bar1.example.org""port1"],
    ["bar1.example.org""port1"],
    ["bar2.example.org""port1"],
    ["bar2.example.org""port1"],
    ["newconn.example.org""port1"],
    ["newconn.example.org""port1"],
    ["example.com""port2"],
    ["newconn.example.org""port2"],
    ["newconn.example.org""port2"],
    ["bar3.example.org""port2"],
    ["bar3.example.org""port2"],
    ["bar4.example.org""port2"],
    ["bar4.example.org""port2"],
    ["newconn2.example.org""port2"],
    ["newconn2.example.org""port2"],
    ["example.com""port3"],
    ["newconn2.example.org""port3"],
    ["newconn2.example.org""port3"],
    ["bar5.example.org""port3"],
    ["bar5.example.org""port3"],
    ["bar6.example.org""port3"],
    ["bar6.example.org""port3"],
  ];

  if (expectedLogTemplate.length != dohReqPortLog.length) {
    // This shouldn't happen, and if it does, we'll fail the assertion
    // below. But first dump the whole server-side log to help with
    // debugging should we see a failure. Most likely cause would be
    // that another consumer of TRR happened to make a request while
    // the test was running and polluted the log.
    info(dohReqPortLog);
  }

  equal(
    expectedLogTemplate.length,
    dohReqPortLog.length,
    "Correct number of req log entries"
  );

  let seenPorts = new Set();
  // This is essentially a symbol table - as we iterate through the log
  // we will assign the actual seen port numbers to the placeholders.
  let seenPortsByExpectedPort = new Map();

  for (let i = 0; i < expectedLogTemplate.length; i++) {
    let expectedName = expectedLogTemplate[i][0];
    let expectedPort = expectedLogTemplate[i][1];
    let seenName = dohReqPortLog[i][0];
    let seenPort = dohReqPortLog[i][1];
    info(`Checking log entry. Name: ${seenName}, Port: ${seenPort}`);
    equal(expectedName, seenName, "Name matches for entry " + i);
    if (!seenPortsByExpectedPort.has(expectedPort)) {
      ok(!seenPorts.has(seenPort), "Port should not have been previously used");
      seenPorts.add(seenPort);
      seenPortsByExpectedPort.set(expectedPort, seenPort);
    } else {
      equal(
        seenPort,
        seenPortsByExpectedPort.get(expectedPort),
        "Connection was reused as expected"
      );
    }
  }
}

Messung V0.5
C=97 H=96 G=96

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.