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

Allow users to choose a SOCKS5 proxy instead of firewall rules. #5032

Open
DemiMarie opened this issue May 11, 2019 · 12 comments
Open

Allow users to choose a SOCKS5 proxy instead of firewall rules. #5032

DemiMarie opened this issue May 11, 2019 · 12 comments
Labels
C: networking P: default Priority: default. Default priority for new issues, to be replaced given sufficient information.

Comments

@DemiMarie
Copy link

DemiMarie commented May 11, 2019

The problem you're addressing (if any)
Many websites do not have stable IP addresses, and rely on dynamic DNS instead. Furthermore, multiple sites can share an IP address. Google is an extreme case ― any of Google’s sites can be at any of Google’s IP addresses. This makes L3 firewalling essentially useless.

While the QubesOS docs do provide a way to use an HTTP proxy, it has several disadvantages:

  • It is not tightly integrated with QubesOS. Users must configure proxy ACLs in text files, rather than via the GUI.
  • Not all programs support HTTP proxies. Thunderbird and OpenSSH are notable examples.
  • HTTP proxies must handle all of HTTP, which has non-trivial attack surface. This is compounded by the fact that the documented configuration runs the proxies unsandboxed.
  • The documentation suggests downloading an unsigned Python script from a mailing list, then running it. This is not a good idea.

Describe the solution you'd like
One solution is to use a filtering SOCKS5 proxy instead. SOCKS5 has several advantages:

  • In my experience, more programs support SOCKS5 proxies than HTTP proxies. For example, both Thunderbird and OpenSSH do.
  • Tools such as tproxy allow using SOCKS5 proxies with applications that do not support them natively.
  • SOCKS5 is a very simple protocol. As a result, SOCKS5 proxies have minimal attack surface. Furthermore, it is probably not difficult to implement one, especially in languages such as Go, Nim, or Haskell.
  • SOCKS5 supports UDP, which means that protocols such as QUIC can work.
  • SOCKS5 supports allows the proxied application to listen on a TCP socket, which allows support of protocols such as FTP.
  • A filtering SOCKS5 proxy written in Nim already exists. My understanding is that Nim is memory-safe when compiled correctly.

For this to be of maximal use, there would need to be tight integration with QubesOS. That is, users must be able to select and configure it via the firewall GUI.

Where is the value to a user, and who might that user be?
This allows users to whitelist based on domain name, rather than on IP address. This allows far more specific filtering than would otherwise be possible, especially for sites hosted by large companies such as Google.

Describe alternatives you've considered
I previously considerd combining dynamically-updating firewall rules with DNS filtering (#3641). However, those have disadvantages:

  • They require a filtering DNS server. I am not aware of any, and implementing one is likely non-trivial.
  • They require code to dynamically update firewall rules. The needed hooks already exist, as they are needed by opportunistic IPsec. However, this is additional code that needs to be written.
  • They cannot provide as much protection to the connected VMs. Specifically, the connected VMs still need to resolve DNS.

Additional context
I ran into this problem for months when I was first using QubesOS, and resorted to custom code to work around it.

Relevant documentation you've consulted
https://www.qubes-os.org/docs/firewall

Related, non-duplicate issues
#3641

@DemiMarie DemiMarie added P: default Priority: default. Default priority for new issues, to be replaced given sufficient information. T: enhancement labels May 11, 2019
@andrewdavidwong andrewdavidwong added this to the Release 4.1 milestone May 11, 2019
@maertsen
Copy link

This could also enable wildcard whitelisting of subdomains (e.g. *.domain.tld), which is not currently possible.

@marmarek
Copy link
Member

* Not all programs support HTTP proxies.  Thunderbird and OpenSSH are notable examples.

I don't think those are good examples. Thunderd definitely supports both HTTP proxy and SOCKS. And OpenSSH doesn't support directly either (you can provide ProxyCommand though).
Generally, my experience is significantly more applications support HTTP proxy than SOCKS.
And regarding "tight integration with QubesOS", both approaches requires configuring every single application to actually use that proxy. In case of http(s), there are de facto standard http_proxy and https_proxy environment variables. But it solves only part of the problem.

Otherwise, I agree with all the other points about SOCKS being superior over HTTP.

As for the implementation, I see multiple options:

  1. Run SOCKS over TCP, then use standard firewall to allow only SOCKS. Store filtering rules in a (generated) file on SOCKS server side.
  2. Run SOCKS over qrexec. Store filtering rules in a (generated) file on SOCKS server side.
  3. Run SOCKS over qrexec, with connection parameters in service argument and filtering rules are qrexec policy (requires client side to extract those parameters before making the call and server side to assemble them again)

I think point 3 is most elegant (avoids direct access to the whole IP layer), but also least performant, because qrexec connection setup currently takes about 200ms. We're working on improving it (for example QubesOS/qubes-core-qrexec#6, but your @DemiMarie QubesOS/qubes-core-qrexec#3 is also important step here). But until it's significantly improved, I think those options are blocked.

@DemiMarie
Copy link
Author

What about multiplexing several SOCKS connections over a single qrexec connection? That’s what OpenSSH does (though with SSH instead of qrexec).

@marmarek marmarek modified the milestones: Release 4.1, TBD Jun 1, 2020
@marmarek
Copy link
Member

marmarek commented Jun 1, 2020

@DemiMarie Do you have any recommendation for specific software to use for SOCKS5/HTTP proxy that is also capable of filtering, but also isn't an easy attack target (memory-safe language preferred)?
But also - I see a major usability issue with this approach: application(s) need to be specifically configured to use the proxy. It may work for a carefully crafted own custom configuration, but not so much for a system default that should "just work". For HTTP proxy, many applications respects http(s)_proxy environment variable, but last time I've checked, SOCKS support was very inconsistent between applications (some supports addresses like socks:// in env variable, some expect a different env variable or syntax, and many doesn't support SOCKS at all).

@DemiMarie
Copy link
Author

@marmarek I only know of Squid and tinyproxy (both written in C) and a SOCKS5 proxy written in Nim. This would be best served by a new proxy. SOCKS5 is extremely simple, though, and Go’s standard library provides an HTTP package that should be up to the task.

Writing a SOCKS5 proxy is ~400 lines or less of Rust, so it isn’t that hard.

@tlaurion
Copy link
Contributor

@DemiMarie @marmarek what PRs are associated with the resolution of this issue?

@DemiMarie
Copy link
Author

@tlaurion none so far

@3hhh
Copy link

3hhh commented Apr 27, 2022

This issue is rather identical to #5225, just with a specific proposal on a solution. I still consider DNS pinning to be superior though as it's fully transparent to the application.

@andrewdavidwong
Copy link
Member

This issue is rather identical to #5225, just with a specific proposal on a solution. I still consider DNS pinning to be superior though as it's fully transparent to the application.

@DemiMarie, do you agree that these two issues are duplicates? If so, is there a strong reason to favor one over the other as the one to keep open? (The default is to keep the older issue open, which would be this one.)

@DemiMarie
Copy link
Author

This issue is rather identical to #5225, just with a specific proposal on a solution. I still consider DNS pinning to be superior though as it's fully transparent to the application.

@DemiMarie, do you agree that these two issues are duplicates? If so, is there a strong reason to favor one over the other as the one to keep open? (The default is to keep the older issue open, which would be this one.)

Not really; they are two different approaches and not mutually exclusive. Both have advantages and disadvantages.

@DemiMarie
Copy link
Author

What about dante proxy? It is also available in the debian repo and was quite simple to setup up for domain filtering.

Never heard of it. I have considered writing my own in Go, though.

@andrewdavidwong andrewdavidwong removed this from the Release TBD milestone Aug 13, 2023
@milahu
Copy link

milahu commented Nov 29, 2023

One solution is to use a filtering SOCKS5 proxy instead.

This allows users to whitelist based on domain name, rather than on IP address.

note: this requires clients to use the socks5h protocol
to enforce sending DNS requests over the proxy server = to avoid DNS leaks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: networking P: default Priority: default. Default priority for new issues, to be replaced given sufficient information.
Projects
None yet
Development

No branches or pull requests

8 participants
@maertsen @marmarek @tlaurion @DemiMarie @andrewdavidwong @milahu @3hhh and others