ipfilter on GNU/Linux: Is It Finally Here?

by David Bogen

For the better part of a decade, users of FreeBSD, OpenBSD, NetBSD, Solaris and IRIX have used Darren Reed's ipfilter software to firewall networks and protect individual systems from network-based attacks. Now, with the release of ipfilter 4.1.1, GNU/Linux is moving into the fold as a supported platform.

Although GNU/Linux has had its own built-in packet filtering technologies (iptables and ipchains) for some time, the ability to use ipfilter on GNU/Linux may interest those who administer a large number of heterogeneous systems and want to standardize on one packet filtering technology. Using ipfilter everywhere certainly would be easier than using iptables on GNU/Linux systems, ipfw on FreeBSD, pf on OpenBSD and ipfilter on Solaris.

With years of ipfilter experience in both my personal and professional life, I was eager to get my hands on the latest ipfilter code and see exactly what it could do on GNU/Linux. Unfortunately, that was easier said than done.

The code itself can be retrieved easily from the ipfilter web site. My biggest complaint with ipfilter has been its sometimes sparse documentation and the fact that existing documentation tends to lag behind the most current release. For instance, the INSTALL.Linux file inside the ipfilter tarball contains the following text: Linux is no longer supported. If you can handle the lack of good documentation, however, some interesting times lie ahead.

Because FreeBSD 4.x ships with ipfilter, compiling it from source is not something many FreeBSD users do. If they keep up with the -STABLE source code tree, they get periodic updates to the ipfilter code when they update their operating systems.

Those who want to update to a new release of ipfilter between operating system rebuilds may choose to download and install the source code for ipfilter themselves. The process for doing this usually looks something like this: untar source, cd into source directory, twiddle a few knobs in various files for various reasons, make freebsd4 and make install-bsd. Of course, this is a vastly simplified, high-level overview of the process that makes numerous assumptions about how the software is used, but you get the idea.

Compiling ipfilter on GNU/Linux currently is no easy matter. Mr. Reed compiles and tests ipfilter on Red Hat 9, so you should have better luck testing the software on that platform. I'm a SuSE 8.2 Pro user, so I had a bit of a struggle getting the software to compile and install.

Regardless of the platform you use, you most likely have to modify the top-level Makefile in the ipfilter distribution. The first item to check is the LINUXKERNEL variable. Most likely you need to change that variable to reflect the location of your Linux kernel source code. You also may wish to add -O2 to the end of the CFLAGS line, which adds some optimizations to the code that you'll need if you ever seriously start pumping data through ipfilter. For the purposes of this test, however, I chose not to optimize the code.

While you still are in the Makefile, you can turn on the software's so-called state top capability. State top allows you to view the software's built-in state table in a format much like the GNU/Linux top(1) command. This is a cool feature that allows you to view the state table in a nearly real-time manner. To enable this feature, you need to have ncurses installed. Uncomment the STATETOP_CFLAGS, STATETOP_INC, STATETOP_LIB lines and modify them as appropriate for your system.

Finally, you need to decide if you want the software to default to a pass or block condition on packets fed through it. The software ships with a default of pass. To change this policy to block packets by default, change the POLICY line to:

    POLICY=-DIPF_DEFAULT_PASS=FR_BLOCK

Once you've made your changes to the Makefile, you may need to change two other files. ipfilter is a stateful packet filter. As such, all that state information has to be stored somewhere. ipfilter has a state table to store state information. The maximum size of the state table is set at compile time in the ip_state.h file. The software's default state table is sized appropriately for a home or a small business LAN. To protect more than 20 or 30 hosts with stateful rules, you have to increase the size of the state table to avoid locking the software when the state table fills. If you plan on firewalling hundreds and hundreds of hosts behind an ipfilter firewall, you'll also need to change ip_nat.h to increase the size of the NAT table. Because I was testing ipfilter using a handful of computers, I chose to proceed with the defaults in both files.

The ipfilter build/install process assumes there is a file named ipfboot (or ipfilter, if you use my patches below) in the Linux/ subdirectory. However, that file was not included with the distribution, so I wrote my own. The ipfboot file is simply a chkconfig-compatible shell script that starts and stops the service. You can download my ipfboot file from a link in the Resources section below. If you download my file or create your own, make sure to place it in the Linux/ subdirectory in the untarred source; otherwise, the compilation fails. Finally, I had to patch various source and build files. You can download my patches from a link in the Resources section below.

Once all that is done, you are ready to make the software. Use the following command sequence:

     make linux
     make install-linux

You may notice a warning about not using GNU's version of make. Go ahead and ignore it. If everything has gone as planned, you now should be able to look at your RPM database and find an ipfilter package has been installed.

You've got the software installed, now what? Well, you'll need a set of rules. Most ipfilter rules look something like the following:

pass in quick on eth0 proto tcp from any to 172.19.3.3/32 port = 80 flags S/SA keep state keep frags
block in quick on eth0 proto tcp/udp from any to any port = 137
pass out on eth0 proto tcp/udp from 172.19.3.3/32 to any keep state keep frags
pass out quick on eth0 proto icmp from 172.19.3.3/32 to any keep state keep frags

The rules above are reasonably straightforward. The first line allows inbound TCP traffic to IP address 172.19.3.3, port 80 on Ethernet adapter eth0. It keeps track of the state of the connection (keep state) but only creates a state entry if the correct flags are set on the packet (flags S/SA). We also keep track of fragments (keep frags) from packets that were fragmented due to size on their travels to us. We're now keeping track of the connection state, so when packets travel to or from the end-user/server those packets bypass rules checking if they match the state table's expectations. Packets stop being checked against the waterfall of rules as soon as they match a rule that uses the quick keyword, such as the one above.

The second line blocks inbound TCP/UDP traffic that originates from anywhere and terminates anywhere, port 137. This is useful for protecting Windows systems or simply to prevent a large number of NBT packets from clogging up your logs.

The third line allows outbound TCP/UDP traffic from host 172.19.3.3. Again, state is kept, which means that inbound packets determined to be part of these connections' state bypass the ruleset.

The fourth line allows outgoing ICMP traffic. Some folks forget that ICMP is a different protocol than TCP and UDP and that they need to allow it explicitly out of the firewall if they want to use it.

Obviously, the above ruleset is anything but complete or comprehensive. Several resources on-line (listed in the Resources section below) detail rule construction in much more depth than I'm going to do here. Rather than duplicate their excellent efforts, I'll ask you to consult those resources if you're interested in writing your own ipfilter ruleset.

Using my experience with ipfilter, I decided to make a simple set of rules to take the software out for a little test drive. Unfortunately, mere seconds after loading the ruleset, my system's kernel panicked. That was disappointing. So I tried again, this time from runlevel 3. Another kernel panic.

Some experimentation and a few more reboots revealed that using the keep state functionality of ipfilter guaranteed me a kernel panic. So, I rewrote my small test ruleset to remove all the stateful rules. Now, ipfilter would function simply as a packet filter. That did the trick, as the system was stable once again.

Some tests showed that ipfilter had a small impact on network speed. Using scp to copy a 450+MB file from one host to another showed almost no speed penalty, but it did increase CPU usage somewhat. NFS was not impacted by ipfilter nor were incoming network requests for Web and DNS service.

Now that I had a stable system, I was ready to try out the NAT functionality of ipfilter. I put a system running FreeBSD behind the GNU/Linux/ipfilter firewall system and addressed both properly. Next, I had to write my NAT rules. By convention, most ipfilter NAT rules are kept in /etc/ipnat.conf. My test ruleset looked like this:

map eth0 192.168.1.0/24 -> 172.19.3.3/32 portmap tcp/udp auto
map eth0 192.168.1.0/24 -> 172.19.3.3/32

The map directive is what forces a connection into the NAT pool. In this case, I'm telling ipfilter to rewrite all connections from the 192.168.1.0/24 network so that they appear to be from 172.19.3.3 if the packets are go to out eth0. The portmap TCP/UDP directive tells ipfilter it is okay to rewrite the source port to some ipfilter-chosen value (auto) for TCP and UDP packets. The directive that lacks a portmap option handles all protocols that are not TCP or UDP. Those protocols would include ICMP, GRE and the like.

I have a soft spot in my heart for ipfilter's NAT engine as I've used it to do some non-standard packet rewriting/redirection several times in the past. I was eager to see if I could add GNU/Linux to the platforms on which I could do Things Not Recommended To Be Done With NAT. Once I had my small test ruleset written and the various systems configured and in place, I loaded the NAT ruleset and started running some tests.

Unfortunately, NAT functionality seems to be broken in ipfilter on GNU/Linux. Although the firewall system itself could access various network resources, any requests that traversed the NAT system were ignored by the target servers. For instance, if I ran the following command on the GNU/Linux firewall:

     host www.gnu.org

I got back an IP address for the GNU web server. However, running the exact same command on the system behind the GNU/Linux firewall produced a DNS timeout.

Using tcpdump, packets could be seen leaving the GNU/Linux firewall and reaching the various target servers. However, no response could be seen leaving the target servers or reaching the GNU/Linux firewall. This leads me to believe the NAT functionality of ipfilter on GNU/Linux is mangling packets ever so slightly. The mangled packets then seem to be dropped silently on the floor by the target servers.

So, if you can't use ipfilter's stateful packet engine and you can't use its NAT code, what can you do with it? Well, you can run the software on kernel 2.4.20. Anecdotal evidence suggests that running ipfilter on 2.4.25 produces a platform even less stable than that of 2.4.20. I have not tested the software on the 2.6 kernel, nor has anyone else to my knowledge. However, given the difficulty of running the software on 2.4.20, I wouldn't bet the farm that 2.6 was going to be the answer to0 stability issues.

Right now, the people who should be testing ipfilter on GNU/Linux are those looking for one firewall package that can be deployed across numerous UNIX or UNIX-like platforms. When the software matures a bit more, those folks may choose to move ahead and standardize their firewall software.

For those seeking an Internet-ready firewall on GNU/Linux, you would be best served today by using another software package until ipfilter matures on the platform a bit more. ipfilter's functionality on GNU/Linux is handicapped enough at the moment that I cannot recommend it for production use.

Keep an eye on ipfilter, however. The software is moving ahead constantly and when it matures a bit more on GNU/Linux, it most likely will prove to be a worthy alternative to iptables and other firewalls available for GNU/Linux.

David Bogen has been a systems administrator for eight years. He spends most of his time seeking out incredibly hot and spicy foods with which to torture his digestive tract.

Load Disqus comments