Transparent HTTP/DNS Anonymity, Encryption and Filtering with Tor, Privoxy, Squid, DansGuardian and dnsmasq on ClearOS
Warning: There is a problem with UDP-based DNS query interception and a fix will be posted shortly! See comments for more info.
In this article we will use Tor and Privoxy with dnsmasq and netfilter on ClearOS to transparently encrypt and anonymize web and DNS traffic on an entire private network or a single host without necessarily having to reconfigure any of its constituents. We will also cover daisy-chaining Squid to speed up browsing and DansGuardian to provide content filtering against browser attacks and on-the-fly virus scanning via ClamAV.
For your convenience I have provided a virtual machine image with these modifications at the end of the article.
Introduction: Pros
There are a number of reasons one might choose to use this method over locally installing Tor, which may include:
- Browsers do not require configuration
- Not all software that makes use of HTTP supports using proxies
- Anonymous software updates
- Composition of network to be protected frequently changes (guests with laptops etc.)
- Squid cache "speeds up" slow Tor requests
- Clients may lack technical skill required to properly implement Tor locally and utilize it wisely
- Users with multiple browsers installed can not inadvertently break network policy simply by switching or installing new browsers
- The side-benefits of running behind ClearOS: drop-in IPS, transparent gw-gw VPN with IPSEC, PPTP server etc.
- Centralized content filtering against browser exploits, phishing sites etc.
- On-the-fly anti-virus protection with ClamAV
- Allows packet inspectors like BotHunter to inspect torified traffic for malicious activity
Introduction: Cons
- Traffic sent over Tor tends to be very slow. Reducing the number of hops increases speed but decreases anonymity.
- TLS/SSL still requires browser configuration
- Traffic other than DNS and HTTP on ports 53 and 80 must be configured to use the prox(y/ies).
- Communication between hosts and the gateway is not Tor encrypted, of particular concern on wireless networks.
Introduction: whatis
- ClearOS - A full-featured, easy-to-use turnkey Linux router distribution. It is based on CentOS (RHEL) and provides a simple web-based configuration front-end to help drive its powerful network services. Personal favourites include Intrusion Prevention, bandwidth and QoS management, connection failover and load balancing.
- Tor - Tor provides anonymity for networked applications by routing traffic through encrypted, multi-layered tunnels between nodes operated by Tor supporters.
- Privoxy - From their website: "Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk."
- Squid - A versatile caching proxy. It is available with a webconfig interface for ClearOS users through the default repositories.
- dnsmasq - A multi-talented DHCP, caching-forwarding DNS and TFTP/PXE/BOOTP server that is a default component of ClearOS installations.
- DansGuardian - A content filtering proxy that also gives us the ability to plug in virus scanning with ClamAV.
- ClamAV - An anti-virus solution designed to run on UNIX servers to provide filter-style scanning in applications as diverse as MTAs and PHP uploads.
Introduction: The Objective
By the end of this article we will have a working router, either on dedicated physical hardware or as a virtual machine running on a host. In both scenarios it will be possible to transparently route all HTTP and DNS traffic through Tor from any hosts configured to use the ClearOS box as their gateway. By running a virtual machine on a single host one can effectively put a self-contained firewall appliance between one's self and the upstream network. In fact, this method allows those with more than one NIC installed to eliminate an existing embedded firewall/router appliance and serve an entire private network without significantly altering the host machine's configuration. Protected, portable hotspots can be created with little more than a laptop and a switch or secondary wifi card simply by bridging the virtual machine's internal and external interfaces with the appropriate NICs.
We will be using netfilter and NAT to transparently redirect requests destined for remote servers to proxies running locally on the router:
We will be daisy-chaining a series of proxies together. One may choose to omit one or two depending on available resources and your intent. For the purposes of this article, we will cover configuring all three of the following; if you choose to omit a proxy you must adjust your configuration (including port forwarding for transparency) to reflect this.
- Privoxy - This is the proxy we will be connecting to Tor, it is not optional. Default port tcp/8118.
- Squid - Provides caching. Optional, module is required as a dependency for DansGuardian in ClearOS repos but does not need to be enabled to use it if bypassing the content filter webconfig panel. Default port tcp/3128
- DansGuardian - Content filtering, ClamAV anti-virus module. Both optional. Default port tcp/8080.
Introduction: Prerequisites
You must start this process with a working ClearOS installation. You can use my ClearOS virtual machines for paravirtualized Xen or hardware emulators to set up a test environment. If you will be installing ClearOS on dedicated hardware you may find my personal installation checklist helpful, if a bit dated. For a production environment I recommend going with the Xen paravirtualized image but if your objective is to create a more portable solution the HVM image with VirtualBox is an alright pick.*
* See VirtualBox (Windows) for instructions on converting the raw disk image into a VDI.
Configuration: ClearOS: Networking
How you configure your networking on the ClearOS host will depend on whether you are virtualizing or using real hardware, how many NICs the physical server has and whether you intend to replace your existing gateway. The specifics go beyond the scope of this article but the end result must be the same: hosts on the private network must at least be configured to use the ClearOS installation as their gateway.
It is possible to put the ClearOS box behind an existing NATted router by creating a separate subnet for its LAN side. For example, the existing network is 192.168.0.0/24 and you have a ClearOS VM on your desktop with two virtual network interfaces bound to your one physical interface. You would configure the external interface of the ClearOS VM for 192.168.0.100/24 gw 192.168.0.1 then configure the internal (LAN) interface for 192.168.1.1/24. Next you would configure the hosts (including the machine on which the VM is running if you desire) you will be forcing through Tor to use IPs on the 192.168.1.0/24 subnet with 192.168.1.1 as the gateway. Be wary of offering DHCP from both the existing router and ClearOS.
Configuration: ClearOS: netfilter
We will need to store some iptables rules in such a way that they are loaded on startup. ClearOS provides two ideologically-correct places to do this. If you installed the Firewall - Custom rules module you will have a webconfig interface for manipulating rules stored in /etc/rc.d/rc.firewall.custom. The format of the file is simply
iptables options # descriptive comment
Traditionally, user-defined rules have been stored in /etc/rc.d/rc.firewall.local. This option is available whether or not you have installed the custom rules module and is formatted in much the same fashion, though one may do away with the hash mark and comment.
If you choose to omit one or more of the proxies outlined in this procedure you will have to manually configure netfilter to redirect TCP traffic on port 80 to the listening port of the last proxy in the chain. The "magic rule" looks like this:
iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports {PORT_NUMBER}
Where {PORT_NUMBER} is the intended target. Be mindful of existing rules that may need to be deleted.
Configuration: ClearOS: Installing the Software
ClearOS Modules
Assuming you now have a working ClearOS instance you will need to register with ClearSDN to get software updates and the rest of the modules we need (unless you selected them when doing the initial ClearOS installation).
If you will be using Squid and DansGuardian install the the Web Proxy Module and Content Filtering Module under Clear Center > Modules in the webconfig (if you did not do so during the server installation). Also install Antivirus file scanner module if you wish to use DansGuardian in conjunction with ClamAV to scan HTTP traffic for viruses on the fly.
If you would like to provide users attempting to use HTTPS friendly failure pages telling them how to enable their proxy locally install the Web server module.
Privoxy from RPM
Log into the ClearOS machine via SSH and install privoxy:
# rpm -iv ftp://ftp.muug.mb.ca/mirror/centos/5.5/os/i386/CentOS/privoxy-3.0.3-9.3.el5.i386.rpm
Make privoxy start on boot:
# chkconfig --level 2345 privoxy on
Tor from RPM
Installing Tor from RPM takes care of user account creation and init scripts automagically.
To install Tor you will first need libevent:
# yum install libevent
We will be using the torify command on the router to send our DNS requests over Tor later in the article. You will need to install tsocks or torify will not work:
# rpm -iv ftp://ftp.univie.ac.at/systems/linux/dag/redhat/el5/en/i386/dag/RPMS/tsocks-1.8-7.beta5.2.el5.rf.i386.rpm
Now Tor (adjust for the latest version):
# rpm -iv http://deb.torproject.org/torproject.org/rpm/centos5/tor-0.2.1.29-tor.0.rh5_5.i386.rpm
Make Tor start on boot:
# chkconfig --level 2345 tor on
If you don't like the thought of ClearOS calling home disable suvad - bear in mind this will negatively impact your ability to receive software updates. First, remove your ClearSDN registration information via webconfig by loading this URL:
http://LAN-address:81/admin/register.php?Reset=yes
Next run:
# /etc/init.d/suvad stop # chkconfig --level 2345 suvad off
Bear in mind that even if you decide to leave suvad on the basic ClearSDN subscription includes and automatically configures Clear's dynamic DNS service. One may wish to disable this feature if one does not want systemname.poweredbyclear.com always pointing to your current public IP.
Tor from Source
A while back one had to modify Tor's source to get one-hop circuits running but it seems this recommendation has since been implemented and one-hop circuits can be configured without modification, provided the intended exit node is configured to allow this.
If you still wish to compile Tor from source on ClearOS we must first install its build environment:
# yum groupinstall "Development Tools"
If you have already installed Tor from RPM remove it:
[root@system html]# cp -r /etc/tor/ /etc/tor.bak [root@system html]# cp /etc/init.d/tor /etc/init.d/tor.bak [root@system html]# rpm -e tor tor (pid 2058) running Stopping tor: /usr/bin/torctl stop: tor stopped [ OK ] /var/tmp/rpm-tmp.25797: line 12: fg: no job control warning: /etc/tor/torrc saved as /etc/tor/torrc.rpmsave
Download the latest source tarball from the Tor project's website:
# cd /usr/src # wget https://www.torproject.org/dist/tor-0.2.1.28.tar.gz # tar zxf tor-0.2.1.28.tar.gz # cd tor-0.2.1.28
Before we begin compiling we need to install libevent (if it is not already available) and libevent-devel:
# yum install libevent libevent-devel
Now OpenSSL and OpenSSL-devel:
# yum install openssl openssl-devel
On older software one had to modify src/or/control.c, removing or commenting out the following lines (big ups to sprawl for their article in 2600):
if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) { connection_write_str_to_buf( "551 Can't attach stream to one-hop circuit.\r\n", conn); return 0; }
As we can see this block has been replaced:
/* Is this a single hop circuit? */ if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) { routerinfo_t *r = NULL; char* exit_digest; if (circ->build_state && circ->build_state->chosen_exit && circ->build_state->chosen_exit->identity_digest) { exit_digest = circ->build_state->chosen_exit->identity_digest; r = router_get_by_digest(exit_digest); } /* Do both the client and relay allow one-hop exit circuits? */ if (!r || !r->allow_single_hop_exits || !get_options()->AllowSingleHopCircuits) { connection_write_str_to_buf( "551 Can't attach stream to this one-hop circuit.\r\n", conn); return 0; } ap_conn->chosen_exit_name = tor_strdup(hex_str(exit_digest, DIGEST_LEN)); }
Compile the software and install it:
# ./configure # make # make install
Now we need to make a non-privileged user for Tor to run under.
# useradd -d /var/lib/tor -s /sbin/nologin -r tor
Let's use the init script provided by the RPM, modifications in bold:
#!/bin/sh # # tor The Onion Router # # Startup/shutdown script for tor. This is a wrapper around torctl; # torctl does the actual work in a relatively system-independent, or at least # distribution-independent, way, and this script deals with fitting the # whole thing into the conventions of the particular system at hand. # This particular script is written for Red Hat/Fedora Linux, and may # also work on Mandrake, but not SuSE. # # These next couple of lines "declare" tor for the "chkconfig" program, # originally from SGI, used on Red Hat/Fedora and probably elsewhere. # # chkconfig: 2345 90 10 # description: Onion Router - A low-latency anonymous proxy # # Library functions if [ -f /etc/rc.d/init.d/functions ]; then . /etc/rc.d/init.d/functions elif [ -f /etc/init.d/functions ]; then . /etc/init.d/functions fi # Increase open file descriptors a reasonable amount ulimit -n 8192 TorCTL=/usr/bin/torctl # torctl will use these environment variables TorUSER=tor export TorUSER if [ -x /bin/su ] ; then SUPROG=/bin/su elif [ -x /sbin/su ] ; then SUPROG=/sbin/su elif [ -x /usr/bin/su ] ; then SUPROG=/usr/bin/su elif [ -x /usr/sbin/su ] ; then SUPROG=/usr/sbin/su else SUPROG=/bin/su fi case "$1" in start) action $"Starting tor:" $TorCTL start RETVAL=$? ;; stop) action $"Stopping tor:" $TorCTL stop RETVAL=$? ;; restart) action $"Restarting tor:" $TorCTL restart RETVAL=$? ;; reload) action $"Reloading tor:" $TorCTL reload RETVAL=$? ;; status) $TorCTL status RETVAL=$? ;; *) echo "Usage: $0 (start|stop|restart|reload|status)" RETVAL=1 esac exit $RETVAL
We're going to need the torctl script too, open /usr/bin/torctl and paste (modifications in bold):
#!/bin/sh # # Tor control script designed to allow an easy command line interface # to controlling The Onion Router # # The exit codes returned are: # 0 - operation completed successfully. For "status", tor running. # 1 - For "status", tor not running. # 2 - Command not supported # 3 - Could not be started or reloaded # 4 - Could not be stopped # 5 - # 6 - # 7 - # 8 - # # When multiple arguments are given, only the error from the _last_ # one is reported. # # # |||||||||||||||||||| START CONFIGURATION SECTION |||||||||||||||||||| # -------------------- -------------------- # Name of the executable EXEC=tor # # the path to your binary, including options if necessary TorBIN="/usr/local/bin/$EXEC" # # the path to the configuration file TorCONF="/usr/local/etc/tor/torrc" # # the path to your PID file PIDFILE="/var/run/tor/tor.pid" # # The path to the log file LOGFILE="/var/log/tor/tor.log" # # The path to the datadirectory TorDATA="/var/lib/tor" # TorARGS="--pidfile $PIDFILE --log \"notice file $LOGFILE\" --runasdaemon 1" TorARGS="$TorARGS --datadirectory $TorDATA" # If user name is set in the environment, then use it; # otherwise run as the invoking user (or whatever user the config # file says)... unless the invoking user is root. The idea here is to # let an unprivileged user run tor for her own use using this script, # while still providing for it to be used as a system daemon. if [ "x`id -u`" = "x0" ]; then TorUSER=tor fi if [ "x$TorUSER" != "x" ]; then TorARGS="$TorARGS --user $TorUSER" fi # We no longer wrap the Tor daemon startup in an su when running as # root, because it's too painful to make the use of su portable. # Just let the daemon set the UID and GID. START="$TorBIN -f $TorCONF $TorARGS" # # -------------------- -------------------- # |||||||||||||||||||| END CONFIGURATION SECTION |||||||||||||||||||| ERROR=0 ARGV="$@" if [ "x$ARGV" = "x" ] ; then ARGS="help" fi checkIfRunning ( ) { # check for pidfile PID=unknown if [ -f $PIDFILE ] ; then PID=`/bin/cat $PIDFILE` if [ "x$PID" != "x" ] ; then if kill -0 $PID 2>/dev/null ; then STATUS="$EXEC (pid $PID) running" RUNNING=1 else STATUS="PID file ($PIDFILE) present, but $EXEC ($PID) not running" RUNNING=0 fi else STATUS="$EXEC (pid $PID?) not running" RUNNING=0 fi else STATUS="$EXEC apparently not running (no pid file)" RUNNING=0 fi return } for ARG in $@ $ARGS do checkIfRunning case $ARG in start) if [ $RUNNING -eq 1 ]; then echo "$0 $ARG: $EXEC (pid $PID) already running" continue fi if eval "$START" ; then echo "$0 $ARG: $EXEC started" # Make sure it stayed up! /bin/sleep 1 checkIfRunning if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $EXEC (pid $PID) quit unexpectedly" fi else echo "$0 $ARG: $EXEC could not be started" ERROR=3 fi ;; stop) if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $STATUS" continue fi if kill -15 $PID ; then echo "$0 $ARG: $EXEC stopped" else /bin/sleep 1 if kill -9 $PID ; then echo "$0 $ARG: $EXEC stopped" else echo "$0 $ARG: $EXEC could not be stopped" ERROR=4 fi fi # Make sure it really died! /bin/sleep 1 checkIfRunning if [ $RUNNING -eq 1 ]; then echo "$0 $ARG: $EXEC (pid $PID) unexpectedly still running" ERROR=4 fi ;; restart) $0 stop start ;; reload) if [ $RUNNING -eq 0 ]; then echo "$0 $ARG: $STATUS" continue fi if kill -1 $PID; then /bin/sleep 1 echo "$EXEC (PID $PID) reloaded" else echo "Can't reload $EXEC" ERROR=3 fi ;; status) echo $STATUS if [ $RUNNING -eq 1 ]; then ERROR=0 else ERROR=1 fi ;; log) cat $LOGFILE ;; help) echo "usage: $0 (start|stop|restart|status|help)" /bin/cat <<EOF start - start $EXEC stop - stop $EXEC restart - stop and restart $EXEC if running or start if not running reload - cause the running process to reinitialize itself status - tell whether $EXEC is running or not log - display the contents of the log file help - this text EOF ERROR=0 ;; *) $0 help ERROR=2 ;; esac done exit $ERROR
Now make both scripts executable:
# chmod +x /usr/bin/torctl # chmod +x /etc/init.d/tor
Now copy the sample configuration file:
# cp /usr/local/etc/tor/torrc.sample /usr/local/etc/tor/torrc
Create these directories if they were not created for you:
# mkdir /var/log/tor # mkdir /var/run/tor # mkdir /var/lib/tor # chown tor: /var/log/tor # chown tor: /var/run/tor # chown tor: /var/lib/tor -R # chmod 750 /var/log/tor # chmod 750 /var/run/tor # chmod 750 /var/lib/tor
Add Tor to startup:
# chkconfig --add tor # chkconfig --level 2345 tor add
Configuration: Tor
Tor is configured by default to listen to port 9050 on localhost. If you would like hosts on the private network to be able to have direct access to Tor you must change or add a second SocksListenAddress directive for your router's LAN address (in this case 192.168.1.1) in /etc/tor/torrc.
Enable the control port by uncommenting this line in /etc/tor/torrc:
ControlPort 9051
Run this command, replacing password with the password you would like to use for the controller:
tor --hash-password password
Ignore the warning about running Tor as root; the actual daemon has been configured by its RPM to use a non-privileged account. Ucomment and change the HashedControlPassword to the output you were provided. Start Tor:
# /etc/init.d/tor start
Verify you can log into the controller, replace password with the unencrypted password you gave tor --hash-password:
[root@system log]# telnet localhost 9051 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. authenticate "password" 250 OK
By default Tor builds random 3-hop circuits. You can use the controller to increase performance or anonymity by increasing or decreasing the number of hops your circuits use, and even the geographical distance between hops. I recommend you read Tor Control Protocol for more information.
Quit telnet by holding down control and pressing the ] key. Type quit and hit enter.
It is important that your system time is accurate; you will find it difficult to establish circuits if your clock is skewed. Let's force an NTP update before Tor is started by modifying its init script at /etc/init.d/tor:
start) /usr/sbin/ntpdate -s -b -u 0.gentoo.pool.ntp.org 1.gentoo.pool.ntp.org 2.gentoo.pool.ntp.org 3.gentoo.pool.ntp.org action $"Starting tor:" $TorCTL start RETVAL=$? ;;
Note: choose time servers you trust. You may not be able to start Tor and subsequently torify ntpd if the first update does not go out vanilla. ClearOS uses these time servers:
time1.clearsdn.com time2.clearsdn.com time3.clearsdn.com time4.clearsdn.com
To keep the system time accurate and optionally provide NTP service for your local network activate the NTP daemon:
# chkconfig --level 2345 ntpd on # /etc/init.d/ntpd start
NOTE Xen users experiencing clock skew between the VM and dom0 should add this to Tor's init script before the call to ntpdate (/etc/rc.d/rc.local is run too late):
echo 1 > /proc/sys/xen/independent_wallclock
Configuration: Tor: torify
If you have configured Tor to only listen on your LAN address you must configure tsocks accordingly in /etc/tsocks.conf:
# This is the configuration for libtsocks (transparent socks) # Lines beginning with # and blank lines are ignored # # This sample configuration shows the simplest (and most common) use of # tsocks. This is a basic LAN, this machine can access anything on the # local ethernet (192.168.0.*) but anything else has to use the SOCKS version # 4 server on the firewall. Further details can be found in the man pages, # tsocks(8) and tsocks.conf(5) and a more complex example is presented in # tsocks.conf.complex.example # We can access 192.168.0.* directly local = 192.168.0.0/255.255.255.0 # Otherwise we use the server server = 192.168.0.1
Configure tsocks to connect to your LAN address on every host in the private network where you would like to use torify without the overhead of a local Tor deployment.
Configuration: Privoxy
Privoxy listens for connections on localhost by default. Set the listen-address parameter in /etc/privoxy/config to the LAN address of your router if you would like the ability to manually configure browsers to use it - a good idea if you expect to be using TLS/SSL connections. Configure Privoxy to connect to Tor:
# listen-address 127.0.0.1:8118 listen-address 192.168.1.1:8118 ... forward-socks4a / 127.0.0.1:9050 .
The period at the end is intentional. Start Privoxy:
# /etc/init.d/privoxy start
Configuration: Squid
Log in to the ClearOS webconfig at https://lan-ip:81 and configure Web Proxy under the Gateway menu. Set a suitable cache size and enable transparent mode. Optionally, you may wish to enable the banner and pop-up filter. If you will be using DansGuardian to provide anti-virus protection and content filtering enable the Contant Filter. Make the service start on boot, then start it.
Next we must configure squid to channel its requests through privoxy. Add this to /etc/squid/squid.conf:
cache_peer localhost parent 8118 7 no-query default header_replace User-Agent Mozilla/5.0 (en) Gecko/20070515 Firefox/2.0.0.4 header_access User-Agent deny all header_access From deny all header_access Server deny all header_access WWW-Authenticate deny all header_access Link deny all header_access Cache-Control deny all header_access Proxy-Connection deny all header_access X-Cache deny all header_access X-Cache-Lookup deny all header_access Via deny all header_access Forwarded-For deny all header_access X-Forwarded-For deny all header_access Pragma deny all header_access Keep-Alive deny all header_access Referer deny all # header_access Cookie deny all
Add this line if you are record-conscious would like to disable Squid's cache:
cache deny all
Then update any cache_dir values:
#cache_dir ufs /var/spool/squid 500 16 256 cache_dir null /tmp
Alternatively, one can use tmpfs/shm for the cache_dir. With this method the entire cache tree is stored in RAM; evidence disappears when the machine is shut down rather than being written to potentially recoverable storage media. Not only does this let us reap the benefits of caching in lieu of the low speeds Tor is notorious for, it produces faster cache hits. The down side is that if the router is compromised before it can be shut down the contents of /dev/shm may also be compromised. To use this method you will need enough free RAM to satisfy the cache constraints we configured earlier in proxy server webconfig module. Do not add the cache deny allACL to the configuration script. Instead, configure your cache_dir to reflect:
#cache_dir ufs /var/spool/squid 500 16 256 cache_dir ufs /dev/shm/squid 500 16 256
Now edit /etc/init.d/squid to create the directory on tmpfs with the proper permissions every time squid starts:
start() { automagic mkdir /dev/shm/squid chown squid:squid /dev/shm/squid chmod 750 /dev/shm/squid for adir in $CACHE_SWAP; do
Now restart Squid:
# /etc/init.d/squid restart
Try loading http://whatismyip.com etc. from a host configured to use the ClearOS gateway. If everything worked successfully you should see the IP of a Tor exit node at this stage.
Configuration: DansGuardian
In webconfig click on the Content Filter link under the Gateway menu. Configure it to start on boot then start it manually. You can take advantage of the Blanket Block to enforce a web-based authentication scheme as I outlined in this article: Transparent Proxy for Hot Spot/Public Network Web-Based Authentication on ClearOS. Enable the virus scanner to take advantage of ClamAV.
We will need to remove a rule which this process inserts automatically. Use one of the custom rule files (see Configuration: ClearOS: netfilter) to run:
iptables -t nat -D PREROUTING -s ! 127.0.0.1 -p tcp -m tcp --dport 3128 -j REDIRECT --to-ports 82
Now we must direct DansGuardian to hand off connections to the last proxy in the chain before it; port 3128 for Squid or 8118 for Privoxy. Edit /etc/dansguardian-av/dansguardian.conf:
# Network Settings # # the IP that DansGuardian listens on. If left blank DansGuardian will # listen on all IPs. That would include all NICs, loopback, modem, etc. # Normally you would have your firewall protecting this, but if you want # you can limit it to a certain IP. To bind to multiple interfaces, # specify each IP on an individual filterip line. filterip = # the port that DansGuardian listens to. filterport = 8080 # the ip of the proxy (default is the loopback - i.e. this server) proxyip = 127.0.0.1 # the port DansGuardian connects to proxy on proxyport = 3128 #proxyport = 8118
Configuration: dnsmasq: Torifying dnsmasq
I was pleasantly surprised to find that dnsmasq - ClearOS' default caching DNS and DHCP server - not only worked with torify but continued to bind to localhost and the LAN interface properly. It's as simple as editing this line in /etc/init.d/dnsmasq to show:
start) echo -n $"Starting $prog: " daemon torify $dnsmasq RETVAL=$?
Restart dnsmasq:
# /etc/init.d/dnsmasq restart
Make sure dnsmasq is using the tsocks library:
[root@trollup ~]# lsof | grep tsocks
dnsmasq 31015 nobody mem REG 3,1 63136 12419 /lib/libtsocks.so.1.8
Queries made through dnsmasq via the ClearOS box are now sent out over Tor and results are cached in RAM locally. Make sure the resolv.conf on the gateway starts with 127.0.0.1 but includes additional name servers so that dnsmasq knows where to send its queries.
[root@system ~]# cat /etc/resolv.conf nameserver 127.0.0.1 nameserver 208.94.147.150 nameserver 208.94.147.151
Configuration: dnsmasq: Transparent Query Redirection
Add the following to your firewall configuration:
iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 53 iptables -t nat -A PREROUTING -i eth1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 53
Where eth1 is the ClearOS box's LAN interface.
Configuration: dnsmasq: Verifying Transparency
Delete the rules we just added with iptables:
iptables -t nat -D PREROUTING -i eth1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 53 iptables -t nat -D PREROUTING -i eth1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 53
UNIX
On a *nix host configured to use the ClearOS box as the gateway determine the name servers for any given domain:
karma@bzp ~ $ whois google.ca ... Name servers: ns1.google.com ns2.google.com ns3.google.com ns4.google.com
Query one of them for the domain you chose, in this case google.ca:
karma@bzp ~ $ dig google.ca @ns1.google.com ; < < > > DiG 9.7.1 < < > > google.ca @ns1.google.com ;; global options: +cmd ;; Got answer: ;; -> > HEADER < <- opcode: QUERY, status: NOERROR, id: 64208 ;; flags: qr aa rd; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;google.ca. IN A ;; ANSWER SECTION: google.ca. 300 IN A 74.125.226.80 google.ca. 300 IN A 74.125.226.81 google.ca. 300 IN A 74.125.226.82 google.ca. 300 IN A 74.125.226.84 google.ca. 300 IN A 74.125.226.83 ;; Query time: 68 msec ;; SERVER: 216.239.32.10#53(216.239.32.10) ;; WHEN: Sun Dec 19 20:05:29 2010 ;; MSG SIZE rcvd: 107
Note the presence of the aa flag. This indicates that we are looking at an authoritative answer from DNS servers configured to serve this zone. Now load the rules back in:
iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 53 iptables -t nat -A PREROUTING -i eth1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 53
Try the query again:
karma@bzp ~ $ dig google.ca @ns1.google.com ; < < > > DiG 9.7.1 < < > > google.ca @ns1.google.com ;; global options: +cmd ;; Got answer: ;; -> > HEADER < <- opcode: QUERY, status: NOERROR, id: 48247 ;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
Note how the aa flag has been replaced by ra, indicating a recursive lookup.
Windows
On a windows host configured to use the ClearOS box as the gateway, open the command line and run:
nslookup
Find the DNS server for any given domain name. Set it in nslookup:
> server xxx.xxx.xxx.xxx
Now query the domain name:
> domain-name.com
You should see no trace of "Non-authoritative answer:" in the output. Now, add the rules again:
iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 53 iptables -t nat -A PREROUTING -i eth1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 53
Do not change the DNS server nslookup is configured to query. Run the query again:
> domain-name.com
Immediately before the Name and Address(es) portion of the output you will see "Non-authoritative answer:" which indicates that your requests are being routed through dnsmasq.
Configuration: dnsmasq: Verifying Anonymity
Verifying that your DNS queries are being routed through Tor is somewhat more complicated than with web traffic. You will either need to run packet capture software (see my article on Remote Ethernet Packet Capture with Wireshark and tshark over SSH for ideas; on ClearOS run yum install wireshark to get tshark) or set up a name server that logs queries.
I used BIND because I already had that deployed. You don't need to have a name server on public address space - or even a registered domain to do this. Simply get a working BIND installation on an address which is reachable by the ClearOS box and configure its /etc/resolv.conf to do lookups against it after 127.0.0.1.
Include the following in your named.conf's logging block:
channel request_log { file "/var/log/named/request.log" versions 3 size 5m; severity info; print-time yes; print-severity yes; print-category yes; }; category queries { request_log; };
Now create and set the permissions on request.log:
# touch /var/log/named/request.log # chown named: /var/log/named/request.log # chmod 660 /var/log/named/request.log
Now reload the configuration and enable query logging:
# rndc reload # rndc querylog
Make a request for a unique-looking subdomain of some zone your BIND server is configured to serve so you will be able to pick it out if you are using busy live servers. Otherwise you can:
# tail -f /var/log/named/request.log
to watch requests as they come through. If, according to this log, the request you made does not originate from your address(es) it is safe to assume they are leaving a Tor exit node.
System logs
It may suit one to take the system logs into account. On a traditional production system logging is important but if we're trying to make a disposable, anonymizing virtual machine it may be preferable to leave as few forensic traces as possible. One could disable syslog but some daemons write directly to file and may complain or fail to start if their logfiles are unwritable. We can satisfy everyone by loading a blank /log/ directory tree into tmpfs and deciding whether or not to disable syslog based on one's paranoia and available RAM.
First, we'll need to turn off syslog:
# /etc/init.d/syslog stop
Next, clear out the existing log files.
# yes | rm /var/log/* # yes | rm /var/log/*/*
Create wtmp:
# touch /var/log/wtmp # chown root:utmp /var/log/wtmp # chmod 664 /var/log/wtmp
Add a symbolic link for dansguardian-av:
# ln -s /var/log/dansguardian /var/log/dansguardian-av
Now, move the sanitized directory elsewhere:
# mv /var/log /var/log.tree
Copy the log directory tree to tmpfs:
# cp -ax /var/log.tree /dev/shm/log
Create a symlink from tmpfs:
# ln -s /dev/shm/log /var/log
Now, if you choose, remove syslog from startup:
# chkconfig --level 2345 syslog off
There may be other logging considerations to take care of depending on your situation - such as snort packet logging, which is enabled by default.
We need to copy the new /log/ tree to tmpfs before anything else starts every time the system is booted, so let's create a very crude init script in /etc/init.d/logtree:
#!/bin/bash cp -ax /var/log.tree /dev/shm/log
Now link it into runlevel 3:
# chmod +x /etc/init.d/logtree # ln -s /etc/init.d/logtree /etc/rc.d/rc3.d/S05logtree
If you would like to reduce the risk of having your logs intercepted while the machine is live we can disable logrotate and add these lines to /etc/crontab:
*/05 * * * * root yes | rm /var/log/* */05 * * * * root yes | rm /var/log/*/*
Restart cron:
# /etc/init.d/crond restart
HTTPS
Due to the way TLS is implemented and proxies are designed to handle such requests it is not, to the best of my knowledge, feasible to transparently handle TLS connections. This presents a serious problem if users on your protected network will be signing in to HTTPS-protected sites as they will break anonymity.
One must block traffic to the port:
iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 443 -j DROP
If your client(s) will be using HTTPS they must now configure either privoxy or squid as the proxy in their browser(s). Privoxy will only be available if you chose to bind it to your LAN address, at port 8118. If you are not taking advantage of squid's cache this may provide some performance gain. Otherwise, configure the browser(s) to use port 3128 (Squid) or 8080 (DansGuardian).
Failing Gracefully
Rather than block HTTPS traffic altogether we can redirect TLS requests to a local web server on the ClearOS box that shows a page instructing users to configure their browsers to use one of the available proxies. This costs resources (mostly RAM) but can save your client's calling you for support. You need to have installed the Web server module as outlined in Configuration: ClearOS: Installing the Software.
Log into webconfig at https://lan-ip:81/ . Click the Web Server link in the Server menu. Click the Start and Automatic buttons. Make sure SSL is enabled. Now add this to your firewall configuration:
iptables -t nat -A PREROUTING -i eth1 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 443
You may choose to replace or edit the default page that comes with ClearOS:
# nano /var/www/html/index.html
Edit the blurb to include details on configuring browsers to use one of the proxies you have chosen to end the daisy-chain with. I thought the ClearOS template was so cute I kept it:
... <body> <div id='dialogintro1' class='sb'> <p class='blurb'> Sorry, you can't make TLS/SSL connections without configuring your browser to use this proxy:<br /> <strong>Server</strong>192.168.1.1<br /> <strong>Port</strong>8080 </p> <p align='center'><a href='http://www.clearfoundation.com/'><img src="logo.png" alt="Powered by ClearOS"></a></p> <br> </div> <script type='text/javascript'> dialogbox.render(dialogintro1); </script> </body>
Now when a user behind the ClearOS box attempts to make an SSL connection their browser will complain about an invalid certificate. If they accept it they will be told why SSL isn't working and what to do about it.
Acknowledgements
I was first inspired to do something like this when I read sprawl's Tor Control Protocol article in the Winter 2009-10 Edition of 2600.
These articles helped along the way:
- Squid + Privoxy + Tor for secure, transparent web browsing
- Linux: Setup a transparent proxy with Squid in three easy steps
- Route ClearOS HTTP Proxy Through Tor
A special thank you to the countless developers who have contributed in one way or another to the software involved in this article.
Virtual Machine Image
DOWNLOAD clear-trollup.tar.lzma (342MB) c9a56f4b55084e97b8a54f54aff1f512
This file is a sparse, raw full-disk image which can be used natively by some virtualization platforms (Xen, QEMU) or converted for use by others (VirtualBox, VMware). It is based on the ClearOS 5.2 foxpa.ws HVM Edition.
Note to Windows Users: 7zip (and probably others) has a problem handling sparse tar files. Download the gnuwin32 version of tar for the command line at ??http://gnuwin32.sourceforge.net/packages/gtar.htm
c:\Users\karma\Desktop>"c:\Program Files\GnuWin32\bin\tar.exe" xf clear-trollup.tar
Modified from the original README:
Caveats and considerations: - comes with iftop and tshark - custom snort rules with SIDs beginning with 4000000 - http://foxpa.ws/2010/06/04/bad-snort-rules/ applied - user username is user, password is user (must SU on physical console) - root password is root - user password is user; log in as user then SU to root on PTYs - automatic updates are disabled by default - graphical console disabled - eth0 ext DHCP - eth1 lan 192.168.254.1/24 - admin https://192.168.254.1:81 - grant users shell access in webconfig enabled
The VM uses all of the proxies covered in this article and fails SSL connections gracefully. Unfortunately, this requires that the VM has on the order of 400MB of RAM to work with. Remember to update IP/port binding directives and netfilter to reflect your new configuration should you drop one or more proxies from the chain. On-the-fly virus-scanning is enabled by default and logs are written to tmpfs at /dev/shm/tmfs.
Suvad has been disabled from startup, it must be re-enabled and started before you will be able to register your VM with ClearSDN:
# chkconfig --level 2345 suvad on # /etc/init.d/suvad start
If you encounter issues registering your system try loading this URL in your browser twice:
https://129.168.254.1:81/admin/register.php?Reset=yes
The LDAP system may stall on startup if the VM is unable to resolve DNS queries. Ensure that the external interface is configured correctly (edit /etc/sysconfig/network-scripts/ifcfg-eth0) and /etc/resolv.conf lists working name servers before you start the VM. The VM is configured to acquire a DHCP address for its external interface from your existing router/DHCP server and uses two public name servers by default.
If you are connecting the internal and external interfaces to distinct Layer 2 networks (i.e. using it as an actual gateway) you may wish to remove these lines from /etc/sysctl.conf:
net.ipv4.conf.default.arp_filter=1 net.ipv4.conf.all.arp_filter=1
To mount the partition inside the full disk image use kpartx:
# kpartx -a clear-trollup.hdd
Find the partition's device node in /dev/mapper and mount it:
# mount /dev/mapper/loop1p1 /mnt/rawroot
Once you have unmounted the partition remove the loop device:
# kpartx -d clear-trollup.hdd
kpartx is a part of the miltipath-tools package. On Gentoo run:
# emerge miltipath-tools
Your kernel must support Device Mapper.
After you have configured your VM it is a wise idea to generate new keys for SSH. run:
# rm /etc/ssh/ssh_host_* # /etc/init.d/sshd restart
Virtual Machine Image: Xen Paravirtualized
You will require a PAE or 64-bit compatible hypervisor and dom0 to run this image paravirtualized. The first time the machine is created you must use the -c flag to see the pyGRUB bootloader or mx will complain about an invalid default kernel having been specified. You will have 5 seconds to choose the domU kernel and initrd combo. Once logged into the VM edit /boot/grub/grub.conf to boot the domU configuration by default.
This is the sample configuration that accompanies the image:
# ClearOS 5.2 foxpa.ws TROllup edition Jan 2011 http://foxpa.ws/ name = "clear-trollup" vcpus = 1 memory = 512 vif = [ 'mac=00:16:3e:ff:00:01,bridge=xenbr0', 'mac=00:16:3e:ff:00:02,bridge=xenbr0' ] disk = ['file:/var/xen/clear-trollup/clear-trollup.hdd,hda,w'] bootloader = "/usr/bin/pygrub" root = "/dev/hda1 ro" extra = "xencons=ttyS" # REMEMBER update your /boot/grub/grub.conf to load the domU kernel automatically
Be sure to update the MAC addresses and file paths.
Virtual Machine Image: Hardware Virtualization
The regular (HVM) kernel entry in grub.conf has the divider=10 RHEL-specific kernel command line argument to reduce the default timer frequency from 1000Hz to 100Hz.
HVM users will probably encounter a recurring error message on the main PTY indicating that agetty is re-spawning too fast on /dev/ttyS0. Open /etc/inittab and comment this line:
s0:12345:respawn:/sbin/mingetty ttyS0
Tor's init script may complain when it goes to enable the independent clock feature specific to Xen PV before setting the time with ntpdate. Comment this line in /etc/init.d/tor:
echo 1 > /proc/sys/xen/independent_wallclock
Virtual Machine Image: Hardware Virtualization: VirtualBox (Windows)
On Linux, and with older versions of VB I recall being able to use raw disk images unmodified. It seems that this is no longer the case so before you set up your virtual machine we will have to convert the disk image into a suitable format.
On *nix run:
$ VBoxManage convertfromraw clear-trollup.hdd clear-trollup.vdi --format VDI
On Windows:
C:\Users\karma>cd "c:\Program Files\Oracle\VirtualBox" c:\Program Files\Oracle\VirtualBox>VBoxManage.exe convertfromraw clear-trollup.hdd clear-trollup.vdi --format VDI
Open VirtualBox then click on the New button to start the New VM Wizard.
Give the VM a name, set the OS to Linux and the Version to Red Hat (32 bit).
Click next and specify a reasonable amount of RAM for the VM. With all proxies used, antivirus scanning, HTTPS graceful failure and IDS/IPS the VM will need up to 400MB. Click Next and you will be prompted to locate the disk image.
Click Next then Finish and you will exit the Wizard.
Select the VM and click the Settings button. You may wish to reduce the amount of video memory under the Display tab. Click on the Storage tab. Remove clear-trollup.vdi from the SATA controller, then add it to the IDE controller:
Click on the Network tab. Change the Attached to: drop-down to Bridged Adapter. Select the NIC you will be putting the external interface of the VM on.
Click on the Adapter 2 tab. Enable the adapter and attach it to a Bridged Adapter. If you will be using the VM to protect only the PC it is installed on or other hosts on the same layer 2 network with an existing router you may choose to bridge this interface to the same physical NIC as Adapter 1. If you will be using the VM as your subnet's primary router/firewall Adapter 1 must be connected to the uplink NIC (i.e. plugged into your cable modem) and Adapter 2 should connect to the local layer 2 network (i.e. switch).
Click on the Serial Ports tab and check the Enable Serial Port box to avoid annoying respawning messages due to a Xen-related modification to /etc/inittab. Click OK to exit the settings window and start the virtual machine.
Once init has finished its run change the IP address of the physical adapter you have bridged to Adapter 2 (eth1) to something on the 192.168.254.0/24 subnet:
In your browser navigate to https://192.168.254.1:81 and log in with the username root and password root. Go to IP Settings under the Network menu and update your configuration if necessary (i.e. provide a static IP for eth0). Continue to set a new password, user accounts and so on. Reboot the virtual machine once you have reconfigured it to your specifications.
Load up your web browser and navigate to, say, http://whatismyip.org/. If the IP does not match your public address congratulations, you have successfully configured your VM.
Dedication
This article and VM are dedicated to Bradley Manning, who reminded us all that no matter how creative your OPSEC is mouthing off to some asshat will probably get you nailed.