IP Filter – an alternative firewall and NAT to ipfw/natdThis article is now outdated. For FreeBSD 3.* and ipf 3.3.3, see Installing IP Filter 3.3.3
You may have seen the problems I was having with natd and ipfw. It was suggested by by Darren Reed that I drop ipfw/natd and try IP Filter. I decided to do so. For a trial at least. It should also be mentioned that Darren is the author of IP Filter.
IP FilterThe main webpage is http://coombs.anu.edu.au/~avalon/. See their list of mirrors for the latest source. It basically does the same thing as the natd and ipfw combination, but it seems to do it better. This is based solely upon my first impressions. However, like most ports, the documentation on how to install it is minimal and open to some interpretation. I have listed the steps I took. Hopefully, they’ll work for you too.
One of the best how-to guides for ipfilter is at:
You will be installing a new kernel. I named my new kernel IPFILTER. You may wish to name your kernel something else. Keep that in mind when you see IPFILTER.
obtain the sourceAs mentioned above, use the http://coombs.anu.edu.au/~avalon/ site to obtain your source code. I downloaded my file and place it in the /usr/ports/net directory. Then I did the following to uncompress and extract the files:
- cd /usr/ports/net
- gunzip ip-fil3.2.9.tgz
- tar -xvf ip-fil3.2.9.tar
- cd ip_fil3.2.9
prepare a kernelPrepare, but don’t yet compile a new kernel. Follow these steps to do this:
- cd /usr/src/sys/i386/conf/
- cp GENERIC IPFILTER
- /usr/sbin/config IPFILTER
We will compile this kernel later on. The above steps merely create the kernel file which will be modified by the IP Filter make.
make IP Filter
- cd /usr/ports/net/ip_fil3.2.9
- make freebsd22 IPFILKERN=IPFILTER
- make install-bsd
Step 3 may have to be done as root. Step 4 must be done as root.
build a new kernelYou should now build the kernel you prepared above.
- cd /usr/src/sys/i386/conf/
- /usr/sbin/config IPFILTER
- cd ../../compile/IPFILTER
- make depend
- make install
reboot to install the kernelIn order for the kernel to be installed, you need to reboot. This command will do it for you:
shutdown -r now
load the moduleAfter the new kernel boots, issue the following command to load the module:
Network Address Translation. I’ve summarized what I did based on the instructions supplied in the file NAT.FreeBSD. The following numbered sections are extracted from that file. Please refer to the next section for a list of other steps I performed which were not included in the instructions.su-2.02# modload /lkm/if_ipl.o Module loaded as ID 0 su-2.02# modstat Type Id Off Loadaddr Size Info Rev Module Name DEV 0 79 f3c86000 0031 f3c90248 1 IP Filter v3.2.9 su-2.02#
NOTE: The instructions supplied with IP Filter make reference to /etc/sysconfig which has been replaced by /etc/rc.conf.
1. Load the kernel moduleWe did this manually above. In order for it to run at boot-time, you should add the following line to /etc/rc.local (NOTE: /etc/rc.local is deprecated; use /usr/local/etc/rc.d/ instead; see Starting stuff at boot time and Installing IP Filter 3.3.3 for an example):
2. Setting up the NAT RulesRules for IP Filter are stored in the file /etc/ipnat.conf. I took what I found in /usr/ports/net/ip_fil3.2.9/rules/nat-setup as the basis for my NAT rules. Here they are (these may or my not be my real numbers):
map ed0 10.1.0.0/16 -> 18.104.22.168/32 portmap tcp/udp 10000:40000 map ed0 10.1.0.0/16 -> 22.214.171.124/32
Please note that the above example differs from that supplied in the file. The second line does not contain the portmap keyword. I could not get the rules to load otherwise.
3. Loading the NAT RulesThe above rules need to be loaded everytime the computer reboots. This can be done by putting the following line in /etc/rc.local (NOTE: /etc/rc.local is deprecated; use /usr/local/etc/rc.d/ instead; see Starting stuff at boot time and Installing IP Filter 3.3.3 for an example):
ipnat -f /etc/ipnat.conf
You can view the loaded rules by issuing the following command:
I have also supplied my NAT rules for those that may need an example.
As for your firewall rules, I suggest you start with the contents of the Rules directory and use either BASIC_1.FW or BASIC_1.FW as the basis for your rule set. Also note that BNF contains the rule syntax.
4. Enable Routing between interfacesThe instructions say you should do this:
sysctl -w net.inet.ip.forwarding=1
But you can achieve the same thing by using /etc/rc.conf. Look for the following section and ensure that the values are as shown.
### Network routing options: ### gateway_enable=YES
5. Static Routes to Subnet RangesThe instructions want you to set up the following routes. I didn’t do this and it still worked. I’m not sure what I’m missing.
static_routes="foo" route_foo="10.0.0.0 -netmask 0xf0000000 -interface 10.0.0.1"
6. Make sure that you have your interfaces configuredIn /etc/rc.conf, you should have someething which looks like this:
network_interfaces="fxp0 fxp1" ifconfig_fxp0="inet 126.96.36.199 netmask 255.255.255.0" ifconfig_fxp1="inet 10.0.0.1 netmask 255.0.0.0"
IP Filter examples are highly recommended reading. Of note are the sections on NAT and Rule Groups. In short, if you do this, you will Flush existing rules and add the rules contained in the /etc/ipfrules:
- removed the "options IPFIREWALL" and "options IPDIVERT" from my kernel.
- changed firewall_enable=YES to firewall_enable=NO in /etc/rc.conf.
ipf -Fa -f /etc/ipfrules
TIP: Another good thing to try is to add the rules, wait a bit, then restore the original rules. This ensure that you haven’t locked yourself out of your box. This is very useful when working remotely.
ipf -I -Fa -f /etc/ipfrules
ipfilter has two rule lists, the active list and the inactive list. ipfilter always works against the active list. The options in the line above, as taken from the man ipf page are:
-I Set the list to make changes to the inactive list. -F This option specifies which filter list to flush. The parameter should either be "i" (input), "o" (output) or "a" (remove all filter rules). Either a single letter or an entire word starting with the appropriate letter maybe used. This option maybe before, or after, any other with the order on the command line being that used to execute options.-f <filename> This option specifies which files ipf should use to get input from for modifying the packet filter rule lists.
So the above command tells ipfilter to load your rules into the inactive list but first flushes any rules which were already there.
ipf -s; sleep 10; ipf -s
The following man page extract explains the above command.
-s Swap the active filter list in use to be the "other" one.
The above command line tells ipfilter to swap the active and inactive list. This invokes the rules you added with the first command. It then tells the system to sleep for 10 seconds. You should type a few characters and see if they are echoed. If they are, you haven’t locked yourself out of the system. But just in case you have, the next command tells ipfilter to swap the active/inactive lists again. This puts you right back where you were before.
Rule GroupsThe concept of a rule group is at the heart of understanding how IP Filter works. Rules can be grouped together according to logical function. The documentation also states that groups make for more efficient rule processing.
Each group is identified by a unique group number. A new group is created by including a head statement such as the following:
block in log on ed0 all head 100
The above rule declares that all incoming packets on ed0 will be processed using group 100. The default action for this group is to block all. Note: that only packets which match the above rule will be processed by rules in group 100.
If we wish to allow people to access our webserver, we would add a rule which looks like this.
pass in quick proto tcp from any to any port = WWW keep state group 100
Default rulesIP Filter comes with a script which will create some default blocking rules for you. Read rules/firewall for details. Here’s what I did to invoke those rules:
- cd /usr/ports/net/ip_fil3.2.9
- ./mkfilters > rules/mkfilter_rules
- ipf -f rules/mkfilter_rules
To view the rules, try the following:
Firewall rulesBut for real protection, you want the firewall rules. I started with the ones provided in rules/BASIC_1.FW. Then I moved to rules/BASIC_1.FW because I couldn’t get some of my services to run. I struggled for 2 days trying to get traceroute to work. I gave up.
(see below for additional information).
I found it very difficult to find out how to load rules, display the rules, and view the accounting statistics. Once you know the commands, they are easy to do. That said, I found it difficult to obtain this information from the documentation. Hopefully, the information I’ve provided above will help.
See the notes below for more information
traceroute solved (added on 9 November 1998)I’ve been using the latest beta of IP Filter and doing some testing with the help of the author. Darren has fixed the trace problem I initially encountered. The utility I was using to do a trace used short packets which were being removed by the block in log quick all with short rule. This fix will be available with IP Filter 3.2.10.
some block packets (added on 15 November 1998)I am now using IP Filter for my firewall. The only outstanding problem is related to packets which are being blocked. I’ll have to investigate this further now that I know how to interpret the information in the log..
Tip for updating your rule set remotely (added on 16 November 2000)When you are changing your rule set, there is always the chance that you will lock yourself out of your box. That’s OK if you’re at the console, or if you can just walk over and reset things. But that’s not very nice if the box is several hours away by car or plane. So here’s a tip on how to change the rule set, do a short test, and make sure you’re not locked out. This tip came to me from David S. Madole of Optimized Micro Devices back in April 1999 via the ipfilter mailing list, but that message is still in my mailbox.
modify /etc/ipfrules ipf -I -Fa -f /etc/ipfrules ipf -s; sleep 10; ipf -s
In this example, you modify the rules. Then you load those rules into the inactive rule set. Then you swap the rule sets, wait 10 seconds, then swap them back. During that ten seconds, you can type a few characters to make sure you get echoes, then type ^C.
Hope this helps.