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:
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) => {