TOR Transparent Proxy
This article will go through the steps necessary to set up a gateway machine that transparently routes traffic through the TOR network. The goal is to have a subnet that will have all TCP traffic routed through TOR which should prevent any leaking of information by the TOR browser (for instance, due to a browser vulnerability).
Prerequisites
You must have a machine that has at least two network interfaces (one for the external network, one for the TOR network). This guide was created against a clean installation of CentOS 7.1 x86_64.
The two networks will have the following configuration:
Description | Interface | Addresses |
---|---|---|
External Network Interface (to internet) | eno16777728 | 10.1.3.39/22 |
Internal Network Interface (to internal TOR subnet) | eno33554952 | 192.168.192.1/24 |
This host will be the gateway for the internal TOR subnet.
Installation
Install the TOR package. You can find the TOR repository at https://deb.torproject.org/torproject.org/.
For CentOS 7, the packages are at https://deb.torproject.org/torproject.org/rpm/el/7/x86_64/.
Install dnsmasq. Optionally, install Apache for your internal website.
Disable SELinux.
Ensure that your network interfaces are set up correctly. Because the internal network does not have a DHCP server, you will need to set it manually:
ip addr add 192.168.192.1/24 dev eno33554952
Configuration
Create the dnsmasq.conf file:
listen-address=192.168.192.1
port=53
strict-order
no-resolv
# Remote DNS server (this should go to TOR's DNS service)
# This is set to 1.1.1.1 which is routed by IPTables to TOR's service.
# DNSMasq does not allow you to set this to an internal IP address.
server=1.1.1.1
interface=eno33554952
address=/torified.wifi/192.168.192.1
dhcp-script=/scripts/dnsmasq_dhcp
dhcp-range=192.168.192.20,192.168.192.250,2h
dhcp-option=1,255.255.255.0
dhcp-option=6,192.168.192.1
dhcp-option=3,192.168.192.1
# This is the external (non TOR) network interface.
no-dhcp-interface=eno16777728
domain=torified.wifi
log-queries
log-dhcp
Enable and start the TOR service.
systemctl enable dnsmasq systemctl start dnsmasq
Create the torrc file containing: (/etc/tor/torrc)
Log notice file /var/log/tor/notices.log
DataDirectory /var/lib/tor
VirtualAddrNetwork 10.192.0.0/10
TransPort 9040
TransListenAddress 192.168.192.1
DNSPort 5353
DNSListenAddress 192.168.192.1
AutomapHostsOnResolve 1
As of this writing (version 0.2.6.10), the TOR package only has the old SystemV startup script and not the systemd service unit file. Create /usr/lib/systemd/system/tor.service containing:
[Unit]
Description = Anonymizing overlay network for TCP
After = syslog.target network.target nss-lookup.target tor-firewall.service
[Service]
Type = simple
User = _tor
ExecStart = /usr/bin/tor --runasdaemon 0 -f /etc/tor/torrc --quiet
ExecReload = /bin/kill -HUP ${MAINPID}
ExecStop = /bin/kill -INT ${MAINPID}
TimeoutSec = 30
Restart = on-failure
LimitNOFILE = 4096
[Install]
WantedBy = multi-user.target
Enable and start the TOR service.
systemctl enable tor.service systemctl start tor.service
Create the firewall configuration script (firewall.sh):
#!/bin/sh
IPT=/usr/sbin/iptables
TOR_UID=998
TOR_NET=192.168.192.0/24
TOR_IF=eno33554952
OUT_IF=eno16777728
ip addr add 192.168.192.1/24 dev $TOR_IF
$IPT -F
$IPT -t nat -F
# Connections cannot be forwarded from one network to another.
$IPT -A FORWARD -i $TOR_IF -j REJECT
# Accept HTTP traffic for web service running on this host.
$IPT -t nat -A PREROUTING -i $TOR_IF -p tcp -d 192.168.192.1 --dport 80 -j ACCEPT
# Accept DNS traffic (handled by dnsmasq which goes to 1.1.1.1)
$IPT -t nat -A PREROUTING -i $TOR_IF -p udp -d 192.168.192.1 --dport 53 -j ACCEPT
# DNSMasq will send DNS queries to 1.1.1.1 which will be routed to the TOR DNS service
$IPT -t nat -A OUTPUT -p udp -d 1.1.1.1 --dport 53 -j DNAT --to-destination 192.168.192.1:5353
# Client chain. Append clients who should have access to this chain.
$IPT -t nat -X tor_clients
$IPT -t nat -N tor_clients
$IPT -t nat -A PREROUTING -i $TOR_IF -j tor_clients
# Allow all clients to connect.
# $IPT -t nat -A tor_clients -i $TOR_IF -p udp --dport 53 -j REDIRECT --to-ports 53
# $IPT -t nat -A tor_clients -i $TOR_IF -p tcp --syn -j REDIRECT --to-ports 9040
# Allow a specific client to connect.
$IPT -t nat -A tor_clients -i $TOR_IF -p udp -s 192.168.192.128 --dport 53 -j REDIRECT --to-ports 53
$IPT -t nat -A tor_clients -i $TOR_IF -p tcp -s 192.168.192.128 --syn -j REDIRECT --to-ports 9040
# Allow the 1.1.1.1 DNS redirection (UDP to the TOR server IP)
# Allow DNS to TOR 5353 service. Allow DNS from this host to the subnet.
$IPT -A OUTPUT -p udp --dport 5353 -j ACCEPT
$IPT -A OUTPUT -p udp -s 192.168.192.1 -d 192.168.192.1/24 -j ACCEPT
# Allow web service
$IPT -A OUTPUT -p tcp --sport 80 -s 192.168.192.1 -d 192.168.192.1/24 -j ACCEPT
# Allow this talking to internal network
$IPT -A OUTPUT -p tcp -s 10.1.3.39 -d 10.1.1.0/22 -j ACCEPT
# Allow TOR
$IPT -A OUTPUT -m owner --uid-owner 0 -j ACCEPT
$IPT -A OUTPUT -m owner --uid-owner $TOR_UID -j ACCEPT
$IPT -A OUTPUT -j LOG --log-prefix "drop: " --log-level 4
$IPT -A OUTPUT -j REJECT
Run the firewall script above to set up IPTables.
The TOR gateway should now be operational.
Create a systemd service unit to execute the firewall script on startup. See Systemd
/usr/lib/systemd/system/tor-firewall.service
[Unit]
Description=TOR Firewall
After=network.target
ConditionFileIsExecutable=/scripts/firewall.sh
[Service]
Type=oneshot
ExecStart=/scripts/firewall.sh
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
[Install]
WantedBy=multi-user.target
Enable the service so that it is triggered on startup.
systemctl enable tor-firewall
Optional Services
You may want to set up a web portal to allow users to register in order to access the TOR network. Install apache and use the script in the wifi page.
You can make DNSMasq execute a script whenever there is a change in the DHCP lease. This is useful to automatically remove hosts from having access to TOR after the lease expires.
#!/bin/sh
if [ $# -ne 3 -a $# -ne 4 ] ; then
echo "Usage: dnsmasq_dhcp <add|del> <mac> <ip> [hostname]"
exit
fi
TOR_IF="eno33554952"
Action=$1
IP=$3
# We want to remove them when they lose their lease...
if [[ "$Action" = "del" ]] || [[ "$Action" = "old" ]] ; then
/sbin/iptables -t nat -D tor_clients -p tcp -s $IP --syn -j REDIRECT --to-ports 9040
/sbin/iptables -t nat -D tor_clients -p udp -s $IP --dport 53 -j REDIRECT --to-ports 5353
fi