Bug 1631609 - Steer to network-indicated DoH endpoint if detected. r=valentin,dragana,NhiNguyen,johannh

Differential Revision: https://phabricator.services.mozilla.com/D76414
This commit is contained in:
Nihanth Subramanya 2020-06-04 19:05:37 +00:00
Родитель a8b62ece12
Коммит 9c7d8bdc02
4 изменённых файлов: 94 добавлений и 24 удалений

Просмотреть файл

@ -31,6 +31,7 @@ const HEURISTICS_TELEMETRY_EVENTS = {
"browserParent",
"thirdPartyRoots",
"policy",
"steeredProvider",
"evaluateReason",
],
record_on_release: true,

Просмотреть файл

@ -62,6 +62,10 @@
"description": "Indicates whether browser policy blocks DoH",
"type": "string"
},
"steeredProvider": {
"description": "Indicates whether we steered to a provider-endpoint. Value is the name of the provider",
"type": "string"
},
"evaluateReason": {
"description": "Reason why we are running heuristics, e.g. startup",
"type": "string"

Просмотреть файл

@ -82,7 +82,7 @@
"parameters": [
{
"type": "string",
"enum": ["doh-rollout.doorhanger-decision", "doh-rollout.heuristics.mockValues"]
"enum": ["doh-rollout.doorhanger-decision", "doh-rollout.heuristics.mockValues", "doh-rollout.provider-steering.provider-list"]
},
{
"type": "string",

Просмотреть файл

@ -11,19 +11,24 @@ const GLOBAL_CANARY = "use-application-dns.net";
const NXDOMAIN_ERR = "NS_ERROR_UNKNOWN_HOST";
async function dnsLookup(hostname) {
async function dnsLookup(hostname, resolveCanonicalName = false) {
let flags = ["disable_trr", "disable_ipv6", "bypass_cache"];
let addresses, err;
if (resolveCanonicalName) {
flags.push("canonical_name");
}
let addresses, canonicalName, err;
try {
let response = await browser.dns.resolve(hostname, flags);
addresses = response.addresses;
canonicalName = response.canonicalName;
} catch (e) {
addresses = [null];
err = e.message;
}
return { addresses, err };
return { addresses, canonicalName, err };
}
async function dnsListLookup(domainList) {
@ -121,26 +126,86 @@ async function modifiedRoots() {
return "enable_doh";
}
async function runHeuristics() {
let safeSearchChecks = await safeSearch();
let zscalerCheck = await zscalerCanary();
let canaryCheck = await globalCanary();
let modifiedRootsCheck = await modifiedRoots();
// Check if the network provides a DoH endpoint to use. Returns the name of the
// provider if the check is successful, else null.
async function providerSteering() {
if (
!(await browser.experiments.preferences.getBoolPref(
"doh-rollout.provider-steering.enabled",
false
))
) {
return null;
}
const TEST_DOMAIN = "doh.test";
// Check other heuristics through privileged code
let browserParentCheck = await browser.experiments.heuristics.checkParentalControls();
let enterpriseCheck = await browser.experiments.heuristics.checkEnterprisePolicies();
let thirdPartyRootsCheck = await browser.experiments.heuristics.checkThirdPartyRoots();
// Array of { name, canonicalName, uri } where name is an identifier for
// telemetry, canonicalName is the expected CNAME when looking up doh.test,
// and uri is the provider's DoH endpoint.
let steeredProviders = await browser.experiments.preferences.getCharPref(
"doh-rollout.provider-steering.provider-list",
"[]"
);
try {
steeredProviders = JSON.parse(steeredProviders);
} catch (e) {
console.log("Provider list is invalid JSON, moving on.");
return null;
}
// Return result of each heuristic
return {
google: safeSearchChecks.google,
youtube: safeSearchChecks.youtube,
zscalerCanary: zscalerCheck,
canary: canaryCheck,
modifiedRoots: modifiedRootsCheck,
browserParent: browserParentCheck,
thirdPartyRoots: thirdPartyRootsCheck,
policy: enterpriseCheck,
};
if (!steeredProviders || !steeredProviders.length) {
return null;
}
let { canonicalName, err } = await dnsLookup(TEST_DOMAIN, true);
if (err || !canonicalName) {
return null;
}
let provider = steeredProviders.find(p => {
return p && p.canonicalName == canonicalName;
});
if (!provider || !provider.uri || !provider.name) {
return null;
}
// We handle this here instead of background.js since we need to set this
// override every time we run heuristics.
browser.experiments.heuristics.setDetectedTrrURI(provider.uri);
return provider.name;
}
async function runHeuristics() {
// First run enterprise and OS-level parental controls heuristics.
let results = {
google: "",
youtube: "",
zscalerCanary: "",
canary: await globalCanary(),
modifiedRoots: await modifiedRoots(),
browserParent: await browser.experiments.heuristics.checkParentalControls(),
thirdPartyRoots: await browser.experiments.heuristics.checkThirdPartyRoots(),
policy: await browser.experiments.heuristics.checkEnterprisePolicies(),
steeredProvider: "",
};
// If any of those were triggered, return the results immediately.
if (Object.values(results).includes("disable_doh")) {
return results;
}
// Check for provider steering, return results immediately if triggered.
results.steeredProvider = (await providerSteering()) || "";
if (results.steeredProvider) {
return results;
}
// Finally, run safe search checks and zscaler canary.
let safeSearchChecks = await safeSearch();
results.google = safeSearchChecks.google;
results.youtube = safeSearchChecks.youtube;
results.zscalerCanary = await zscalerCanary();
return results;
}