Routers as Tor bridges

Rob van der Hoeven
Tue Dec 06 2011

Most of the readers of this blog will probably know the Tor project. One of the problems that Tor has encountered is that all nodes of the Tor network are public. This enabled governments to block all IP addresses of the Tor nodes, preventing anyone behind their firewall to use Tor. To solve this problem the Tor project created a pool of unlisted Tor nodes known as bridges. If a user gets blocked, he/she can ask for the IP address of (only) one of these unlisted Tor nodes and use this node as the entry point to the rest of the Tor network.

The function of a Tor bridge is simple: provide an unlisted IP address that blocked users can use to connect to the rest of the Tor network. You can run a full Tor node at the unlisted address, but you don't have to. Forwarding the traffic from the unlisted address to a public Tor node will provide the same functionality and can be done by a simple router.

How to configure a router to forward Tor traffic?

Forwarding traffic from the internet to your local network is very easy. Every router has a nice UI that can be used to do this. Forwarding traffic from the internet to another IP address in the internet zone is slightly more complicated. This type of forwarding is so uncommon that most (all?) routers simply leave it out of the UI.

The first step you have to take if you want your router to forward Tor traffic is to replace the firmware with less limited free software. I replaced the firmware of my TP-Link router with OpenWrt. With OpenWrt you have access to all the functions of your router.

With full control of your router forwarding Tor traffic is simple. I started a ssh connection to my router and typed the following three commands:

iptables -t nat -i eth0.2 -I PREROUTING -p tcp --dst --dport 443 -j DNAT --to-destination
iptables -t nat -o eth0.2 -I POSTROUTING -p tcp --dst --dport 443 -j SNAT --to-source
iptables -I FORWARD -o eth0.2 -p tcp --dst -j ACCEPT


eth0.2             WAN-interface of the internal router switch    WAN IP address     IP address of the rainbowwarrior Tor node

The first command tells the iptables firewall to translate the WAN IP address to the address of the rainbowwarrior Tor node if the destination port is 443. The second command changes the source address of packets leaving the system into the WAN address. The last command allows traffic with the rainbowwarrior Tor node destination to pass through the system.

That's it. I checked this using a remote system and it seems to work. Double checking with Wireshark showed all traffic was routed through my router-bridge.

Comments: 0

MITM for Tor

Rob van der Hoeven
Fri Sep 23 2011

One of the goals of the FreedomBox project is to give users back their privacy. No more snooping by Google, Facebook, governments etc. In order to give users back their privacy two conditions must be met:

One project that tackles both privacy conditions is the Tor project. Tor stands for The Onion Router. It is a special type of network in which all traffic is encrypted and there is never a direct connection from a user to a website (details are here). Protecting privacy the way Tor does comes at a price, connecting to a website using the Tor network is much slower than a direct connection.

How fast (slow) is Tor? At the Tor metrics portal you can find all kinds of interesting statistics that are updated every day. One statistic I find interesting is the time it takes to download files of different sizes. Although this measurement is a good indication of the speed of the network, it does not measure the user experience. Normal websites download at least 10 files and do so on multiple parallel connections. To give an (extreme) example: contacts 11 different domains using 64 connections, on these connections a total of 145 HTTP requests (wow!) are issued.

I really like the Tor project and I would love to see it improve (especially its speed). One thing that's missing from the project is a way to accurately measure what is going on between Tor and the browser. I believe this information can be quite useful and therefore wrote a special measuring proxy: MITM.

What is MITM?

MITM stands for Monitor In The Middle. It is basically a Socks 5 proxy that is placed between the browser and Tor. The browser connects to MITM, MITM connects to Tor. All communication between the browser and Tor is intercepted and decoded.

MITM decodes both the Socks protocol as the HTTP protocol and collects the following data:

Socks protocol:

Http protocol:

All collected data is converted into a nice report that can be viewed by contacting an internal mini webserver that lives at: http://mitm.proxy.

The report consists of the following sections:

A time graph of all connections. The graph uses SVG so you need a recent browser to display the results.

In the graph you see the following information:

Each bar or circle in the graph has a tool-tip and a link connected to it. If you click on a bar you navigate to the connection information.

Server information:

This section shows the following statistics of the servers that were connected

Connections           8 (still open : 6)
Requests              15
Responses             15
MeanResponseTime      2.025
TotalConnectionTime   there are still open connections

Connection information:

This information can be quite substantial. In the table below you only see the first lines of a request and response. You can use the settings page to change this to all the header lines.

         ID                  435
         Server port         80

000.249  SocksRequestStart
001.291  SocksResponseEnd
001.292  HttpRequestStart    GET / HTTP/1.1
004.293  HttpResponseStart   HTTP/1.1 200 OK
005.332  HttpResponseEnd     20522
005.333  HttpRequestStart    GET /wp-includes/js/l10n.js?ver=20101110 HTTP/1.1
007.318  HttpResponseStart   HTTP/1.1 200 OK
007.318  HttpResponseEnd     221
010.390  HttpRequestStart    GET /wp-content/themes/graphene/images/sprite_h.png HTTP/1.1
012.338  HttpResponseStart   HTTP/1.1 200 OK
012.338  HttpResponseEnd     1378

How to use MITM.

MITM is a Python 2.x program that uses the Twisted event-driven networking framework. You can download MITM by pressing this link. MITM has been tested with OpenSuse 11.3 and Firefox > 4. You need at least Firefox version 4 to see the SVG graphics.

In order to use MITM effectively you need to create and use a special Firefox profile. Use the following steps:

If you named your profile “mitm” you can start using this profile by typing:

firefox -P mitm -no-remote

The first time you start you have to change the configuration of the profile:


Remove all feeds if they are present.

Network configuration.

Edit Preferences:Advanced:Network:Connection-Settings

Choose: Manual proxy configuration, Socks Host Port 9000 Socks v5 Clear the “No proxy for” setting.

Save these settings and open the about:config page. Filter on socks_remote_dns and change this setting to true


On the privacy tab choose: Never remember history

With these settings in place and Tor running you can start To display the results I usually open a second tab and navigate to http://mitm.proxy.

Some extra functions.

MITM does not only monitor all communication but it can also delay Socks connect requests and HTTP requests. This function can be used together with some bandwidth limiting software to simulate a slow TOR connection.

MITM can also take measurements without connecting to Tor. On the settings page there is an option to use an internal Socks5 server.

Limitations and final words.

The HTTP specification(s) are large documents with many sections that are open to interpretation (confusing). This makes it difficult to write an HTTP decoder that's 100% bulletproof. I did not try to handle all possible aspects of the specification. I just wanted something uncomplicated that is correct most of the time. Feel free to contact me if you find a problem.

MITM is my first Python program. I tried to make it as Pythonic as possible. Don't hesitate to contact me if something in the code is less optimal. I like to learn more.

Comments: 0

SSH access from the internet to my FreedomBox

Rob van der Hoeven
Sat Jul 02 2011

On my FreedomBox I want SSH access from the internet for the following reasons:

Using virtual machines complicates the use of SSH. Each virtual machine has its own IP address, and the FreedomBox only has one external IP address. There must be a way to connect this external address to one of the many internal addresses. Fortunately SSH is very flexible and it is possible to do this very elegantly.

Read this first.

This article is one in a series that describes the building of my FreedomBox. Not all information from the previous articles is repeated.

The method.

On my FreedomBox the external IP address is connected to a special virtual machine which I call the internet module. This internet module acts as a gateway to the host system and all the other virtual machines.

[client (A)] --> Internet --> [internet module (IM)] -->  n*[virtual machine (B)]

If you want a SSH connection from client A to a virtual machine B then you need two SSH connections. First you have to make a connection from A to an account on the internet module (IM). From this connection you can make a second connection from IM to B. Making connections this way is not transparent. Machine A does not know it's connected to machine B, machine B does not know it's connected to machine A. Because the machines are not connected directly some SSH commands do not behave normally, or may not work at all.

Fortunately there is an elegant way to let both machines think they have a direct connection. For this you have to use the ProxyCommand statement in the ~/.ssh/config configuration file. With this statement you can specify a shell command that makes the connection to the remote system. The SSH client then uses the resulting stdin/stdout of the command as a channel to the remote SSH server.

For a transparent connection the returned stdin/stdout must be connected to the SSH port of the target server. The tick to get this done involves the following steps. First make a connection to the gateway system. On the gateway system start a program that returns a connection to the target system. Return this connection to the client.

Enough theory, here's the ~/.ssh/config setting I use to connect to my freedomboxblog VM over the internet:

Host freedomboxblog
  ProxyCommand ssh -p 99999 -qax nc -w 1 22

I use ssh to log-in on the guest account of my internet module. Then the netcat program is used to make a connection to the freedomboxblog VM. This connection is returned and used by the SSH client to connect to “host freedomboxblog”.

On the internet module I only allow RSA authentication for the guest account. This is not only the most secure way, but it also prevents the password pop-up. With RSA authentication it is not possible to log-in if you don't have the private key. Unfortunately many people still try to log in by brute force. To prevent these attacks I use a non-standard SSH port (see my firewall article).

The configuration.

Client side:

cd ~/.ssh

Edit the config file, add the following lines:

Host myhost
  ProxyCommand ssh -p 99999 -qax nc -w 1 22

Create RSA authentication keys:


This command creates two keys with your username. The one ending with .pub is needed by the internet module on the FreedomBox.


The internet module.


Install netcat:

apt-get install netcat

Create a guest user:

useradd -m guest
cd /home/guest

Add your public key to the authorized users of this account:

mkdir .ssh
cd .ssh

cat /root/ >> authorized_keys

Edit /etc/ssh/sshd_config so it has the following settings:

PasswordAuthentication no
AllowUsers guest

Restart ssh:

/etc/init.d/ssh restart

Now you can only log-in using the guest account, and only if you have one of the private keys belonging to the public keys in /home/guest/.ssh/authorized_keys.

The next time you try:


you get:

Permission denied (publickey).

So in order to get root access you first have to log-in to the guest account and then use the su command.

Comments: 0

Adding a firewall and NAT to my FreedomBox

Rob van der Hoeven
Thu Jun 09 2011

Something every FreedomBox should have is a firewall combined with NAT functionality. These functions are provided by every router, so why not let the router take care of these functions? There are several reasons against using the router for these functions:

Read this first.

This article is one in a series that describes the building of my FreedomBox. Not all information from the previous articles is repeated.

A short overview of my FreedomBox architecture.

In order to understand the configuration of the firewall you need to have a high level view of the architecture of my FreedomBox. In my architecture I use virtual machines (Linux Containers: LXC) that are all part of the same bridged network br0. All VM's use DHCP to get an IP address. There are two static IP addresses:

This is the address of the br0 interface. (a.k.a. the internal address of my FreedomBox)

This address belongs to a special VM: the internet module. The internet module is a so called bastion host A bastion host is a special hardened system that is placed in the DMZ of the router as a gateway to the internal systems (or programs).

In my architecture I try to run every service that is connected to the internet inside its own VM. Access from the internet to a service inside a VM always passes the internet module first.

Sometimes it is not possible to run a service inside a VM. In that case I use NAT to route incoming requests from the DMZ (IP: to the host system (IP: At the moment OpenVPN is the only service connected to the internet that is running directly on the host.


Installing a firewall/NAT should accomplish the following:

Some small adjustments.

In order to integrate the firewall into my FreedomBox I had to make the following changes to my setup:

For the vendor class identifier I changed my lxc-debian-box script. Click the link for the update. If you have already made some LXC modules you can bring them up to date by adding the following line to the /etc/dhcp/dhclient.conf file inside the container:

send vendor-class-identifier "lxc.module";

The vendor-class-identifier is used by dnsmasq. The file /etc/dnsmasq.conf should be edited as follows:





Restart dnsmasq and all the containers to activate the changes.

Installing Shorewall.

On my FreedomBox I use Shorewall for the firewall/NAT functions. It is a very mature and flexible program. Installing is simple:

apt-get install shorewall

Configuring Shorewall.

Shorewall is well documented so I only give a quick overview before presenting my Shorewall configuration.

Central in the Shorewall configuration is the concept of zones. A zone is one-to-one coupled to a network interface. If it is necessary to have multiple zones within the same network (this is the case with my FreedomBox) you can specify sub-zones. Only traffic between different (sub-)zones is examined by the firewall. Default actions for inter-zone traffic are specified by a policy. Exceptions to the policy are specified by rules.

All Shorewall configuration files are in the directory /etc/shorewall. After installing this directory only has one file (shorewall.conf) in it that does not have to be changed. The actual configuration is in the files:

I have the following configuration:



net     br0           detect        bridge,dhcp
vpn     tap0

On my system there are two network interfaces, br0 is placed in the net zone, this zone represents the internet. For OpenVPN I have a second zone (I will write about my OpenVPN configuration in a next article)


#                                 IN          OUT

fw          firewall
vpn         ipv4
net         ipv4
loc:net     ipv4
vmnet:net   ipv4
imod:vmnet  ipv4

The fw zone is a special firewall zone. Think of “fw” as the system on which Shorewall runs. The net zone is split in tho sub-zones: loc and vmnet. Loc stands for all the systems that are not VM's, those systems are in the vmnet zone. One special VM, the internet module, is placed inside its own imod sub-zone.


#ZONE     HOST(S)                           OPTIONS

imod      br0:
vmnet     br0:     routeback
loc       br0:   routeback

This file has all the sub-zones



net         all      DROP       info
imod        vmnet    ACCEPT
imod        all      REJECT     info
vmnet       net      ACCEPT
vmnet       all      REJECT     info
loc         all      ACCEPT
$FW         all      ACCEPT
vpn         all      ACCEPT


all         all      REJECT     info

The policies are examined from top to bottom and the first match cancels further processing of policies. You can see that no traffic from the net zone to any other zone is allowed by the default policy. The exceptions to the policies are in the rules configuration file.


#                                                           DEST     SOURCE     ORIGINAL     RATE     USER/     MARK
#ACTION        SOURCE      DEST                     PROTO   PORT     PORT(S)    DEST         LIMIT    GROUP


Ping(DROP)     net         all

# enable DHCP and DNS access for zones on the freedombox

ACCEPT         imod        $FW                      udp     67:68
DNS(ACCEPT)    imod        $FW
ACCEPT         vmnet       $FW                      udp     67:68
DNS(ACCEPT)    vmnet       $FW
ACCEPT         loc         $FW                      udp     67:68
DNS(ACCEPT)    loc         $FW

# enable HTTP and SSH access, use a non-standard port for SSH

ACCEPT:info    net         imod                     tcp     http
DNAT:info      net         imod:     tcp     99999

# enable OpenVPN

DNAT:info      net         fw:      udp     1194

The only traffic from the net zone to my FreedomBox is HTTP, SSH and OpenVPN traffic.

It's amazing how many people try a brute-force attack on your SSH port. Even if you clearly indicate that it is only possible to login with RSA. I got very annoyed by the constant flickering of my lan-light so for SSH i'm using a non-standard port (not port 99999 ;-)).


#TYPE                ZONE    GATEWAY      GATEWAY_ZONE
#openvpnserver:1194  net


#                                               DEST      SOURCE

br0            -          source

Running Shorewall

With the configuration in place Shorewall can be started. The Debian packagers have wisely prevented Shorewall to start by default. For this you have to edit /etc/default/shorewall and change the startup configuration option. Shorewall is a very flexible program. This flexibility comes at a price: it is very easy to make a mistake, and mistakes can lock you out. I think it is best to start Shorewall manually. If you make a mistake you can correct the error after restarting the system.

Comments: 0

A WordPress module for my FreedomBox

Rob van der Hoeven
Mon May 02 2011

Until now everything I built was “just infrastructure”. The WordPress module is the first module that uses the infrastructure. Building a WordPress module as the first “real” module had two reasons. First: I need the module to house this blog :-). Second: the configuration and data inside the module is reasonably complex. This makes it ideal to develop and test the data-interface of my FreedomBox architecture. Creating a WordPress module consists of the following steps:

Read this first.

This article is one in a series that describes the building of my FreedomBox. Information from the previous articles like network and software configuration is not repeated.

Create a LXC container to house the module.

cd /var/lib/lxc
mkdir wordpress
/usr/lib/lxc/templates/lxc-debian-box -n wordpress -p /var/lib/lxc/wordpress

Start the container and continue installation.

lxc-start -n wordpress -d

Login (password = root)


Inside the container issue the following commands:


dpkg-reconfigure tzdata
dpkg-reconfigure locales

apt-get update
atp-get upgrade

Choose both a locale and default locale (my system: es_US.UTF-8).

Install MySQL.

apt-get install mysql-server

Install PHP & Co.

apt-get install php5 php5-mysql php-apc

Installation of PHP triggers the installation of Apache2. The php-apc package caches the byte codes of the PHP interpreter. This makes PHP execution much faster.

Install the Exim4 MTA.

WordPress needs a MTA to send notifications to the blog admin/user. I use a version of Exim4 that is probably way too powerful for this simple task.

apt-get install exim4-daemon-heavy

After installation you can use the following command to configure Exim4:

dpkg-reconfigure exim4-config

Most configurations should be “mail send by smarthost”.

Install and configure WordPress.

I found the Debian WordPress configuration a little bit confusing so I decided to install the official version:

apt-get install wget

cd /var/www

tar xfvz latest.tar.gz

Create a WordPress database:

mysql -u root -p 

mysql> CREATE DATABASE wordpress;
mysql> GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'localhost' IDENTIFIED BY 'password';
mysql> exit

Change the password in the line with the privileges statement (do not remove the quotes).

Create and edit a wp-config.php:

cd /var/www/wordpress
cp wp-config-sample.php wp-config.php

Install your favorite text editor and edit wp-config.php. Change the MySQL settings and use the link in the “Authentication Unique Keys and Salts” section to get unique values.

The www-data user needs to be the owner of /var/www/wordpress.

cd /var/www/wordpress
chown -R www-data:www-data *

Remember: every time you edit one of the files in the wordpress directory you have to change the ownership to www-data afterwards.

Configure Apache.

In my FreedomBox every request to Apache comes from the Nginx web-server in the internet module. Therefore Apache thinks that every request comes from the same IP address. This must be corrected otherwise things like logging and surveys won't work as expected. To correct the IP address mod_rpaf must be installed and configured:

apt-get install libapache2-mod-rpaf
cd /etc/apache2/mods-enabled

Edit rpaf.conf. Add the IP address of the internet module ( to RPAFproxy_ips.

Make a symbolic link to mod_rewrite so you can have “pretty urls” in WordPress:

ln -s ../mods-available/rewrite.load

Create a file with the name wordpress inside the directory /etc/apache2/sites-available

The file should contain something like:

<VirtualHost *:80>
    DocumentRoot /var/www/wordpress

    <Directory />
        Options FollowSymLinks
        AllowOverride None

    <Directory /var/www/wordpress>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all

    ErrorLog ${APACHE_LOG_DIR}/error.log
    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.

    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/access.log combined

Change both ServerAdmin and ServerName.

Enable the site by creating a symbolic link in /etc/apache2/sites-enabled and by restarting the Apache web-server.

cd /etc/apache2/sites-enabled
ln -s ../sites-available/wordpress
apache2ctl restart

Configure the internet module to forward requests to the WordPress module.

Logout from the WordPress module and connect to the internet module:


Edit the Nginx configuration in /etc/nginx/nginx.conf. Make it look like:

user  www-data; 
worker_processes  1; 

#error_log  logs/error.log; 
#error_log  logs/error.log  notice; 
#error_log  logs/error.log  info; 
#pid        logs/; 

events { 
    worker_connections  1024; 

http { 
    include       mime.types; 
    default_type  application/octet-stream; 

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ' 
                      '$status $body_bytes_sent "$http_referer" ' 
                      '"$http_user_agent" "$http_x_forwarded_for"'; 

    access_log /var/log/nginx/access.log main; 

    gzip              on; 
    sendfile          on; 
    keepalive_timeout 65; 
    server_names_hash_bucket_size 64; 

    server { 
      # this is a catch-all for requests with none of our hosts 

      listen 80 default; 
      location / { return 403; } 

    server { 

      location / { 
        proxy_set_header Host $host; 
        proxy_set_header X-Forwarded-For $remote_addr; 


Change the server_name setting to the domain name you used inside the WordPress module.

Restart nginx

/etc/init.d/nginx restart

Configure your router.

If you configure your router to forward port 80 to the internet module you can start blogging!

Comments: 0