Wednesday, August 19, 2009

Dansguardian, Tinyproxy (or squid) and IPTables transparent proxy with multiple users on Fedora Linux.

Update: Fedora now has dansguardian in the updates repository, so there's no longer any need for special download instructions.

I've been working on this system for quite awhile now, and drastically improved it as my own understanding of the parts involved has come along. I intend to update this post as I improve the system even more, and I'm certainly open to suggestions from others. The basic sequence of events by the time we're done will be this:
  • Use firewall (iptables) to grab outbound tcp port 80 (http) traffic, except that belonging to tinyproxy, and redirect it (DNAT) to dansguardian.
  • Use firewall (iptables) to grab the packets again, and rewrite the source address (SNAT) based on the user from whom the packets originated.
  • Dansguardian applies content filtering based on who is looking, and logs everybody.
  • Tinyproxy performs the proxying, going out and fetching the actual pages.
I will try to make this as easy as possible for people not already familiar with 'nix, but at the same time some of this information, or at least the way this is put together, will be new to veterans as well. I have been running this system on Fedora, so my instructions are Fedora-specific, but you can probably do most of it on Ubuntu if you just replace my "yum install" commands with "apt-get install", and other Linux systems should be similar as well. If you are a total newbie, probably the biggest hurdles will be editing text files and switching to root access. To gain root access on your system, open a terminal and run "su -", then provide the root password, which you should have specified at install time. If I remember correctly, in Ubuntu you can just run commands preceded by "sudo" to achieve the same result. Of course sudo is available in any system, but in Fedora it requires configuration. To edit a text file, you really should install vi (yum install vim in Fedora) and run vimtutor to get familiar with vi-improved, but in the meantime you can run gedit /path/to/file, which will open the file in the gnu graphical text editor, very similar to notepad or textedit.

I run this system for some friends who have a couple of kids and a young adult living with them. There is just one computer, a desktop, in the house, and it's running Fedora because I can fix that a lot more easily than Windows. Their router/dsl modem hybrid can't run dd-wrt (http://www.dd-wrt.com/dd-wrtv3/index.php), so I'm stuck configuring all of this on the end-user box. I implemented tinyproxy because squid was thrashing the 1.1Ghz processor and 512M of RAM on the system, but they still needed to allow the adult living with them broader access to the web, so I had to figure out a solution. Here it is.

Install Dansguardian
First let's get the basic system up and running. Install Dansguardian: yum -y install dansguardian. The main configuration file for dg is /etc/dansguardian/dansguardian.conf, but we shouldn't need to change anything there yet. By default it's just listening on localhost (which is fine for a transparent proxy), on port 8080. I do recommend editing bannedextensionlist and bannedmimetypelist under /etc/dansguardian/lists/, as the default configuration won't allow much. Any sites you want to explicitly allow for everyone can be added on separate lines in /etc/dansguardian/lists/exceptionsitelist, while bannedsitelist acts as an explicit deny list for everyone. An entry of "facebook.com" would allow anything under facebook.com, including "apps.facebook.com". chkconfig dansguardian on sets it to automatically start during boot, and /etc/init.d/dansguardian start gets it up and running right now.

Install Tinyproxy (or squid)
Well, first I suppose I should explain why I'm mainly focusing on tinyproxy, but I actually use squid on my own laptop. Dansguardian does require a proxy, and either one will do the trick. Squid actually has a lot more features than tinyproxy (wow, wasn't that hard to figure out), like caching (whoo-hoo performance boost) and at least three types of user authentication not (yet) supported by tinyproxy. Check out http://www.squid-cache.org/ and https://www.banu.com/tinyproxy/ for more info. So, why bother with tinyproxy at all? Well, it's a lot more lightweight, so if you aren't going to experience heavy usage, and don't care so much about caching, it can be a lot nicer to your hardware.

Squid actually wouldn't really require any configuration for basic usage other than simply yum -y install squid, service squid start and chkconfig squid on, although it is VERY configurable in /etc/squid/squid.conf. Since this file contains a heck of a lot of comments and empty lines, I like to run:
sed -e '/^#/d' -e '/^$/d' /etc/squid/squid.conf

to view just the actual non-default configuration. In a default install on RHEL 5.1, this cuts the line count from 4,325 to 35. By default, squid listens only on the loopback interface, using port 3128. This is the default port on which dansguardian will look for it, so this works out nicely.

Tinyproxy can be installed with yum -y install tinyproxy, and turned on with service tinyproxy start and chkconfig tinyproxy on. Since tinyproxy listens on port 8888 by default rather than 3128, you either need to change the port specification in /etc/tinyproxy/tinyproxy.conf to 3128 or the proxy port in /etc/dansguardian/dansguardian.conf to 8888. I changed tinyproxy to 3128. Tinyproxy just listens on the loopback by default, which is fine for now. service tinyproxy restart will apply any changes to the config file, or service dansguardian restart if that's what you changed.

At this point, we should be able to put redirects in place, and dansguardian should work with just one set of configuration (i.e. treating everyone the same).

Redirect Traffic
iptables
is just a user interface to load firewall rules into kernel-space memory for use by the nefilter kernel module. Check out http://netfilter.org/ for more information about these tools. For our purposes, we need to catch and redirect all outbound tcp port 80 (http) traffic to our dansguardian server, except for packets belonging to our proxy server, which we want to let through. Although it'd be weird for this not to already be in place, we'll want to ensure that all loopback traffic is allowed, but we may want to also block all traffic on port 3128, except packets belonging to dansguardian, and all traffic on port 8080 that's not destined for dansguardian, to prevent script kiddies from bypassing the filter. If you're a business, you are probably already blocking most ports anyway.

To make sure our loopback stuff will be accepted, run:
iptables -t filter -I INPUT -i lo -j ACCEPT
To redirect our outbound tcp port 80, run:
iptables -t nat -I OUTPUT -p tcp -m tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8080

To exempt squid from this redirect, run:
iptables -t nat -I OUTPUT -p tcp -m tcp --dport 80 -m owner --uid-owner squid -j ACCEPT
To exempt tinyproxy, run:
iptables -t nat -I OUTPUT -p tcp -m tcp --dport 80 -m owner --uid-owner nobody -j ACCEPT
To block outbound port 3128, run:
iptables -t filter -I OUTPUT -p tcp -m tcp --dport 3128 -j REJECT
To allow dansguardian past this, run:
iptables -t filter -I OUTPUT -p tcp -m tcp --dport 3128 -m owner --uid-owner nobody -j ACCEPT
To block our outbound port 8080, run:
iptables -t filter -I OUTPUT -p tcp -m tcp --dport 8080 -j REJECT
But to allow to dansguardian-destined traffic, run:
iptables -t filter -I OUTPUT -p tcp -m tcp --dport 8080 -d 127.0.0.1 -j ACCEPT
Finally, to save our firewall rules, run:
service iptables save

If you want to act as a gateway, and apply filtering to other systems that route through this one, first add the following line to /etc/sysctl.conf:
net.ipv4.ip_forward = 1
then, run:
sysctl -p
iptables -t nat -I PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8080
iptables -t filter -I FORWARD -j ACCEPT
iptables -t filter -I FORWARD -p tcp -m tcp --dport 8080 -j REJECT
iptables -t filter -I FORWARD -p tcp -m tdp --dport 3128 -j REJECT
service iptables save

All your traffic should now be running through dansguardian! To test this, I recommend using the text-based browser links, which can be installed with yum install links. Try this:
links http://www.google.com
replacing the url appropriately to test. service iptables save writes the file /etc/sysconfig/iptables, which you can edit manually to add/remove/change rules and their order. After editing the file, run service iptables restart to apply the changes. If you want to see a log of packets that match a particular rule, add a duplicate line above the rule, and change everything after "-j" (the target) to "LOG", apply the changes, and run tail -f /var/log/messages.

Enable IP-based Auth
This one was a real kicker for me...If you are using squid, you have plenty of options for determining who's who, and filtering content based on that. However, since tinyproxy doesn't (yet) support authentication, I had to figure out a different method. The documentation I could find suggested either IDENT, with which I was and am unfamiliar, and IP-based Authentication. Obviously IP-based authentication is easy if all you're trying to do is detect from which computer a request came, but I needed it to distinguish between users on a system. I fooled around with IDENT for awhile unsuccessfully before trying to think of a way to use IP-based Authentication.

I tried writing firewall rules to redirect traffic to 127.0.0.2, .3, etc. instead of 127.0.0.1...and dansguardian listened to it, but didn't distinguish...I was about to create a bunch of aliases for eth0 when I remembered dg isn't looking for the IP address of entry into the system, it's looking for the source IP address...enter SNAT! I'd used MASQUERADE before, but never SNAT, so this was a good learning experience for me. Essentially, I added several of the following rules, one for each user, replacing "username" with the user's actual account name, and "X" with a different number for each user. You could support up to 253 separate users this way, I think, although if you used addresses outside of 127.0.0.0/24, which you could, you could support close to 4 billion users:


iptables -t nat -I POSTROUTING -p tcp -m tcp --dport 8080 -m owner --uid-owner username -j SNAT --to 127.0.0.X

Of course once you're done adding your rules, you'll want to service iptables save. Now, nothing has really changed yet from dg's perspective, but we needed this framework in place before we can identify separate users with dg and tp.

Now, we'll set it up in dansguardian. Edit /etc/dansguardian/dansguardian.conf, and uncomment (remove the preceding # from) the line that says "authplugin = '/etc/dansguardian/authplugins/ip.conf'", as well as the one that says "filtergroupslist = '/etc/dansguardian/lists/filtergroupslist'", and change the value of "filtergroups =" to the number of different filtering groups you intend to support. Now edit /etc/dansguardian/lists/filtergroupslist. Follow the instructions of the comments in the file, and pair an IP address to a filtergroup. I ended up using lines like this, with comments to remind me which user is associated with that address, for when I change it sometime:
127.0.0.2 = filter2 #bob

Now, you need to copy the file /etc/dansguardian/dansguardianf1.conf for each of the filter groups you want to use. So, if you set "filtergroups = 5", you could run:
for i in 2 3 4 5; do cp /etc/dansguardian/dansguardianf1.conf /etc/dansguardian/dansguardianf$i.conf; done
Now you can configure each group separately. Some guides that I've read recommend setting group one's "groupmode = 0", which will completely disable access for the group. Since this is the catchall group, anyone not explicitly recognized that placed in another group would be banned. For all groups, you should set "groupname =" to something appropriate and informative. This is especially useful if you want to enable access logging by group, rather than just by user. Well, before I say anything else...now that we have the framework in place, I'll let you look at a site that's much more thorough on the topic of group filtering than I could be: http://contentfilter.futuragts.com/wiki/doku.php?id=filter_groups_configurations

Of course, once all your changes are in place, you'll want to run service dansguardian restart. The nice thing about SNAT is that, until you actually implement IP-based auth in dg, it won't really change anything functionally.

Squid Log Analysis
Coming Soon...

Tinyproxy Log Analysis
Coming Soon...

Dansguardian Log Analysis
Comings Soon...

Installing Webmin and dg-webmin

Coming Soon...

1 comment:

Anonymous said...

I've been looking for quite a while at achieving what you have described here and be. Your pointers are just what I needed to get me going. For example, I've been looking at how to get tinyproxy to do authentication, going round and round, only to finally confirm with your experience, that tinyproxy won't do as is.
I was about to start looking into using squid instead, but I've always thought of it as overkill for a family pc.
I'll keep visiting this page for the latest.
Good luck.
M.