tor-browser

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

commit 87e69a7a1cda023fd3efb21f3afccf9f37102048
parent 12a654cf235b070e6cc11f4c128cf97d9098c9fb
Author: Fred Chasen <fchasen@mozilla.com>
Date:   Tue, 28 Oct 2025 18:11:07 +0000

Bug 1996529 - Exclude origins essential to starting the IPP proxy until connected. r=ip-protection-reviewers,baku

Adds a list of essential pref to the `IPPChannelFilter` which will be excluded temporarily.
This will allow getting the proxy pass and telemetry, while still sending these through the VPN when connected.

Differential Revision: https://phabricator.services.mozilla.com/D270281

Diffstat:
Mbrowser/components/ipprotection/IPPChannelFilter.sys.mjs | 35+++++++++++++++++++++++++++++++++--
Mbrowser/components/ipprotection/tests/browser/browser_IPPChannelFilter.js | 32++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/browser/components/ipprotection/IPPChannelFilter.sys.mjs b/browser/components/ipprotection/IPPChannelFilter.sys.mjs @@ -20,6 +20,12 @@ const DEFAULT_EXCLUDED_URL_PREFS = [ "identity.fxaccounts.remote.profile.uri", ]; +const ESSENTIAL_URL_PREFS = [ + "toolkit.telemetry.server", + "network.trr.uri", + "network.trr.default_provider_uri", +]; + /** * IPPChannelFilter is a class that implements the nsIProtocolProxyChannelFilter * when active it will funnel all requests to its provided proxy. @@ -88,6 +94,15 @@ export class IPPChannelFilter { this.addPageExclusion(prefValue); } }); + // Get origins essential to starting the proxy and exclude + // them prior to connecting + this.#essentialOrigins = new Set(); + ESSENTIAL_URL_PREFS.forEach(pref => { + const prefValue = Services.prefs.getStringPref(pref, ""); + if (prefValue) { + this.addEssentialExclusion(prefValue); + } + }); } /** @@ -140,6 +155,11 @@ export class IPPChannelFilter { } const origin = uri.prePath; // scheme://host[:port] + + if (!this.proxyInfo && this.#essentialOrigins.has(origin)) { + return true; + } + return this.#excludedOrigins.has(origin); } catch (_) { return true; @@ -150,18 +170,28 @@ export class IPPChannelFilter { * Adds a page URL to the exclusion list. * * @param {string} url - The URL to exclude. + * @param {Set<string>} [list] - The exclusion list to add the URL to. */ - addPageExclusion(url) { + addPageExclusion(url, list = this.#excludedOrigins) { try { const uri = Services.io.newURI(url); // prePath is scheme://host[:port] - this.#excludedOrigins.add(uri.prePath); + list.add(uri.prePath); } catch (_) { // ignore bad entries } } /** + * Adds a URL to the essential exclusion list. + * + * @param {string} url - The URL to exclude. + */ + addEssentialExclusion(url) { + this.addPageExclusion(url, this.#essentialOrigins); + } + + /** * Starts the Channel Filter, feeding all following Requests through the proxy. */ start() { @@ -285,6 +315,7 @@ export class IPPChannelFilter { #observers = []; #active = false; #excludedOrigins = new Set(); + #essentialOrigins = new Set(); #pendingChannels = []; static makeIsolationKey() { diff --git a/browser/components/ipprotection/tests/browser/browser_IPPChannelFilter.js b/browser/components/ipprotection/tests/browser/browser_IPPChannelFilter.js @@ -57,6 +57,38 @@ add_task(async function test_exclusion_and_proxy() { }); }); +add_task(async function test_essential_exclusion() { + const server = new HttpServer(); + server.registerPathHandler("/", (request, response) => { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/plain"); + response.write("Hello World"); + }); + server.start(-1); + + await withProxyServer(async proxyInfo => { + // Create the IPP connection filter + const filter = IPPChannelFilter.create(); + // Add essential URL to exclusion list + filter.addEssentialExclusion( + "http://localhost:" + server.identity.primaryPort + ); + filter.initialize("", proxyInfo.host, proxyInfo.port, proxyInfo.type); + proxyInfo.gotConnection.then(() => { + Assert.ok(false, "Proxy connection should not be made for excluded URL"); + }); + filter.start(); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://localhost:" + server.identity.primaryPort + ); + await BrowserTestUtils.removeTab(tab); + filter.stop(); + }); +}); + add_task(async function test_channel_suspend_resume() { const server = new HttpServer(); server.registerPathHandler("/", (request, response) => {