http://www.free-x.ch/pub/ipf-conf-en.html

Configuration of ipfilter on FreeBSD

Configuration of ipfilter on FreeBSD

Georg Wagner

1  Introduction

ipfilter is a small but efficient firewall package. It does everything done by other firewalls and even more. It's also a very portable package. FreeBSD versions above 3.3.3 have it already integrated and you only have to activate it via the kernel configuration. In earlier versions of FreeBSD you have to patch the kernel.

2  Installation

2.1  FreeBSD before version 3.3.3

If you are using a FreeBSD version above 3.3.3 you can skip this section.

ipfilter does not exist as package or port in the BSD meaning. Therefore you have to download the tarball first. You can get it here: ip-fil3.2.10.tar.gz1.

After uncompressing you will find installation instructions in a file named INST.FreeBSD-2.2 in the directory ip-fil3.2.10. For the 3.x-releases of FreeBSD the file INST.FreeBSD is relevant.

ipfilter can be installed in two different ways:

  1. directly in the kernel or
  2. as Loadable Kernel Module (LKM)

Both ways are described in the above mentioned files. The entry options IPFILTER will be written into the kernel configuration file by the installation script.

2.2  FreeBSD above 3.3.3

You only have to add the entry options IPFILTER to the kernel configuration file, after the line containing options INET.

2.3  All FreeBSD versions

In order to get logging information I have added the entry options IPFILTER_LOG to the kernel configuration.

After the installation you have either to load the LKM or your machine has to be rebooted.

2.4  Loading the filter rules via rc.network

Since I wanted to load the filter rules during the startup of my FreeBSD server I applied several changes to the files rc.conf and rc.network:

Changes in rc.conf

In rc.conf these lines were added:

ipfilter=YES; # NO to switch off
ipfilter_rules=/etc/ipf.rc # file with rules
ipmon_flags=-Ds   # NO for no logging
ipnat=YES
ipnat_rules=/etc/ipnat.rc

Changes in rc.network

In the file rc.network I added the following code in the subroutine network_pass_1() before the configuration of the interfaces:

# Configure the IP filter before configuring network interfaces
if [ X"${ipfilter}" = X"YES" -a -f "${ipfilter_rules}" ]; then
  echo ``configuring IP filter''
  echo ``ipf -Fa -f ${ipfilter_rules} -E''
  ipf -Fa -f ${ipfilter_rules} -E 
else 
  ipfilter=NO
fi
...
In the subroutine network_pass_2() I added this code after the configuration of named:

...
# insert after named
if [ X"${ipfilter}" = X"YES" -a  X"${ipmon_flags}" != X"NO" ]; then
  echo 'starting ipmon';
  ipmon ${ipmon_flags}
fi
I also added code for ipnat in network_pass_3() after the original natd-code:

# CHG-BEGIN: ipnat out of the ipfilter package 
# Configure NAT after configuring network interfaces
if [ "X${ipnat}" = X"YES" -a "X${ipfilter}" = X"YES" ]; then
  if [ -f "${ipnat_rules}" ]; then 
    echo 'configuring NAT' 
    ipnat -CF -f ${ipnat_rules} 
  else 
    echo 'ipnat: file ${ipnat_rules} not found.' 
  fi 
else 
  echo 'no network adress translation.' 
  ipnat=NO 
fi 
# CHG-END: ipnat out of the ipfilter package

In order to get some basic filter rules I executed the command:

# mkfilters > /etc/ipf.rc

which resulted in the following rules:

#
block in log quick from any with ipopts
block in log quick proto tcp from any to any with short
pass out on ed1 all head 150
block out from 127.0.0.0/8 to any group 150
block out from any to 127.0.0.0/8 group 150
block out from any to 192.168.1.110/32 group 150
pass in on ed1 all head 100
block in from 127.0.0.0/8 to any group 100
block in from 192.168.1.110/32 to any group 100
block in from 192.168.0.1/0xffffff00 to any group 100
pass out on fxp0 all head 250
block out from 127.0.0.0/8 to any group 250
block out from any to 127.0.0.0/8 group 250
block out from any to 192.168.0.1/32 group 250
pass in on fxp0 all head 200
block in from 127.0.0.0/8 to any group 200
block in from 192.168.0.1 to any group 200
block in from 192.168.1.110/0xffffff00 to any group 200

3  Creating filter rules

3.1  Preconditions

On my machine I use the interface fxp0 for the internal network. The internal network is a class C network in the range of 192.168.0.x with a netmask of 255.255.255.0. The external network - the internet - is connected via an ISDN-router. This router does a dialup when it receives packages destined for the internet. It also does network address translation. My FreeBSD server is connected to this ISDN-router via the interface ed1 with the ip-address 192.168.1.110. The ISDN-router has the internal ip-adress 192.168.1.111, which will be translated in the router to the adress dynamically assigned by the provider during a dialup. I use ipnat, which belongs to ipfilter, to redirect pakets destined for the outside to the external interface. In this configuration network address translation happens twice; first on the server and then in the router.

3.2  How to configure ipnat ?

For ipnat I created the file /etc/ipnat.rc containing the following lines:

map ed1 192.168.0.0/24 -> 192.168.1.110/32 portmap tcp/udp 40000:65000
map ed1 192.168.0.0/24 -> 192.168.1.110/32

3.3  What to filter ?

Take your stance

Having clarified the preconditions the question remains, what do I want to filter? Basically I had to decide which stance I wanted to take:

Permissive stance: Everything not explicitely forbidden is allowed.
Restrictive stance: Everything not explicitely allowed is forbidden.

The permissive stance is easily implemented. If you do not give any rules to ipfilter, it follows exactly this stance. Also the rules generated by the script mkfilters are based on a slightly enhanced permissive stance. With this stance you take the risk to allow to much, what you normally realise when the damage is already done.

The restrictive stance is more secure but is also more difficult to implement. If you forget something some services may stop to work. On a network with a lot of user you won't have to wait for a long time to get complaints.

Dos and don'ts

Before describing the rules I want to give some hints, how to proceed while generating rules:

Filter rules for the permissive stance

The basic rules you will get by calling mkfilters (see above). To these we'll add some rules to catch pakets, which are principally suspect and to prevent spoofing. The augmented rules for the permissive stance are:

# augmented rules generated by mkfilters
block in log quick from any with ipopts
block in log quick proto tcp from any to any with short
block in log quick all with opt lsrr
block in log quick all with opt ssrr
#-------------------------------------------------------
# loopback pakets left unmolested
pass in quick on lo0 all
pass out quick on lo0 all
#-------------------------------------------------------
pass out on ed1 all head 150
block out from 127.0.0.0/8 to any group 150
block out from any to 127.0.0.0/8 group 150
block out from any to 192.168.1.110/32 group 150
#-------------------------------------------------------
pass in on ed1 all head 100
block in from 127.0.0.0/8 to any group 100
block in from 192.168.1.110/32 to any group 100
block in from 192.168.0.1/24 to any group 100
#-------------------------------------------------------
pass  out on fxp0 all head 250
block out from 127.0.0.0/8 to any group 250
block out from any to 127.0.0.0/8 group 250
block out from any to 192.168.0.1/32 group 250
#-------------------------------------------------------
pass in on fxp0 all head 200
block in from 127.0.0.0/8 to any group 200
block in from 192.168.0.1/32 to any group 200
block in from 192.168.1.110/24 to any group 200

Filter rules for the restrictive stance

*  Services to be allowed

First we do trust our internal users, but we prepare to be more restrictive on the fly.

Before we start to formulate the rules, we select the services we want - rsp. have - to support. In this list we also mention the service - not the paket - direction, the port and the protocol.

*  Creating the rules

#--------------------------------------------------------------------------
# ed1 - external interface
# fxp0 - internal interface
#--------------------------------------------------------------------------
# First, nasty pakets which we don't want near us at all
# pakets which are too short to be real except echo replies on lo0
pass in log quick on lo0 proto icmp from 127.0.0.1/8 to 127.0.0.1/8 with short 
block in log quick all with short
block in log quick all with opt lsrr
block in log quick all with opt ssrr
#--------------------------------------------------------------------------
# loopback packets left unmolested 
pass in log quick on lo0 all 
pass out log quick on lo0 all 
#--------------------------------------------------------------------------
# Group setup: 
# 100 incoming ed1 
# 150 outgoing ed1 
# 200 incoming fxp0
# 250 outgoing fxp0
#--------------------------------------------------------------------------
block in log body on ed1 all head 100
block out log body on ed1 all head 150
#--------------------------------------------------------------------------
block in log on fxp0 all head 200
block out log on fxp0 all head 250
#--------------------------------------------------------------------------
# incoming ed1 traffic - group 100
# 1) prevent localhost spoofing
block in log quick from 127.0.0.1/32 to 192.168.0.0/24 group 100
block in log quick from 127.0.0.1/32 to 192.168.1.0/24 group 100
block in log quick from any to 127.0.0.1/8 group 100
#--------------------------------------------------------------------------
# 2) deny pakets which should not be seen on th internet (paranoid)
block in log quick from 10.0.0.0/8 to any group 100
block in log quick from any to 10.0.0.0/8 group 100
block in log quick from 172.16.0.0/16 to any group 100
block in log quick from any to 172.16.0.0/16 group 100
block in log quick from 192.168.0.0/16 to any group 100
block in log from any to 192.168.0.0/16 group 100
# 3) implement policy
# allow incoming ftp-data
pass in log quick proto tcp/udp from any to 192.168.1.1/24 keep state group 100
# if nothing applies, block and return icmp-replies (unreachable and rst)
block return-icmp(net-unr) in proto udp from any to any group 100
block return-rst in log proto tcp from any to any group 100
#--------------------------------------------------------------------------
# outgoing ed1 traffic - group 150
# Setup outgoing DNS
pass out log quick proto tcp/udp from any to 212.40.0.10 port = 53 keep state group 150
pass out log quick proto tcp/udp from any to 212.40.5.50 port = 53 keep state group 150
# allow outgoing http-service
pass out log quick proto tcp from any to any port = 80 flags S/SA keep state keep frags group 150
# allow outgoing smtp traffic
pass out log quick proto tcp from 192.168.1.1/24 to any port = 25 flags S/SA keep state group 150
# allow outgoing pop3 traffic
pass out log quick proto tcp from 192.168.1.1/24 to any port = 110 flags S/SA keep state group 150
# allow outgoing ftp traffic
pass out log quick proto tcp/udp from 192.168.1.1/24 to any port = ftp keep state group 150
pass out log quick proto icmp from any to any keep state keep frags group 150
#--------------------------------------------------------------------------
# incoming traffic on fxp0 - group 200
#--------------------------------------------------------------------------
# 1) prevent localhost spoofing
block in log quick from 127.0.0.0/8 to any group 200
block in log quick from 192.168.0.1/32 to any group 200
block in log quick from 192.168.1.110/24 to any group 200
pass in log quick from any to any group 200
#--------------------------------------------------------------------------
# outgoing traffic on fxp0 - group 250
#--------------------------------------------------------------------------
block out log quick from 127.0.0.0/8 to any group 250
block out quick from any to 127.0.0.0/8 group 250
block out log quick from any to 192.168.0.1/32 group 250
pass out log quick from any to nay group 250
#--------------------------------------------------------------------------
These rules may serve as a starting point for additional and more elaborated rules.

4  Conclusion

While starting up the my FreeBSD server is configurated as firewall using ipfilter. The configuration shown is easily extended.

If you find any errors in this article or if you have any suggestions, please contact me.


Footnotes:

1I have taken this version because newer versions only support LKM on a 2.2.x-version of FreeBSD.

2In some tutorial about ipfilter it was said, that the way ipfilter handles keep state is confusing. But if you think in outgoing or incoming services the rules correspond nicely with the service's direction. Look at the pass out rules for smtp !

3This is outgoing because we - resp. fetchmail - initiate the pop3 paket exchange.

4There is a better way doing ftp by using the internal proxy of ipfilter.


File translated from TEX by TTH, version 2.53.
On 5 Jan 2000, 08:24.