Open ruihildt opened 2 years ago
It is possible to access the container API to do this.
I can think of two nice-to-have features for configuring a socks proxy per container:
I did some research and found that Firefox has a proxy.onRequest
API , which is
Fired when a web request is about to be made, to give the extension an opportunity to proxy it.
browser.proxy.onRequest.addListener(listener, filter, extraInfoSpec)
passes a proxy.RequestDetails
argument to the listener
, which includes the cookieStoreId
. The listener
can return a proxy.ProxyInfo
object to guide the browser on which proxy to use.
One can keep a mapping of containers to proxies and return the proper proxy for each invocation of onRequest
, e.g., predetermined proxies for Multi-Account Containers and randomly selected proxies within a country or city for Temporary Containers.
I tried to add this feature to the code, although I am unfamiliar with Vue.js; I am unsure where to place the logic related to container proxies. In particular, I thought Location.vue
may be a good place to start, but the listeners I add there are never invoked, e.g., when I add a callback function on contextualIdentities.onCreated
, the callback function is never called; moving the same piece of code to background/main.ts
works as expected.
@ruihildt, can you please give me a few pointers on how I should proceed?
Containers aren't supported in Mullvad Browser.
We need to figure out a way forward first.
Now that the extension is proxying by intercepting request using the proxy
API, it should be much easier to integrate with containers.
Any implementation would first need figuring out the relative priorities of proxying:
Are there still users interested in having some kind of proxy/containers integration?
Are there still users interested in having some kind of proxy/containers integration?
Yes, definitely!
I developed an add-on about a year ago where I could fix the proxy server for Firefox Multi-Account Containers and pick a random proxy server for Temporary Containers. The add-on did not have a UI and some parameters, like the city and list of providers, where hard-coded. But I can share parts of the code that dealt with proxying requests if you are interested.
Sure, I'd be happy to have a look when I get the time and opportunity.
Here are the relevant parts of my code. As I mentioned earlier, there are lots of hard-coded parameters that should be cleaned up in the code or moved to the UI to be selected by the user.
browser.proxy.settings.set({value: {proxyType: "system", proxyDNS: true}});
// Define a request object to fetch Mullvad's proxy servers
// In my code, it reads from https://api.mullvad.net/network/v1-beta1/socks-proxies
// I fetch the list of servers on browser startup, but there may be better ways to do it.
request.addEventListener("load", () => {
// Firefox leaks container's DNS if an invalid proxy is not defined.
// The solution is to set an invalid manual SOCKS proxy under Network Settings,
// e.g., localhost:1
browser.proxy.settings.set({value: {proxyType: "manual", socks:"127.0.0.1:1", proxyDNS: true}});
// Parse the JSON including the list of servers, filter the ones that are online, and return an object that includes per-country and per-city list of servers.
// This is where I hard-coded the proxy servers for Multi-Account Containers.
// This mapping should be done through the UI and stored on disk for future use.
// Ideally, the user can select a country, city, or specific server for each persistent container. If they choose a country (city), we randomly select from all proxy servers in that country (city).
const containerProxyMap = {};
browser.contextualIdentities.query({}).then((containers) => {
for (const container of containers) {
if (container.name === "Personal") {
containerProxyMap[container.cookieStoreId] = "IPv4 Address of the Desired Server";
}
else if (container.name === "Work") {
containerProxyMap[container.cookieStoreId] = "IPv4 Address of the Desired Server";
}
}
});
const country = "My Country";
const city = "My City";
const countryCityProxies = proxies[country][city];
const localhosts = new Set(['localhost', '127.0.0.1', '[::1]']);
browser.proxy.onRequest.addListener((requestDetails) => {
try {
const documentUrl = new URL(requestDetails.url);
// I do not proxy requests made to localhost. This should probably be an option.
if (localhosts.has(documentUrl.hostname)) {
return {type: "direct"};
}
// I proxy requests made from the default container through the server I am currently connected to.
if (requestDetails.cookieStoreId === "firefox-default") {
return {type: "socks", host: "10.64.0.1", port: 1080, proxyDNS: true};
}
// If there is no pre-defined mapping for this container, e.g., it is a temporary container, select a random server. In my case, it selects from the country and city I have hard-coded, but this should also be selected by the user in the UI.
if (!(requestDetails.cookieStoreId in containerProxyMap)) {
const index = Math.floor(Math.random() * countryCityProxies.length);
// Use the same proxy server for future requests made from this container. Ideally, we should remove the entry for the container when it has no more active tabs.
containerProxyMap[requestDetails.cookieStoreId] = countryCityProxies[index].ipv4_address;
}
const hostname = containerProxyMap[requestDetails.cookieStoreId];
return [{type: "socks", host: hostname, port: 1080, proxyDNS: true, failoverTimeout: 1}, {type: "socks", host: "10.64.0.1", port: 1080, proxyDNS: true}];
}
catch (e) {
console.error(e);
return {type: "failed"};
}
}, {urls: ["<all_urls>"]});
});
The DNS leak issue explained near the top of the above snippet may be fixed in 128.0:
Firefox now proxies DNS by default when using SOCKS v5, avoiding leaking DNS queries to the network when using SOCKS v5 proxies.
@ruihildt, is per-container proxy settings still being considered to be added to the Mullvad browser extension? The number of blocked requests has increased significantly in the past few weeks (Google and Reddit), and I am hoping using SOCKS5 proxy can eliminate or reduce the blocked requests.
@MahdiNazemi It's not a high priority, but I think you can already configure a website to load using a specific socks5 proxy right now.
Mozilla has integrated that to their Firefox VPN implementation.
Also see #23