November 2002 | Get BSD | New to BSD? | Search BSD | Submit News | FAQ | Contact Us | Join Us |
|
A few years ago one of my former teachers here at the university arranged for a big donation of equipment from Microsoft to form a lab. This lab was meant as some sort of zoo for students and staff to play in, with more rights than our faculty system admins would allow for. Courses for Internet programming (web, distributed systems, et cetera) were planned there as well. One of the wishes that this teacher had was that the lab itself should not be firewalled so students could access it worldwide. Obviously, he never understood Internet security.
Over the years, the lab literally became the playing ground of a few students (mostly gone now, some to Redmond), playing Unreal Tournament and loud music. The faculty didn't like this very much and wanted to get control back. So they asked me to take it over. After all, I'm usually wearing UNIX/Linux shirts, so I must know what I'm talking about. I agreed to do it, only to discover a complete mess. A few machines were used for warez, were infected with viruses and other evil things. One of them was even rooted once a few years back (ironically, this was a Linux machine, not paid by Microsoft, that was never hardened and the lab admin's brother put a rootkit on it. After we discovered it, we put FreeBSD on it, kept the root password to ourselves and it has never been hacked since).
So, there's a lab, with 10 Windows XP machines and one FreeBSD machine, totally open on the Internet. There are no back ups (there is a tape drive, but always with the same tape), no unified logins and shared home directories between Windows and UNIX and there is no security. My job: secure it and turn the lab into a place where graduate students can work on their projects and wedge in Linux, Mac OS X and FreeBSD.
The first thing I set my mind to is to set up some sort of firewall, to secure the lab from the evil lurking outside, without restricting the users of the lab too much. A few weeks earlier I had set up my first ipfilter firewall with NATing and everything in just a few hours. Even though I'm pretty well known in the Dutch UNIX community for being a Linux bigot I think that FreeBSD with ipfilter (or OpenBSD with packetfilter) is easier to set up than a Linux firewall. Linux firewall rules are cryptic enchantments compared to the natural flow of ipfilter rules, which makes ipfilter and FreeBSD my number one choice.
As you probably know, ipfilter has support for stateful firewalling and NATing, so my first choice was to just use one external IP address, give all the machines an IP address in a private range (10.0.0.x or so), NAT and filter everything and I'd be done in under an hour. Unfortunately the faculty admins didn't want that. Their reason was that if someone on the Internet was hacked from a machine in our lab and we would have NATed the whole lab, it would be a lot harder to find out from which machine that person was actually hacked. So all machines had to keep the IP addresses they already had.
But how do you set up something like that? Obviously, you cannot use normal NATing. After all, which IP addresses and netmasks are you going to assign to the interfaces in your firewall? The solution is a bridge. A bridge connects two network segments and makes it look like it's one network. So basically you're copying packets from one interface to another. And why not put a filter in between and create a filtering bridge? A filtering bridge makes it possible to filter packets without a change to the network setup, apart from rewiring some cables. Filtering bridges are also referred to as transparent filters.
FreeBSD has good support for making a filtering bridge with ipfw and there are excellent tutorials about it. But, I was already hooked on ipfilter. It turned out that filtering bridging with ipfilter is not officially supported in FreeBSD 4-STABLE (it is standard in 5-CURRENT). There are patches for 4-STABLE and as I feel a bit more comfortable with the stable releases I thought I'd give it a shot.
I installed FreeBSD 4.6 from CD (including kernel sources) on an old PC, downloaded the patches, applied them and compiled a new kernel. I included the following kernel options:
options BRIDGE
options IPFILTER
I stripped out most of the other options. After building the new kernel, I booted it. Upon boot I gave the following sysctl commands (and put them in /etc/sysctl.conf):
sysctl net.link.ether.bridge_cfg=xl0:0,xl1:0
sysctl net.link.ether.bridge_ipf=1
sysctl net.link.ether.bridge=1
Right now I had a functional filtering bridge with ipfilter (set up between interfaces xl0 and xl1), but it wasn't configured to do any filtering yet.
The next thing to do was to set up the ipfilter rules. The first step was to enable ipfilter in /etc/rc.conf:
ipfilter_enable="YES"
I kept the ipfilter rules in /etc/ipf.rules, so this was the only change I had to make.
I connected interface xl0 to the outside world and xl1 to my internal network. My rules had to be very simple: prohibit all access to the workstations from the outside, allow access to a few services from the outside (SSH, HTTP, MS Terminal Server connections), but don't restrict the users inside the lab.
pass in quick on xl0 proto tcp from any to 131.211.83.40 port = 22 flags S keep state
pass in quick on xl0 proto tcp from any to 131.211.83.40 port = 80 flags S keep state
pass in quick on xl1 proto tcp from any to any keep state
pass in quick on xl1 proto udp from any to any keep state
pass in quick on xl1 proto icmp from any to any keep state
block in on xl0 from any to 131.211.83.40
[more hosts go here]
All the traffic from my internal network (connected to xl1) is allowed to go through and sessions are tracked (keep state). All traffic on interface xl0 to the host 131.211.83.40 is blocked, except for a few connections from the outside (SSH and HTTP). I only accept a packet if it has the SYN flag set or is part of a session which was already accepted (keep state).
Nearly everything worked, except that I forgot to take FTP into account. FTP is a pretty evil protocol. FTP (at least the variant called "active") wants to make a connection back from the server to the client on port 20 (ftp-data). With the ruleset above Active FTP is not possible. The following rule had to be added:
pass in quick on xl0 proto tcp from any to 131.211.83.40 port = 20 flags S keep state
With a "normal" NAT setup you can create a proxy for FTP. Because this is not a NAT setup, it's not possible to use these proxies. Right now everything works fine, except for WinAmp (which is not a major problem).
Before you start with filtering bridges with ipfilter, there are a few things to consider:
I got it to work on FreeBSD 4.6, but it might not work on newer versions.
out
keyword didn't work for me.
return-rst option
(which returns a connection
refused rather than a time out) didn't work, nor did the
return-icmp-as-dest
option (both options are described
in 3.6 of the ipfilter HOWTO). I found setting up a filtering bridge with FreeBSD and ipfilter quite easy. Both the operating system and the filtering system have proven to be extremely stable and versatile and a filtering bridge is a good addition to other security measures, or to temporarily plug a security hole fast.
ipfilter filtering bridge patch:
http://www.freebsd.org/~cjc/
FreeBSD filtering bridge article:
http://www.freebsd.org/doc/en/articles/filtering-bridges/
ipfilter HOWTO:
http://www.obfuscation.org/ipf/
The
excellent ipfilter HOWTO. Section 9.2.1 is about filtering bridges.