[0.5 XMR Bounty] Setting up proxyVM to route all VM traffic through http/socks5 proxy

Hello, I’m looking for someone to create a community guide on how to set up a proxyVM. Another VM should be able to set this VM as their network and all traffic in the VM should go through the proxy.

The proxyVM should support http and socks5 proxies with authentication and should not have any leaks.

There is already existing work done by other members of the community on this, which may be useful:

Ideally, any third-party software for this should be picked to have minimum attack surface. It should also work in a minimal-template. If there is a need for a proxy to use for testing, let me know and I can provide one.

I would be happy to pay a 0.5 XMR bounty for anyone able to complete an easy-to-follow guide for this to help other community members including myself to set this up.

As an update for anyone interested in this, the instructions in GitHub - hexstore/qubes-proxy: 集成通用代理工具(sing-box)在Qubes OS | mirror of https://git.sr.ht/~qubes/proxy seem to work after removing the firewall rules and I’m able to route all the traffic of an AppVM through a socks/http proxy with authentication. However, there are traffic leaks occasionally.

This is vague. You should define “leaks”, and the kind of “authentication” you would like to use.

Assuming a scenario where the work vm set its network to the proxyvm and the proxyvm set its network to sys-vpn. If the public IP of the work vm was showing the vpn’s IP rather than the proxy IP, that would be a leak.

By proxy authentication, I am referring to socks5/http proxy user:password authentication.

(Also, apologies for the change in forum account. I forgot to save the credentials to my previous forum account…)

When do you see the leaks?

For .5 XMR someone will most likely do this but can you give more info about leaks? Is it from DNS? WebRTC? Is it just when Socks5 drops, whatever rules are in place don’t activate fast enough so the real IP shows for a moment?

Does the qube you are using eventually lock and prevent leaking or does it just leak once connection breaks?

So you are using something called Sing Box. Is the problem is that when Sing Box turns off, the firewall for the Qube doesn’t automatically lock? You can’t find the value of the connection IP for Sing Box, route it to the firewall values for the Qube as the only outbound connection automatically, and then change the firewall status for Qube back to normal. There are great firewall settings for Qubes themselves but those can only be programmed from dom0 and not inside Qube. Sing Box can either be in Debian or Fedora. So you want settings in Debian or Fedora.

So there’s something in https://github.com/hexstore/qubes-proxy that is allow for leaks?

When do you see the leaks? How long do they last? How are you measuring them? Do you know where in git hub code leak is coming from?

@bountyforqubeshelp2 I can put this together for you. You want to make sure that any software running in clientVM can get traffic out to the internet through and only through a proxyVM. You also want to make sure any DNS requests done by software in clientVM are also tunneled through the socks proxy.

Your local ISP should see only a single (probably encrypted) socks5 connection between you and the socks5 host. The socks5 client running inside of proxyVM should be able to authenticate with a username and password to whatever socks5 proxy provider you are using, is this right?

I was only able to get GitHub - hexstore/qubes-proxy: 集成通用代理工具(sing-box)在Qubes OS | mirror of https://git.sr.ht/~qubes/proxy to work after following the guide and then removing the firewall rules file it created. If I don’t remove that file, no traffic would pass through.

While I managed to hack together something with sing-box, the guide should use something available in the debian/fedora package manager instead (and picked with minimal attack surface) so it can be properly kept up-to-date.

When do you see the leaks? How long do they last? How are you measuring them? Do you know where in git hub code leak is coming from?

In regards to the leaks, while as I mentioned before (that the guide shouldn’t use sing-box), the leaks aren’t from DNS. Rather, I had to remove all the firewall rules that were in the GitHub - hexstore/qubes-proxy: 集成通用代理工具(sing-box)在Qubes OS | mirror of https://git.sr.ht/~qubes/proxy repo to get it to even work, so whenever the proxy disconnected for whatever reason, even for a short time, the original IP would be leaked. I haven’t checked for WebRTC leaks but I imagine that would probably leak as well.

You want to make sure that any software running in clientVM can get traffic out to the internet through and only through a proxyVM. You also want to make sure any DNS requests done by software in clientVM are also tunneled through the socks proxy. Your local ISP should see only a single (probably encrypted) socks5 connection between you and the socks5 host. The socks5 client running inside of proxyVM should be able to authenticate with a username and password to whatever socks5 proxy provider you are using, is this right?

Yup, that’s exactly what I’m looking for. Also, proxyVM should use a minimal template and any software picked should be in the debian/fedora package manager so it can be kept up-to-date and selected for minimal attack surface ideally.

@bountyforqubeshelp2 Is there a specific socks client you prefer? You want only socks5, no other socks protocol?

I was able to use GitHub - hexstore/qubes-proxy: 集成通用代理工具(sing-box)在Qubes OS | mirror of https://git.sr.ht/~qubes/proxy as a basis and removed the firewall script that came with it like someone said in this post but after you do that you have to go into /rw/config/, Then edit qubes-firewall-user-script to include

> # Block forwarding of connections through upstream network device
> # (in case the proxy tunnel breaks)
> iptables -I FORWARD -o eth0 -j DROP
> iptables -I FORWARD -i eth0 -j DROP
> ip6tables -I FORWARD -o eth0 -j DROP
> ip6tables -I FORWARD -i eth0 -j DROP

Lastly you have to put the proxy address in the proxyVM firewall rules

  1. PROXY ADDRESS ANY
    2.PROXY ADDRESS TCP PORT OF PROXY
    3.PROXY ADDRESS UDP PORT OF PROXY
    you will not leak dns, your webrtc will be proxy and so will hostname if it has

addy: 87JZjy4n4W7BwscYtGjzqEWdH8HwSHH4wGRexRVHVkCGcCZxPHstoyw8SAhaYTxsNZD8M8hCeJocXDuXrUAv74rn8tTJpqf

Hey, thank you for your contribution. But as I mentioned earlier:

While I managed to hack together something with sing-box, the guide should use something available in the debian/fedora package manager instead (and picked with minimal attack surface) so it can be properly kept up-to-date.

It should also work in a minimal-template.

If you could make a guide using a proxy client available on debian/fedora repos and step-by-step instructions that work with a minimal template and post it on Community Guides - Qubes OS Forum, I would be happy to pay you the bounty.

@bountyforqubeshelp2 Is there a specific socks client you prefer? You want only socks5, no other socks protocol?

socks5 and http proxies with user:password authentication support should suffice. I’m not too familiar with linux proxy clients with minimal attack surface, but perhaps redsocks?

is this a hard requirement? you mentioned redsocks, but that hasn’t been updated (excl. documentation updates) since the start of 2018, i.e. more than 5 years, and has many open issues and pull requests. i’d argue that something outside standard repos which is in active development would be a better choice.

if, however, redsocks is good enough for you, i could make something work, assuming someone doesn’t beat me to it.

is this a hard requirement? you mentioned redsocks, but that hasn’t been updated (excl. documentation updates) since the start of 2018, i.e. more than 5 years, and has many open issues and pull requests. i’d argue that something outside standard repos which is in active development would be a better choice.

If redsocks isn’t maintained like you mentioned then I don’t think it would be a good idea to use it. Is there another actively maintained socks client you can think of that’s in the debian/fedora repos? I’d imagine for most users who follow the guide (including me), they wouldn’t spend the time tracking updates on a specific project manually.

@bountyforqubeshelp2 It appears that what you requested has already been implemented here http://www.dds6qkxpwdeubwucdiaord2xgbbeyds25rbsgr73tbfpqpt4a6vjwsyd.onion/wiki/ProxyBOX which I stumbled on while surveying what other approaches include I may not have thought of.

The implementation looks good, and any other socks proxy could be swapped out for redbox. The contents of the script ~/firewall on that page can be saved to a script that is called from /rw/config/rc.local.

The lines

$iptables_cmd -P INPUT DROP
$iptables_cmd -P FORWARD DROP
$iptables_cmd -P OUTPUT DROP

followed by explicit whitelisting, and the whitelist entries I’m looking at, cover what you are asking. Other than helping to validate whatever you do try to run, there may not be anything new here for any of us to bring to you.

If I were choosing the socks5 proxy to use I would choose go-shadowsocks2 because it looks well maintained, is written in a language that avoids memory corruption pitfalls, and has encryption for the tunnel. Although whether your socks5 proxy provider can work with the tunnel’s encryption is another question.

i think i might’ve found something that does what you asked and even more, and is in the standard repos and is maintained. i’ll let you know if i get it working as a proxyVM

It appears that what you requested has already been implemented here http://www.dds6qkxpwdeubwucdiaord2xgbbeyds25rbsgr73tbfpqpt4a6vjwsyd.onion/wiki/ProxyBOX which I stumbled on while surveying what other approaches include I may not have thought of.

This looks great. If someone could swap out redsocks for another proxy provider, like go-shadowsocks2 as you mentioned (if it is maintained, in the debian/fedora repos and supports both socks5 and http proxies with user:password authentication) and create a guide on this forum for it (should use a minimal template), that should be enough, and would be happy to pay out the bounty to the user.

Although whether your socks5 proxy provider can work with the tunnel’s encryption is another question.

Wouldn’t every socks5 proxy with user:password authentication work with every socks5 client that supports such authentication?

1. install Fedora minimal template

in dom0:
sudo qubes-dom0-update qubes-template-fedora-38-minimal

2. update template

in dom0, open Qubes Update tool, enable
Enable updates for qubes without known available updates, check fedora-38-minimal and click next

3. clone template

open Qube Manager, find fedora-38-minimal, right-click, choose Clone qube
name it fedora-38-minimal-proxy and hit OK

4. start terminal of new template

in dom0:
qvm-run -u root fedora-38-minimal-proxy xterm

5. install software in template

in template terminal:

dnf install qubes-core-agent-networking iproute clash dnscrypt-proxy
systemctl disable dnscrypt-proxy
poweroff

6. open Create Qubes VM

name: sys-proxy
type: AppVM
template: fedora-38-minimal-proxy
networking: this is for you to decide, perhaps you want to use a VPN qube, default is sys-firewall
tick Launch settings after creation and click OK
tab Advanced, tick Provides network
tab Applications, select XTerm on the left, click > button in the middle
click Apply and OK

7. in dom0 terminal:

qvm-firewall sys-proxy del --rule-no 0
qvm-firewall sys-proxy add drop
qvm-firewall sys-proxy add --before 0 drop proto=icmp
qvm-firewall sys-proxy add --before 0 drop specialtarget=dns
qvm-firewall sys-proxy add --before 0 accept PROXY_IP
qvm-firewall sys-proxy

replace PROXY_IP with your proxy’s IP
last command should show accept → drop DNS → drop ICMP → drop

8. launch sys-proxy terminal

in dom0: qvm-run -u root sys-proxy xterm

9. finish setup

in sys-proxy terminal run:
mkdir -p /rw/proxy/dns /rw/proxy/clash
edit /rw/proxy/dns/dnscrypt-proxy.toml and paste:

listen_addresses = ['127.0.0.1:5353']
max_clients = 250
proxy = 'socks5://127.0.0.1:7891'
timeout = 5000
keepalive = 30
ignore_system_dns = true
netprobe_timeout = 0
cache = true
[static]
  [static.quad9_doh]
    stamp = 'sdns://AgMAAAAAAAAABzkuOS45LjkgKhX11qy258CQGt5Ou8dDsszUiQMrRuFkLwaTaDABJYoSZG5zOS5xdWFkOS5uZXQ6NDQzCi9kbnMtcXVlcnk'
  [static.mullvad_doh]
    stamp = 'sdns://AgcAAAAAAAAAAAAPZG9oLm11bGx2YWQubmV0Ci9kbnMtcXVlcnk'

this is a minimal dnscrypt-proxy configuration that doesn’t rely on online serverlists, but those would work as well because it’s using the socks proxy

edit /rw/proxy/clash/config.yaml and paste:

socks-port: 7891
redir-port: 7892

mode: rule

allow-lan: true
bind-address: '*'

dns:
  enable: false

proxies:
  - name: "socks_proxy"
    type: socks5
    server: PROXY_IP
    port: 1080
    # username: username
    # password: password
  # - name: "http_proxy"
  #   type: http
  #   server: PROXY_IP
  #   port: 80
  #   # username: username
  #   # password: password
  #   # tls: true # https
  #   # skip-cert-verify: true

rules:
  - MATCH,socks_proxy # or http_proxy

replace PROXY_IP and with your proxy’s IP and replace the default port if needed, modify proxy settings as needed

edit /rw/config/rc.local and paste:

sysctl -w net.ipv4.conf.all.route_localnet=1
iptables -I FORWARD -o eth0 -j DROP
iptables -I FORWARD -i eth0 -j DROP
iptables -P OUTPUT DROP
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -d PROXY_IP -j ACCEPT
iptables -t nat -F PR-QBS
iptables -t nat -A PR-QBS -d 10.139.1.1 -p udp --dport 53 -j DNAT --to 127.0.0.1:5353
iptables -t nat -A PR-QBS -d 10.139.1.1 -p tcp --dport 53 -j DNAT --to 127.0.0.1:5353
iptables -t nat -A PR-QBS -d 10.139.1.2 -p udp --dport 53 -j DNAT --to 127.0.0.1:5353
iptables -t nat -A PR-QBS -d 10.139.1.2 -p tcp --dport 53 -j DNAT --to 127.0.0.1:5353
iptables -t nat -A PREROUTING -i vif+ -p udp -j REDIRECT --to-ports 7892
iptables -t nat -A PREROUTING -i vif+ -p tcp -j REDIRECT --to-ports 7892
iptables -I INPUT -i vif+ -p tcp --dport 7892 -j ACCEPT
iptables -I INPUT -i vif+ -p udp --dport 7892 -j ACCEPT
iptables -I INPUT -i vif+ -p tcp --dport 5353 -j ACCEPT
iptables -I INPUT -i vif+ -p udp --dport 5353 -j ACCEPT
clash -d /rw/proxy/clash >/dev/null 2>&1 &
sleep 0.5
dnscrypt-proxy -config /rw/proxy/dns/dnscrypt-proxy.toml >/dev/null 2>&1 &

replace PROXY_IP with your proxy’s IP

download Country.mmdb from here in another VM, move it to sys-proxy’s /rw/proxy/clash directory
it doesn’t actually use it, so you don’t have to keep it up-to-date, but clash refuses to start without it

10. restart sys-proxy, create a new qube with it as its networking qube and test it out!

@bountyforqubeshelp2 try it out and let me know how it works. if it’s good i can post it in Community guides and give you my address

@bountyforqubeshelp2 try it out and let me know how it works. if it’s good i can post it in Community guides and give you my address

Thanks for the guide. Will test it out today and pay out the bounty if all works fine tomorrow, after which you can make a post on Community Guides - Qubes OS Forum

Hmm, I can’t seem to get it to work. The work qube that’s network is set to sys-proxy is unable to curl example.com nor curl 1.1.1.1.

I followed the steps on a regular fedora-38 template. I also removed all the qubes firewall rules. sys-proxy’s network was set to sys-firewall

To try to debug, I commented out:

#clash -d /rw/proxy/clash >/dev/null 2>&1 &
sleep 0.5
#dnscrypt-proxy -config /rw/proxy/dns/dnscrypt-proxy.toml >/dev/null 2>&1 &

reboot, and ran sudo clash -d /rw/proxy/clash and sudo dnscrypt-proxy -config /rw/proxy/dns/dnscrypt-proxy.toml myself to see if there was any error in the output.

It didn’t seem to have any error.

[user@sys-proxy ~]$ sudo clash -d /rw/proxy/clash
INFO[0000] SOCKS proxy listening at: [::]:7891
INFO[0000] Redirect proxy listening at: [::]:7892
[user@sys-proxy ~]$ sudo dnscrypt-proxy -config /rw/proxy/dns/dnscrypt-proxy.toml
[2023-07-15 00:16:01] [NOTICE] dnscrypt-proxy 2.1.1
[2023-07-15 00:16:01] [NOTICE] Now listening to 127.0.0.1:5353 [UDP]
[2023-07-15 00:16:01] [NOTICE] Now listening to 127.0.0.1:5353 [TCP]
[2023-07-15 00:16:01] [NOTICE] Firefox workaround initialized
[2023-07-15 00:16:03] [NOTICE] [quad9_doh] OK (DoH) - rtt: 255ms
[2023-07-15 00:16:05] [NOTICE] [mullvad_doh] OK (DoH) - rtt: 274ms
[2023-07-15 00:16:05] [NOTICE] Sorted latencies:
[2023-07-15 00:16:05] [NOTICE] -   255ms quad9_doh
[2023-07-15 00:16:05] [NOTICE] -   274ms mullvad_doh
[2023-07-15 00:16:05] [NOTICE] Server with the lowest initial latency: quad9_doh (rtt: 255ms)
[2023-07-15 00:16:05] [NOTICE] dnscrypt-proxy is ready - live servers: 2

However, unfortunately neither sys-proxy nor the work vm was able to curl example.com or 1.1.1.1

Will PM you shortly the contents of /rw/config/rc.local file, /rw/proxy/clash/config.yaml and /rw/dns/dnscrypt-proxy.toml including the socks5 proxy I tested with.

2 Likes