Links: { Chris Lowth's Home Page | LinWiz | TCP/IP Connection Cutter | Protector }

Adding IPTables "Patch-o-matic" modules to Linux 2.4 Kernels

Introduction

The Linux operating system supports stateful packet filtering using “IPTables”. This software allows the kernel to inspect IP packets as they are received, sent or forwarded and make choices about what to do with them. The base installation of IPTables commonly deployed by distributions such as RedHat includes all the features that are considered to be “stable” by the developers, but there is a wealth of less-tested but feature-rich add-ons that are available as patches to the system. These patches introduce interesting possibilities such as searching for known strings in packets, taking the time of day into account in the rules, handling GRE and H232 protocols intelligently, and much more.

This document describes the adding of the "string match" module to IPTables by way of a worked example. The technique will also work for other IPTables "patch-o-matic" modules.

Platform and software versions

This note describes how to upgrade a RedHat Linux 8.0 system to add iptables string matching. The logic described here will also work for other RedHat distributions in the 7.x and 9 version lines and the new "Fedora". It is likely to work on other RPM-based Linux distributions as well. Please post a note into the “open discussion” forum for the p2pwall project with news of any successes or failures with other distributions.

The software versions I used in this procedure were as follows..

Software
Version
RedHat distribution
8.0
Linux kernel
2.4.20-13-8
iptables package
1.2.8
patch-o-matic software
20030107

Warnings

Before we proceed, I should pass a few warnings on.

  • Iptables "extras" like the string match module is not considered “stable” enough by the IPTables development team to be included in the main body of their software or production Linux kernels. For some modules, this is simply a matter of lack of testing, but others have known bugs. Remember that bugs in the kernel can result in system crashes. My own experience has been very good with "string" but no one is making any guarantees about it. The IPTables distribution describes such patches as “maybe-broken, maybe-cool third-party extensions”.

  • The same “disclaimer” applies to this document and the procedure it describes - Whilst I am describing the process I went through to install  the IPTables "string" addon into my own systems, you must understand that I am not making you any promises – you are welcome to follow this procedure but if it goes wrong for you; I accept no responsibility for the problem or any damage it may cause. I'm sorry about this, but it would be unreasonable for me to take any other stance since I am not the author of the software being discussed and cannot vouch for it's quality.

  • Lastly – backup first. Make sure that you can go back to a working system if the changes you make fail. This is particularly important when considering changes to the kernel of the operating system (which we are).

If none of this has put you off, then read on...

Step zero : Check that changes are actually needed

Before proceeding to add the "string match" module to the linux kernel, it would be worth checking that this hasnt already been done (hey: you never know!). Try running the command..

% insmod ipt_string

And verify that the command doesnt display an error message to the effect that the module cant be found. It may display a message about the fact that the module does not have a GPL license - but you can ignore this for our purposes.

Step 1 : Get up to date.

Before attempting to add a new IPTables module to the kernel, it is well worth ensuring that your kernel and sources are as up to date as possible. The reason I suggest this is that I had no end of problems trying to work on an older kernel, and with an older iptables release. It all started to fly properly when I obtained and installed the “latest” software.

My system is a RedHat 8.0 machine with an internet connection, so I used the “up2date” program to bring me up to speed.

First run “up2date -u” to apply all the patches that are available for your system.

If your Linux kernel is a "standard" one (ie: you havent already built yourself a custom one), check the output of the command to see whether any “kernel” packages needed updating, but we explicitly omitted. Then run a second “up2date” command with the names of those packages given on the command line, along with the option “-f”. Something like this:

% up2date -u kernel -f

You can, of course, upgrade the kernel by installing the new RPM by hand – but be careful to retain the previous working kernel so that you can revert to it should things go wrong later.

Step 2 : Install the kernel sources

If you already have the kernel sources installed, make sure that they were also updated in the previous step. If the kernel sources are not installed on your machine, you should install them now. To discover whether they are present, run the command..

% rpm -qi kernel-source

If this gives a few lines of information, then check that the release number machines the updated kernel. If the utility says something like “package kernel-source is not installed”, then you should install it. One way is to use “up2date” again (if your machine has internet access)..

% up2date -i kernel-source -f

This is probably the best way to do the install because it means that you get the latest version. If, however you are concerned about download times, then you'll need to find an alternative supply for the “kernel-source” rpm file.

Step 3 : Prove that kernel building works

It is generally a good idea to err on the side of caution when dealing with kernel changes, to ensure that problems later are minimised. Following this philosophy, I suggest that you attempt to build a “standard” kernel to match your system before we take the step of applying patches to it. This is what you need to do..

  • “cd” to /usr/src/linux-2.4

  • Run “make distclean

  • Edit the “Makefile” file and add the word “custom” to the EXTRAVERSION parameter near the top of the file. If you are working on a RedHat system, then you will probably find that this is already there – but check for it anyway. If you are already running a custom kernel, then change the word “custom” to something else (you choose) so that the current kernel and the new one can be differentiated from each other. This is very important.

  • Now you need to find the kernel configuration file for your existing system. On RedHat, this may well be saved in the /boot directory under a name like “config-2.4.20-13.8”. If you cant find this file, then list (“ls”) the contents of the “configs” directory and identify the file that matches your system. The names of the files give you all the detail you need. Compare them with the output of the command “uname -a” if you are uncertain.

  • If you find the required file, then copy (“cp”) the identified file to /usr/src/linux-2.4/.config. If you cant find the right file then skip this step, and go through the configuration in detail when you run “make menuconfig” in the next step to verify that all the settings are correct.

  • Run “make menuconfig”. If you have located the right “.config” file in the previous step then just select the “Exit” option and “Yes” to the question “Do you wish to save you new kenel configuration” (note: this step is not strictly required, but I have found it sometimes helps to keep the wheels oiled and running well). If you did not locate the config file used to build your current kernel, then review the configuration settings shown by “make menuconfig” and ensure that they are right for your system.

  • Run “make dep bzImage modules 2>&1 | tee make.out”. This command builds the kernel and modules and saves the messages generated by the process in the file “make.out”. This can take quite a long time – so go and mow the lawn or watch you favourite film on TV. When the “make” has finished, check the end of the make.out file for errors that would indicate that the build failed. If errors are reported, then correct them and retry ( !!! ).

  • Run “make modules_install” and “make install”. These commands load the modules and the main kernel binaries into the right places in the file system and even adjusts the “grub.conf” or (I think) the lilo.conf files to point to the correct kernel.

  • Check the /etc/lilo.conf or /etc/grub.conf file for sensible contents, and make very sure that there is still the possibility of running from the previous kernel version (just in case things haven't worked properly). Then reboot and select the new “custom” kernel when the boot loader menu is displayed.

The system should now “come up” running the kernel you have just compiled. If it does, then we are in the happy situation of have a working kernel compilation system and we can continue on to the more challenging task of adding some iptables treasures to it.

Check that you really are running the new kernel by typing “uname -a” and checking that the word you added to the EXTRAVERSION string appears in the output.

Step 4 : Obtain the up-to-date IPTables sources.

I work with RPM packages when ever possible – this makes repeating any changes made much easier next time round, and allows easy changes of version, even reverting to earlier (working) releases if required.

So, in order to get an updated and patched iptables release onto the system, my suggestion is that we do it using the RPM mechanisms, and aim to build a new RPM with our changes embedded into it. This is the approach that the next sections take you through.

With a little downloading overhead accepted, the easiest way to do this is to get hold of the source RPM (SRPM) for IPTables that comes with the distribution, and modify it to include the updates and patches. So, we need the following..

  • iptables “SRPM” file.
    Downloaded from the distribution provider (RedHat, in my case), from the distribution CD, RedHat's web site or one of it's mirrors. Make sure to check the “updates” section first and only take the SRPM from the “original release” ftp directories if there is nothing more recent available in the updates. Since we ran “up2date” at the start of this procedure, a check on the installed iptables release using “rpm -qi iptables” will tell you what source RPM file to look for.

  • The tarball of the most recent iptables sources.
    This can be downloaded from the netfilter ftp site at ftp://ftp.netfilter.org/pub/iptables.. At the time of writing this note, the most recent source was version 1.2.8, so I downloaded the file iptables-1.2.8.tar.bz2.

  • The tarball of the most recent patch-o-matic sources.
    These files are also available from the netfilter site, at ftp://ftp.netfilter.org/pub/patch-o-matic. Once again; take the most recent version without delving into the “snapshot” directory. I downloaded patch-o-matic-20030107.tar.bz2.

Step 5 : Update the iptables RPM sources

The plan now is to use the standard iptables RPM delivered with your distribution and edit it to generate a new one, with all the additional features we need included. We are going to add new modules to iptables and generate a couple of extra packages as well. The new RPM packages we are going to add are..

  • iptables-pom : The patch-o-matic sources.
  • iptables-devel : the libipq library for writing programs to interact with netfilter's QUEUE target (like the Kazaa-blocking 'ftwall').

In an ideal world, this should be rather less work that it actually is – but I found on my RedHat 8.0 system that the “latest” kernel and “latest” iptables supplied by default are incompatible with each other if you want to rebuild with extra features. So, I had to roll my own. Here's how..

First, install the distribution's iptables source RPM using the following command (change the version number as required).

% rpm -ihv iptables-1.2.6a-1.src.rpm

This places a number of files in /usr/src/redhat (or equivalent).

Then, copy the new iptables and patch-o-matic tarballs into the /usr/src/redhat/SOURCES directory (or equivalent).

Then, modify the iptables.spec file in /usr/src/redhat/SPECS. There are a number of changes to be made, as follows..

  • Change the package version codes and summary texts.
  • Add package descriptions for iptables-devel – to include the library, header files and man pages for libipq.
  • Add package descriptions for iptables-pom – to include the patch-o-matic files, which will be installed under /usr/src/patch-o-matic.
  • Change the “Requires: kernel >=” to give the version number of the kernel you are now using.
  • Remove references to newly-redundant patches.
  • Add a dated comment to the top of the %changelog section to describe the fact that you have updated the versions.
  • Change the first “make” command in the %build section to include the parameter “KERNEL_DIR=/usr/src/linux-2.4” at the end of the line

Dont proceed to build the RPMs yet - we'll do this later.

You may find the easiest thing is just to download my pre-prepared copy and compare with the original (from here). You may still need to change a couple of version numbers in the file, but otherwise it will probably work.

Step 6 : Patch the kernel sources

The next step is to use "patch-o-matic" to apply the "string match" module to the kernel sources.

  • Type the following commands (adjusting version numbers as required) ..
    % cd /usr/src/redhat/SOURCE
    % tar xvfj patch-o-matic-20030107.tar.bz2
    % cd patch-o-matic-20030107
    % KERNEL_DIR=/usr/src/linux-2.4 sh runme extra/string.patch

  • You are now running the iptables kernel patcher utility. Answer the questions it asks, and verify that the patch applies correctly.

Step 7 : Build and install the new iptables RPMs

  • When the question and answer session is complete, go back to the SPECS directory and build the RPMs. The commands to use are..
    % cd ../../../SPECS
    % rpmbuild -ba iptables.spec

This creates RPMs in /usr/src/redhat/RPMS and source RPMS in /usr/src/redhat/SRPMS.

To aid understanding a little: note the order of the last couple of steps here. We are building the iptables packages after patching the kernel because the iptables build process looks to see which patches have been applied to the kernel sources in order to determine which optional user-land modules to compile.

Once created, use “rpm” to install all the iptables files in /usr/src/redhat/RPMS/i386. There are 4 such packages: iptables, iptables-ipv6, iptables-pom and iptables-devel.

Step 8 : Rebuild the kernel.

Now we need to configure and build the patched kernel sources. We've already proved that the process works (prior to patching) so there shouldn't be any problems. It takes time, I'll agree – but just be patient.

  • “cd” to /usr/src/linux-2.4

  • Run “make clean” to clean out the results of the previous build.

  • Run “make menuconfig” to select the options just patched in. Select “Networking options” then “IP: Netfilter configuration”. From here, select “M” mode for the modules you want to include in the kernel. In particular, you will find that “String match support” and others just added are “off” by default. Save the configuration and exit the utility.

  • Run “make dep bzImage modules 2>&1 | tee make.out” to compile the kernel, saving a diagnostic trace of the process in “make.out”.

  • Check the end of the make.out file for any error messages that might indicate that the build process failed.

  • Run “make install modules_install 2>&1 | tee make.out” to install the new kernel and modules.

  • Check “make.out” again.

  • Check the /etc/lilo.conf or /etc/grub.conf file for sensible contents, and make very sure that there is still the possibility of running from the previous kernel version (just in case things haven't worked properly). Then reboot and select the new “custom” kernel when the boot loader menu is displayed.

Step 9 : Reboot

The moment of truth has arrived! Reboot the system with the new kernel and verify that "insmod ipt_string" works. It will report a message saying that the module is not GPL licensed - personally, I ignore this - the module seems to work fine none the less.