How to Route Traffic through a Tor Docker container

Saturday, June 20, 2015

This blog post is going to explain how to route traffic on your host through a Tor Docker container.

It’s actually a lot simplier than you would think. But it involves dealing with some unsavory things such as iptables.

iptables

Run the Image

I have a fork of the tor source code and a branch with a Dockerfile. I have submitted upstream… we will see if they take it. The final result is the image jess/tor, but you can easily build locally from my repo jessfraz/tor.

So let’s run the image:

$ docker run -d \
    --net host \
    --restart always \
    --name tor \
    jess/tor

Easy right? I can already hear the haters, “blah blah blah net host”. Chill out, the point is to route all our traffic duhhhh so we may as well, otherwise would need to change / overwrite some of Docker’s iptables rules, and really who has time for that shit…

You do? Ok make a PR to this blog post.

Routing Traffic

Contain yourselves, I am about to throw down some sick iptables rules.

#!/bin/bash
# Most of this is credited to
# https://trac.torproject.org/projects/tor/wiki/doc/TransparentProxy
# With a few minor edits

# to run iptables commands you need to be root
if [ "$EUID" -ne 0 ]; then
    echo "Please run as root."
    return 1
fi

### set variables
# destinations you don't want routed through Tor
_non_tor="192.168.1.0/24 192.168.0.0/24"

# get the UID that Tor runs as
_tor_uid=$(docker exec -u tor tor id -u)

# Tor's TransPort
_trans_port="9040"
_dns_port="5353"

### set iptables *nat
iptables -t nat -A OUTPUT -m owner --uid-owner $_tor_uid -j RETURN
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports $_dns_port

# allow clearnet access for hosts in $_non_tor
for _clearnet in $_non_tor 127.0.0.0/9 127.128.0.0/10; do
   iptables -t nat -A OUTPUT -d $_clearnet -j RETURN
done

# redirect all other output to Tor's TransPort
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $_trans_port

### set iptables *filter
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# allow clearnet access for hosts in $_non_tor
for _clearnet in $_non_tor 127.0.0.0/8; do
   iptables -A OUTPUT -d $_clearnet -j ACCEPT
done

# allow only Tor output
iptables -A OUTPUT -m owner --uid-owner $_tor_uid -j ACCEPT
iptables -A OUTPUT -j REJECT

Check that we are routing via check.torproject.org.

tor

Woooohoooo! Success.