TorVM for QubesOS

qubes-torvm-archI’ve been using QubesOS (a xen/fedora distribution focused heavily on security by isolation) for a couple weeks now, and I’ve been really enjoying it. There are plenty of rough egdes when it comes to user-friendliess (granted, I’m on a beta release), but I’ve been able to get some pretty cool stuff working. Probably the coolest is having an independent VM which acts as a proxy and transparently makes all my (TCP) traffic go through the TOR network.

Why Qubes?
I’m not going to go into great detail on why I like the premise of Qubes. Joanna’s blog does a good job explaining the concepts and the reasons for investing in security-by-isolation (in addition to security-by-correctness, -by-obscurity, and -by-reactivity). As a person responsible for working with production systems, the fact of the matter is that my personal workstations are a potential vector into the systems I manage. As such, proper care should be taken to ensure that my computer is secure.

Why TOR?
TOR isn’t part of my daily workflow, but occasionally I like to have it. For instance in a coffee shop or at a conference (or any other public WIFI). When I want it, I want to make sure that I’m using it.

TOR + Qubes
Part of the way that isolation in Qubes works is that you have appvms (these are the VMs you actually work or play in), service VMs (dedicated firewall, etc), and netvms (these have the actual WIFI/ethernet hardware, via xen’s PCI passthrough and the like). All you need to do is make a new servicevm, and tell your appvms to use it as their only proxy to the internet. You can see my setup in the diagram above. I also made a new appvm to go with it for occasional usage (“anon-web”). I don’t want to pay the overhead of making all my traffic go through it (by attaching my personal VM to it), but if I were going to a conference for a few days I would probably do that. The benefit of using a servicevm as a proxy is that I don’t have to work about a misconfigured or malicious application in anon-web trying to get around TOR. Anon-web (or any other VM using the TOR proxy) has no way of finding out and leaking my public IP, or getting TCP traffic out to the internet without being TORified.

Putting it together
The Qubes team is working on packages to make a setup like the one I’m describing easy. Since I am particularly interested in how it works under the hood, though, I wanted to do it myself. Thankfully, an old post on Joanna’s blog has plenty to say about the subject. I’ve copied her strategy, and updated a couple bits for use on the latest release.

Install TOR
In order to install software (and have it survive a reboot), you have to do it on the mostly-locked-down templatevm. In my case, that’s called fedora-18-x64. They are working on fedora 20 support now, though, so the middle number in that template name is likely to change.
On the dom0: qvm-run -a fedora-18-x64 teminal.

Now, on the template terminal that just opened, install the necessary software:
sudo yum install tor vidalia

Power off the template VM (shutdown -h now), in order to allow new VMs to see the tor software.

Create TOR proxy
Back on dom0, we’re create the proxy VM and tell it to forward all its network traffic to our firewall:

qvm-create torvm --proxy --label green
qvm-prefs -s torvm netvm firewallvm

Then, start it with qvm-run -a torvm terminal. Most of the disk of an appvm or service vm is wiped every time it is restarted. The few exceptions include /usr/local, /rw, and your home directory. The following script should be written to /usr/local/bin/ (on your torvm):

killall tor
QUBES_IP=$(xenstore-read qubes-ip)

if [ X$QUBES_IP == X ]; then
echo "Error getting QUBES IP!"
echo "Not starting Tor, but setting the traffic redirection anyway to prevent leaks."
/usr/bin/tor \
--SocksPort 0 \
--TransListenAddress $QUBES_IP --TransPort $TOR_TRANS_PORT \
--DNSListenAddress $QUBES_IP --DNSPort 53 \
--RunAsDaemon 1 --ControlPort 9051 \
|| echo "Error starting Tor!"

echo "0" > /proc/sys/net/ipv4/ip_forward
/sbin/iptables -t nat -F
/sbin/iptables -t nat -A PREROUTING -i vif+ -p udp --dport 53 -j DNAT --to-destination $QUBES_IP:53
/sbin/iptables -t nat -A PREROUTING -i vif+ -p tcp -j DNAT --to-destination $QUBES_IP:$TOR_TRANS_PORT
/sbin/iptables -I INPUT 1 -i vif+ -p udp --dport 53 -j ACCEPT
/sbin/iptables -I INPUT 2 -i vif+ -p tcp --dport 9040 -j ACCEPT
/sbin/iptables -F FORWARD

echo "1" > /proc/sys/net/ipv4/ip_forward

Then you can make that script get invoked by adding it to your rc.local file at /rw/config/rc.local, which should look like this:

# Uncomment this if you would like to use a custom torrc file:
#rm -f /rw/config/log
#ln -sf /rw/config/torrc /etc/tor/torrc

chkconfig qubes_netwatcher off
chkconfig qubes_firewall off

In case your networking changes while the torvm is running, you’ll want to reload the TOR service. That can be accomplished by creating this script at /rw/config/qubes_ip_change_hook:


Now, make sure all three are executable:

sudo chmod +x /usr/local/bin/
sudo chmod +x /rw/config/rc.local
sudo chmod +x /rw/config/qubes_ip_change_hook

Shutdown the VM (still on your torvm): shutdown -h now. It will start automatically when an upstream VM needs it.

Create an anonvm to use the TOR proxy
Along the same lines as you did to create the torvm, you can create an upstream VM to use it:

qvm-create anon-web --label black
qvm-prefs -s anon-web netvm torvm

Seeing it in action
If everything worked, you should be able to start firefox (or any other program) in the anon-web VM and get (mandatory) TORification, automatically. Give it a try with this (on the dom0):

qvm-run -a anon-web firefox

You should see (in your Qubes VM Manager) that the torvm starts implicitly. In the anon-web firefox, go to If you’re using TOR, it’ll congratulate you and tell you your exit node’s IP. I’ve found that it sometimes takes a minute for the connection to start up, so if you don’t immediately have internet access, give it a moment before trying again.

What next?
You can easily add more appvms which share this proxy (maybe a dedicated bitcoin VM), or change your personal/banking/work/etc VMs to use this for added security. Another option would be to take the principles discussed here and create a dedicated VM which handles your work VPN. If your VPN requires a shared secret or certificate/key pair, it would be nice to have that on a locked-down machine, separate from your web browser and other applications.

Much thanks to the folks on the Qubes mailing list for their help, and to Joanna for writing the original content. If you found this interesting and you haven’t read her post on it, go do that now.

Published by

Patrick Schless

I'm a (mostly) ruby/rails developer, living in Chicago. I work at Braintree, and I have lots of side-projects.

2 thoughts on “TorVM for QubesOS”

  1. I am shopping for some Christmas pressies. I am considering buying Ivory Elegance Bustier from Peaches and Screams Boutique ! I saw a link to this shop on your site and was wondering whether you have any personal experience with them?

Leave a Reply

Your email address will not be published. Required fields are marked *