Using Tor helps take back control of what data one decides to share online. It also helps in avoiding surveillance from the local network (think of someone listening to the public Wi-Fi) or the Internet access provider. But it is easy to make mistakes: Tor Browser, the easiest and most common way to use Tor, is just a web browser. Extra special care is required to make other applications use Tor, and it is easy to forget to change settings, let alone actual attackers.

That's why using Tails is often recommended as everything is preconfigured and it requires traffic to go through Tor by various means. Qubes or Whonix also have interesting properties, but require reinstalling systems and changing habits. Meanwhile, securing the network on an already installed system can help you feel better.

A potential solution to prevent connections from leaking out without going through Tor is simply to prevent all connections from leaving the computer, except the ones going to the Tor network. This can quite easily be implemented by setting up an outgoing firewall.

Using the default settings, a Tor client can potentially connect to any of the 2,000 “Guard” relays. While there are ways to get such a list and turn it into firewall rules, we are going to use an easier solution.

Because the list of Tor relays is public, censors have often used it to prevent people from connecting to the Tor network. The Tor project came up with bridges as a work-around. Bridges are entry nodes in the Tor network. For public bridges, users can only get a few bridge addresses at a time, preventing an adversary from easily blocking them at all once.

When configured to use a set of bridges, Tor will only connect to their addresses. This will make our firewall much shorter.

The instructions that follow should work on Debian Jessie and later versions. Adapting them to other systems should not be too hard either. We assume that Tor Browser is already installed. As we will want other applications to use Tor than just the browser, we also want to install a system-wide instance:

# apt install tor

Next, visit bridges.torproject.org to request a set of bridges:

BridgeDB landing page

You then need to select the type of bridges. Tor standard protocol is easy to identify as such. The Tor project has developed pluggable transports to easily disguise the traffic, but using them is outside the scope for this documentation. So lets stay with the default type of bridges:

BridgeDB bridge type selection

After solving a CAPTCHA, you'll get a list of addresses and fingerprints for a couple of bridges like the following one:

Example bridge list from BridgeDB (blurred to protect the actual bridges

To tell Tor to use these bridges, edit /etc/tor/torrc, and at the end, add something like:

UseBridges 1
Bridge 109.XXX.XXX.XXX:4XXX 2244XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bridge 37.XXX.XXX.XXX:1XXXX 9CF0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Bridge 171.XXX.XXX.XXX:4XXX 7705XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Replace the actual addresses and fingerprints by those you got earlier. Now reload the daemon and make sure that it still connects to the network:

# service tor reload
# tail -f /var/log/tor/log

Tor Browser also needs to be told to use these bridges. Open the “onion menu” close to the location bar, and select Tor Network Settings….

Tor Browser “onion menu”

In there, tick My Internet Service Provider (ISP) blocks connections to the Tor network and paste the list of bridges below Enter custom bridges:

Tor Browser Network Settings

Before we restrict outgoing connections to only use the Tor network, lets configure APT to use Tor as well so we can continue installing and upgrading packages in the future:

# apt install apt-transport-tor

The following command will reconfigure APT to use Tor to access the currently configured package repositories. It basically takes care of replacing every http:// by tor+http://:

# sed -e 's/^[^#]*\(deb\(-src\)\?\W\+\)http/\1tor+http/' -i /etc/apt/sources.list /etc/apt/sources.list.d/*.list

Lets see if it still works:

# apt update

One last thing: sometimes, we still need to bypass our restrictions and access the network directly. Some websites sadly deny access to Tor users, or we might need to login through a captive portal before being able to use a random network. To make it practical, we are going to create a new user account. This will enable us to use the desktop user switching capabilities to start a new browser or sudo for command line applications. In this example, the user is going to be named passthrough:

# adduser passthrough

Make sure to set a proper password!

Now lets configure the firewall. Here we are going to use ferm which makes it fairly easy to do low-level firewall rule in a readable manner:

# apt install ferm

We want the firewall to be started at boot time. Now edit its configuration in /etc/ferm/ferm.conf. At the end, add:

# Let's block everything for both IPv4 and IPv6, except to localhost,
# already established connections and the special 'passthrough' user.
domain (ip ip6) chain OUTPUT {
    policy DROP;
    outerface lo ACCEPT;
    proto icmp ACCEPT;
    mod state state (ESTABLISHED RELATED) ACCEPT;
    mod owner uid-owner "passthrough" ACCEPT;
}

# Now for IPv4, we want to restrict output to configured Tor bridges
domain ip chain OUTPUT {
    # Don't break network autoconfiguration
    mod owner uid-owner 0 proto udp dport bootps ACCEPT;
    # Allow bridges defined in torrc by getting them directly
    # from the configuration file.
    @include "sed -n -e 's/^Bridge \([^ ]* \)\?\([0-9.]*\):\([0-9]*\).*/daddr \2 proto tcp dport \3 ACCEPT;/p' /etc/tor/torrc |";
}

# Let's REJECT everything else so we get notice instead of timeouts
domain (ip ip6) chain OUTPUT REJECT;

Reload the firewall through:

# service ferm reload

Lets do some tests:

# ping check.torproject.org
→ ping: unknown host check.torproject.org
# tor-resolve check.torproject.org
→ 38.229.72.22
# ping 38.229.72.22
→ From 192.168.7.234 icmp_seq=1 Destination Port Unreachable
# curl https://check.torproject.org/
→ curl: (6) Could not resolve host: check.torproject.org
# curl -I https://38.229.72.22/
→ curl: (7) Failed to connect to 38.229.72.22 port 443: Connection refused
# curl --socks5 127.0.0.1:9050 https://check.torproject.org/
→ curl: (6) Could not resolve host: check.torproject.org
# curl --silent --socks5-hostname 127.0.0.1:9050 https://check.torproject.org/ | grep Congratulations
→ Congratulations. This browser is configured to use Tor.
# sudo -u passthrough ping -c 1 check.torproject.org
→ 64 bytes from sergii.torproject.org (38.229.72.22): icmp_seq=1 ttl=54 time=148 ms
# sudo -u passthrough curl --silent https://check.torproject.org/ | grep Sorry
→ Sorry. You are not using Tor.

One last thing to complete the setup: for command line applications like SSH, torsocks does wonders. Just prefix your usual commands by torsocks and they should work:

# apt install torsocks
# torsocks curl --silent https://check.torproject.org/ | grep Congratulations
→ Congratulations. This browser is configured to use Tor.

All set! In case you ever need to turn it all off, just ask ferm to reconfigure the firewall:

# service ferm stop

But don't forget to turn it back on later!

# service ferm start

Ideally, we would have a way to automatically configure a different set of bridges for each network we connect to make it more difficult to trace the computer from network to network. But there's quite some more work to be done on various levels before that can be done in an integrated manner (torshiftchange and tordyguards are promising options). Meanwhile, be aware that you might want to keep a fresh set of bridges handy to configure them after leaving for a trip.

Another downside of the setup currently is that it doesn't allow for network time synchronization. That might make the system fingerprintable by using its clock drift.

To use obfs4 bridges which helps defeating censored networks, you will need two extra steps. First, install the required software:

# apt install obfs4proxy

Then add the following extra line to /etc/tor/torrc:

ClientTransportPlugin obfs2,obfs3,obfs4,scramblesuit exec /usr/bin/obfs4proxy

You can then request obfs4 bridges from BridgeDB. These changes are only required for the system-wide Tor daemon, as Tor Browser comes with obs4proxy preconfigured.

Kudos to Micah for proofreading this article.