Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure socks per container #24

Open
ruihildt opened this issue Nov 24, 2021 · 12 comments
Open

Configure socks per container #24

ruihildt opened this issue Nov 24, 2021 · 12 comments
Labels
proxy This is related to the socks proxy feature

Comments

@ruihildt
Copy link
Member

Privacy Companion is a great tool but it would be nice it one were able to set separate proxies for different container environments within Firefox. So far I've used an addon called "Container Proxy" for this.

Mozilla has integrated that to their Firefox VPN implementation.

Also see #23

@ruihildt ruihildt added documentation Improvements or additions to documentation enhancement proxy This is related to the socks proxy feature and removed documentation Improvements or additions to documentation labels Nov 24, 2021
@ruihildt
Copy link
Member Author

It is possible to access the container API to do this.

@MahdiNazemi
Copy link

I can think of two nice-to-have features for configuring a socks proxy per container:

  1. Always use the same proxy server for specific containers, e.g., Personal, Work, etc.
  2. Automatically connect to a proxy server from a list of user-selected proxy servers when a new temporary container is opened. Allowing the user to select all proxy servers that match his/her time zone (as set in the browser) would be great.

@MahdiNazemi
Copy link

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?

@ruihildt ruihildt moved this from Backlog to Triage in Mullvad Browser Extension Jan 9, 2023
@ruihildt ruihildt moved this from Triage to Backlog in Mullvad Browser Extension Jan 18, 2023
@ruihildt ruihildt moved this from Backlog to Triage in Mullvad Browser Extension Jan 18, 2023
@ruihildt ruihildt moved this from Triage to Backlog in Mullvad Browser Extension Jun 8, 2023
@ruihildt ruihildt moved this from Backlog to Blocked in Mullvad Browser Extension Oct 6, 2023
@ruihildt
Copy link
Member Author

ruihildt commented Oct 6, 2023

Containers aren't supported in Mullvad Browser.

We need to figure out a way forward first.

@ruihildt
Copy link
Member Author

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:

  • containers proxy
  • site specific proxy
  • proxy for all websites

Are there still users interested in having some kind of proxy/containers integration?

@UtilFunction
Copy link

Are there still users interested in having some kind of proxy/containers integration?

Yes, definitely!

@MahdiNazemi
Copy link

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.

@ruihildt
Copy link
Member Author

ruihildt commented Mar 6, 2024

Sure, I'd be happy to have a look when I get the time and opportunity.

@MahdiNazemi
Copy link

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>"]});
});

@MahdiNazemi
Copy link

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.

@MahdiNazemi
Copy link

MahdiNazemi commented Aug 12, 2024

@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.

@ruihildt
Copy link
Member Author

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proxy This is related to the socks proxy feature
Projects
Development

No branches or pull requests

3 participants