How We Firewall Our Systems With OpenBSD 2.8 and IPFilter


 

Much has been written about building Unix firewalls. Some of what has been written may even be useful.
I chose OpenBSD with IPFilter for the following reasons:

  1. IUPUI Physics Department was disposing of several Mac 68K's with sufficient disk space and memory that I could install a firewall, have a separate firewall maintenance machine, and have another machine to act as a network intrusion detection system.
  2. The OpenBSD development team has emphasized secure coding and code auditing.
  3. IPFilter seemed to be designed in such a way as to make it possible to have many errors in filter rule design default to block.
  4. The combination of text scripts for the firewall rules and OpenBSD's support for multiple operating platforms means that the entire firewall can be ported to a different processor design with ease.

 

Preparation

To prepare to build a firewall like this, the first thing to do is to go to the OpenBSD order page and buy OpenBSD. The 2 CD set is only $40 Canadian, and includes OpenBSD builds and tools for many different processors including: most varieties of Mac 68K's; Sparc 4C and 4M types; Sun3; iMac; Powerpc G3, G4, or cube; amiga; hp300/400; and i386 and higher PC's. The OpenBSD project depends on sales for funding. They build a good operating system for building firewalls and deserve the support. Note that those using i386 and higher PC's can also download a version of OpenBSD stripped down for firewalling, emBSD. However, for this as well, I recommend that you keep a maintenance system with a full OpenBSD installation from the CD's.

Once you have the 2 CD's, I recommend that you have at least two systems, one of which should have at least 800 MB of disk space and a single network interface while the other need only have 200 MB, but must have two network interfaces. On the one with 800 MB of disk space you should load the entire operating system, compiler and compiler tools, and man pages along with the entire source code tree. This will be your maintenance system. At this point, you should go to the OpenBSD errata starting page, locate the correct errata page for the version of OpenBSD you have, and download the appropriate source code patch files to your maintenance system. Patch installation instructions are at the start of each patch file. Follow the instructions intelligently, i.e., if several patches apply to the same code section, do not compile that code until all of those patches have been applied. The patches and compilations may take a while, but they improve the security and the response of the machine. You may want to compile a custom kernel for your systems to exclude kernel code portions you won't need. See kernel configuration, and OpenBSD kernel compilation and optimization, for information on how to do this.

The firewall system should only have a minimal OpenBSD configuration loaded. This means only a generic bsd kernel, the base binary distribution, and the etc distribution file. This gives everything necessary for firewalling. Once this is all installed, boot OpenBSD on the firewall system and transfer from the maintenance system the installed versions of those files that are also present on the firewall system. Note that some of the files installed in the process of patching are not present on the firewall system. However, they were used to produce files that are present on the firewall system. If you have compiled a custom kernel or have recompiled the generic kernel, now is the time to transfer the new kernel to the firewall system as well.
 

Actual Firewall Construction

After all of that preparation, firewall construction can finally begin (See also IPF How To). I've found that native address translation simplifies firewall rule development, and that is what I will describe here. I have gotten an "invisible" bridging firewall to work, but I did not like its behavior and won't describe that method. In the following instructions, I use $INTERNAL$ to mean the first three sets of numbers of the internal network IP, $EXTERNAL$ to mean the first three sets of numbers of the external network IP, $EXTERNAL-MYADDR to mean all four sets of numbers for an external (internet) IP address, and $INTERNAL-MYADDR to mean all four sets of numbers for an internal (local) IP address The steps for developing a firewall on the firewall system are as follows:
 

  1. Create the directories /etc/firewall.conf, /etc/internal.conf, and /etc/ipfrules.conf to hold files that copy to /etc later:
          cd /etc
          mkdir firewall.conf internal.conf ipfrules.conf
     
  2. Copy /etc/rc.conf and /etc/sysctl.conf into configuration directories:
          cd /etc
          cp rc.conf firewall.conf
          cp rc.conf internal.conf
          cp sysctl.conf firewall.conf
          cp sysctl.conf internal.conf
     
  3. Edit /etc/internal.conf/rc.conf to set all options to NO.  In particular, all of sendmail, portmap, inetd, sshd, ipfilter, and ipnat should all be set to NO.
     
  4. Edit /etc/firewall.conf/rc.conf to set the ipfilter and ipnat options to YES and all other options to NO.  In particular, sendmail, portmap, inetd, and sshd should all be set to NO.  The firewall itself will only be accessible from the console.
     
  5. Edit /etc/firewall.conf/sysctl.conf to uncomment the line that reads:
          net.inet.ip.forwarding=1    # 1=Permit forwarding (routing) of packets
     
  6. For the internal (local) interface, called here if0 for convenience, create a file /etc/hostname.if0 with content of the form:
          inet $INTERNAL$.100 255.255.255.0
          up
     
  7. Your internal systems should have the ip address $INTERNALNET.100 in their defaultrouter files.
     
  8. Copy this file to both configuration directories:
          cp hostname.if0 firewall.conf
          cp hostname.if0 internal.conf
     
  9. For the external (internet) interface, called here if1 for convenience, create a file /etc/hostname.if1 with content of the form:
          inet alias $EXTERNAL-MYADDR 255.255.255.0
          #repeat above line for each value of $EXTERNAL-MYADDR
          up
     
  10. Copy this file to the firewall.conf directory only:
          cp hostname.if1 firewall.conf
     
  11. Create the file /etc/mygate to contain the internet router address in the form:
          $EXTERNAL$.100
     
  12. Copy this file to the firewall.conf directory only:
          cp mygate firewall.conf
     
  13. Create the /etc/ipnat.rules file for address translation with content of the form:
         # $OpenBSD: ipnat.rules,v 1.2 1999/05/08 16:33:10 jason Exp $
         #
         # See /usr/share/ipf/nat.1 for examples.
         # edit the ipnat= line in /etc/rc.conf to enable Network Address Translation
         #
         #map ppp0 10.0.0.0/8 -> ppp0/32 portmap tcp/udp 10000:20000
         #
         #need this to make FTP work fully
         #
         map if1 $INTERNAL-MYADDR/32 -> $EXTERNAL-MYADDR/32 proxy port ftp ftp/tcp
         # Repeat above line for each paired set of $INTERNAL-MYADDR and $EXTERNAL-MYADDR
         #
         #this lets everything else work
         #
         bimap if1 $INTERNAL-MYADDR -> $EXTERNAL-MYADDR/32
         # Repeat above line for each paired set of $INTERNAL-MYADDR and $EXTERNAL-MYADDR
         #
    
    

  14. Copy this file to the firewall.conf and ipfrules.conf directories:
          cp ipnat.rules firewall.conf
          cp ipnat.rules ipfrules.conf
     
  15. Create the /etc/ipf.rules file for the firewall rules.  In the following template with instructions for this, $PROTECT is what we called if0 above, $CAMPUS is what we were calling if1 above:
         #  $OpenBSD: ipf.rules,v 1.6 1997/11/04 08:39:32 deraadt Exp $
         #
         # Template for filtering rules development for /etc/ipf.rules
         #
         # To use this template to develop a rules system:
         #
         # 1. Replace $CAMPUS with the name of the interface to which the campus network will
         #       be connected, e.g. ae1
         #
         # 2. Replace $PROTECT with the name of the interface to which your protected local area
         #       network will be connected, e.g. ae0
         #
         # 3. Replace $INTERNAL-NET with the internal net address, e.g. 192.168.123.0/24
         #
         # 4. Replace $EXTERNAL$ with the prefix to the external net address, e.g. 123.45.123
         #       Note that this is not the full address.
         #
         # 5. Duplicate the line that reads,
         #     "block in log quick on $CAMPUS from $EXTERNAL-MYADDR/32 to any group 10     # No, you're not me"
         #       as many times as needed so that there is one for each value of $EXTERNAL-MYADDR with 
         #       one of those values to be substituted for $EXTERNAL-MYADDR on each of those lines.
         #
         # 5. Replace each $EXTERNAL-MYADDR with an actual address to filter against, e.g. 123.45.123.45
         #
         # 6. Add incoming from campus network policy rules just above the line that
         #       reads, "block in quick on $CAMPUS all group 10      # Kill it all now!"
         #       to reflect the site needs.
         #
         # 7. Edit the outgoing to campus network policy rules between the line that
         #       reads,
         #         "# 4. Allow ping out." and the line that
         #       reads,
         #         "block in log quick on $PROTECT all group 20     # block everything else forever and log it!"
         #
         # 8. Edit other names beginning in $ to reflect your network.
         #
         # 9. Add the file /etc/ipnat.rules with the following type of content in this precise order:
         #       Note that the $EXTERNAL-MYADDR* and $INTERNAL-MYADDR* can be repeated as often
         #       as needed in order to reflect the entire network.  However, all map/proxy rules
         #       must precede all bimap rules.  Substitute for $CAMPUS as above.
         #         #
         #         #need this to make FTP work fully for some reason
         #         #
         #         map $CAMPUS $INTERNAL-MYADDR1/32 -> $EXTERNAL-MYADDR1/32 proxy port ftp ftp/tcp
         #         map $CAMPUS $INTERNAL-MYADDR2/32 -> $EXTERNAL-MYADDR2/32 proxy port ftp ftp/tcp
         #         map $CAMPUS $INTERNAL-MYADDR3/32 -> $EXTERNAL-MYADDR3/32 proxy port ftp ftp/tcp
         #         #
         #         #this lets everything else work
         #         #
         #         bimap $CAMPUS $INTERNAL-MYADDR1/32 -> $EXTERNAL-MYADDR1/32
         #         bimap $CAMPUS $INTERNAL-MYADDR2/32 -> $EXTERNAL-MYADDR2/32
         #         bimap $CAMPUS $INTERNAL-MYADDR3/32 -> $EXTERNAL-MYADDR3/32
         #
         # 10. The file /etc/hostname.$PROTECT where $PROTECT is replaced with the name of the interface
         #        to which your protected local area network will be connected must contain the lines
         #           inet $INTERNAL$.100 255.255.255.0
         #           up
         #        with $INTERNAL$ replaced with the prefix of the protected local area network, e.g. 192.168.123
         #        Note that this is not the full address.
         #
         # 11. The file /etc/hostname.$CAMPUS where $CAMPUS is replaced with the name of the interface
         #        to which the campus network will be connected must contain the lines
         #           inet alias $EXTERNAL-MYADDR1 255.255.255.0
         #           inet alias $EXTERNAL-MYADDR2 255.255.255.0
         #           inet alias $EXTERNAL-MYADDR3 255.255.255.0
         #           up
         #        with as many alias lines as you have $EXTERNAL-MYADDR* and with each value substituted
         #        appropriately.
         #
         # 12. The file /etc/myname should contain a system name such as bsd-4a
         #
         # 13. The file /etc/hosts should have a line that defines the host address as $INTERNAL$.100 as
         #           $INTERNAL$.100     bsd-4a     bsd-4a.not.here.now
         #        The exact name does not matter.
         #
         # 14. Edit the ipfilter= line in /etc/rc.conf to enable IP filtering
         #
         # 15. Edit the ipnat= line in /etc/rc.conf to enable NAT
         #
         # 16. Delete any file named /etc/bridgename*   The bridge is not needed and causes a leak.
         #
         # 17. The file /etc/mygate should contain the gateway router IP address such as:
         #          $EXTERNAL$.100
         #
         # 18. Check all the above files in /etc to be sure of their contents, connect the cables, reboot,
         #        and enjoy life behind your new firewall.  
         #
         #
         # Examples of rules to print to printers external to the firewall, and for telnet, web,
         # ftp, domain, and ping out both active and passive, are given.
         #
         # IP filtering rules.  See the ipf(5) man page for more
         # information on the format of this file, and /usr/share/ipf
         # for example configuration files.
         #
         block in  all             #kill everything, both ways.  Default deny
         block out all
         #
         # allow loopback to work.
         #
         pass in  quick on lo0 all
         pass out quick on lo0 all
         #
         # block problem packet types
         #
         block in     quick           all             with opt lsrr
         block in     quick           all             with opt ssrr
         block in     quick proto tcp all             with short
         block in log quick proto tcp from any to any flags FUP     # Block & log this OS fingerprinting
         #
         # block persistent campus network usages
         #
         block in     quick proto tcp/udp from any to any port = 67             #bootps
         block in     quick proto tcp/udp from any to any port = 68             #bootpc
         block in     quick proto tcp/udp from any to any port = 69             #tftp
         #
         # block problematic services on both sides
         #
         block in     quick proto tcp/udp from any to any port = sunrpc         #portmap
         block in     quick proto tcp/udp from any to any port = msp            #msp?
         block in     quick proto tcp/udp from any to any port = 1109           #kpop
         block in     quick proto tcp/udp from any to any port = 1127           #SUP debug
         block in     quick proto tcp/udp from any to any port = 1495           #cvc
         block in     quick proto tcp/udp from any to any port = 1524           #ingres lock
         block in     quick proto tcp/udp from any to any port = 1525           #prospero
         block in     quick proto tcp/udp from any to any port = 1645           #radius
         block in     quick proto tcp/udp from any to any port = 1646           #radius acct.
         block in     quick proto tcp/udp from any to any port = 1760           #www-ldap-gw
         block in     quick proto tcp/udp from any to any port = 2049           #nfs
         block in     quick proto tcp/udp from any to any port = 2105           #kerberos rlogin
         block in     quick proto tcp/udp from any to any port = 2108           #k-init
         block in     quick proto tcp/udp from any to any port = 2111           #k X
         block in     quick proto tcp/udp from any to any port = 2112           #k ip
         block in     quick proto tcp/udp from any to any port = 2120           #K auth
         block in     quick proto tcp/udp from any to any port = 4045           #lockd
         block in     quick proto tcp/udp from any to any port = 2627           #webster dict.
         block in     quick proto tcp/udp from any to any port = 5002           #radio free ethernet
         block in     quick proto tcp/udp from any to any port = 5680           #Kana-Kanji server
         block in     quick proto tcp/udp from any to any port = 6112           #dtspc
         block in     quick proto tcp/udp from any to any port = 7100           #font server
         block in     quick proto tcp/udp from any to any port = 7326           #internet CB
         block in     quick proto tcp/udp from any to any port = 26740          #hunt (6)
         #
         # The following line can be removed if site policy permits X terminals
         #
         block in     quick proto tcp     from any to any port 5999 >< 6010     # No X
         #
         #
         #
         block in quick on $CAMPUS all head 10
         #
         #
         # Antispoofing incoming rules
         #
              block in     quick on $CAMPUS from           0.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from           2.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from           5.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from          10.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from       20.20.20.0/24 to any group 10
              block in     quick on $CAMPUS from          23.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from          27.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from          31.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from          67.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from          68.0.0.0/6 to any group 10
              block in     quick on $CAMPUS from          72.0.0.0/5 to any group 10
              block in     quick on $CAMPUS from          80.0.0.0/4 to any group 10
              block in     quick on $CAMPUS from          96.0.0.0/3 to any group 10
              block in     quick on $CAMPUS from         127.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from        128.0.0.0/16 to any group 10
              block in     quick on $CAMPUS from       128.66.0.0/16 to any group 10
              block in     quick on $CAMPUS from      169.254.0.0/16 to any group 10
              block in log quick on $CAMPUS from       172.16.0.0/12 to any group 10
              block in     quick on $CAMPUS from      191.255.0.0/16 to any group 10
              block in     quick on $CAMPUS from        192.0.0.0/16 to any group 10
              block in log quick on $CAMPUS from      192.168.0.0/16 to any group 10
              block in     quick on $CAMPUS from         197.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from         201.0.0.0/8 to any group 10
              block in     quick on $CAMPUS from     204.152.64.0/23 to any group 10
              block in     quick on $CAMPUS from         224.0.0.0/3 to any group 10
         #
         # Anti-incoming broadcasts rules:
         #
              block in     quick on $CAMPUS from  255.255.255.255/32 to any group 10    # No broadcast.
              block in     quick on $CAMPUS from   $EXTERNAL$.255/32 to any group 10    # No broadcast.
              block in     quick on $CAMPUS from     $EXTERNAL$.0/32 to any group 10    # Not this broadcast either.
         #
         # Anti-self masquerade rule:
         #
              block in log quick on $CAMPUS from $EXTERNAL-MYADDR/32 to any group 10    # No, you're not me
         #
         #************************************************************************
         #
         # Insert lines to stop incoming traffic from ISP's from which past strange contacts have come.
         # Add to these as needed to block hostile activities.  Note this does not block outgoing to
         # these ISP's.  In other words, treat them as "Don't call us.  We'll call you." because of
         # their repeated problems.
         #
             block in     quick on $CAMPUS from  $PROBLEM$.0/$MASK$ to any group 10    # Block a problem
         #
         #*************************************************************************
         #
         # Internet incoming rules:
         #
         # 1. Place specific rules for the site here.
         #
         # 2. Allows in destination unreachables naturally.
         #
         # 3. Block everything else without exceptions and without further notice.
         #
              block in quick on $CAMPUS all group 10      # Kill it all now!
         #
         #
         #*************************************************************************
         #
         block in quick on $PROTECT all head 20
         #
         # Antispoofing from LAN rules
         #
              block in      quick on $PROTECT from !$INTERNAL-NET to any                 group 20    # Must be from legal address range
              block in      quick on $PROTECT from   any          to           0.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to           2.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to           5.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to          10.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to       20.20.20.0/24 group 20
              block in      quick on $PROTECT from   any          to          23.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to          27.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to          31.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to          67.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to          68.0.0.0/6 group 20
              block in      quick on $PROTECT from   any          to          72.0.0.0/5 group 20
              block in      quick on $PROTECT from   any          to          80.0.0.0/4 group 20
              block in      quick on $PROTECT from   any          to          96.0.0.0/3 group 20
              block in      quick on $PROTECT from   any          to         127.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to        128.0.0.0/16 group 20
              block in      quick on $PROTECT from   any          to       128.66.0.0/16 group 20
              block in      quick on $PROTECT from   any          to      169.254.0.0/16 group 20
              block in      quick on $PROTECT from   any          to       172.16.0.0/12 group 20
              block in      quick on $PROTECT from   any          to      191.255.0.0/16 group 20
              block in      quick on $PROTECT from   any          to        192.0.0.0/16 group 20
              block in      quick on $PROTECT from   any          to      192.168.0.0/16 group 20
              block in      quick on $PROTECT from   any          to         197.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to         201.0.0.0/8 group 20
              block in      quick on $PROTECT from   any          to     204.152.64.0/23 group 20
              block in      quick on $PROTECT from   any          to         224.0.0.0/3 group 20
         #
         # Anti-broadcasting rules.
         #
              block in      quick on $PROTECT from   any          to  255.255.255.255/32 group 20
              block in      quick on $PROTECT from   any          to   $EXTERNAL$.255/32 group 20
              block in      quick on $PROTECT from   any          to     $EXTERNAL$.0/32 group 20
         #
         # Anti-self send rules
         #
              block in      quick on $PROTECT from   any          to $EXTERNAL-MYADDR/32 group 20    # Don't send to self.group 20
         #
         # Do not need to block going to ISP's from which strange contacts have come.
         # Only needed to block their contacting here.  Here contacting them may be
         # an acceptable actitivy depending on why done.
         #
         #*************************************************************************
         #
         # LAN in going rules {outgoing to campus network.  Edit below here down to the line
         #    that reads,
         #       "block in log quick on $PROTECT all group 20     # block everything else forever and log it!"
         #    to reflect policy}.    The line above that reads
         #      "block in quick on $PROTECT from !$INTERNAL-NET to any group 20    # Must be from legal address range"
         #    means that now do not have to check address legality any more in this rule group since
         #    only legal from addresses are allowed in at all.
         #
         # Example shown is designed to:
         #
         # 1. Allow ftp, web, and telenet from internal through firewall.  Allows both
         #       passive ftp for web servers and active ftp sessions.  Of course, the NAT
         #       rules must do the ftp proxy as well for this to work completely.
         #
         # 2. Allow printing to approved printers ONLY.
         #
         # 3. Allow udp out to domain
         #
         # 4. Allow ping out.
         # 
              pass  in           quick on $PROTECT proto tcp     from any                     to $EXT-PRNT$.0/24 port = 515    flags S keep state group 20     # lp
              block in log       quick on $PROTECT proto tcp/udp from any                     to any             port = 515                       group 20     # lp only to ours
              pass  in           quick on $PROTECT proto tcp     from any                     to $DNS/32         port = 53     flags S keep state group 20     # domain names
              pass  in           quick on $PROTECT proto udp     from any                     to $DNS/32         port = 53             keep state group 20     # domain names
              pass  in log first quick on $PROTECT proto tcp     from any                     to any             port = 23     flags S keep state group 20     # telnet
              pass  in log first quick on $PROTECT proto tcp     from any                     to any             port = 80     flags S keep state group 20     # web
              pass  in log first quick on $PROTECT proto tcp     from any                     to any             port 19 >< 22 flags S keep state group 20     # ftp
              pass  in log first quick on $PROTECT proto tcp     from any                     to any             port = 443    flags S keep state group 20     # secure web
         #
         # This next allows active ftp out
         #
              pass  in log first quick on $PROTECT proto tcp     from any port 19 >< 22       to any             port > 1024   flags S keep state group 20
         #
         # This next allows passive ftp such as is done with web servers.  X already blocked and not a threat.
         #
              pass  in log first quick on $PROTECT proto tcp     from any port 32800 >< 46000 to any                           flags S keep state group 20
         #
              pass  in           quick on $PROTECT proto icmp    from any                     to any             icmp-type 8           keep state group 20
              block in log       quick on $PROTECT               all                                                                              group 20     # block everything else forever and log it!
         #
         #
         #*************************************************************************
         #
         # Internet outgoing rules for addresses
         # allow tcp and udp out from here.  Its been filtered.
         # allow pings out from here.  They've been filtered.
         # block all else
         #
         block out quick on $CAMPUS all head 60
              pass  out     quick on $CAMPUS proto tcp  from any to any             flags S keep state group 60
              pass  out     quick on $CAMPUS proto udp  from any to any                     keep state group 60
              pass  out     quick on $CAMPUS proto icmp from any to any icmp-type 8         keep state group 60
              block out     quick on $CAMPUS            all                                            group 60
         #
         #
         #*************************************************************************
         #
         # LAN out going rules for addresses
         #
         # Allow tcp and udp to go back to internal from here.  Its been filtered.
         # Allow destination unreachables to go back naturally.  Be sure that only
         # packets bound for the internal network pass this group.
         #
         block out quick on $PROTECT all head 80
              pass  out     quick on $PROTECT proto tcp from any to $INTERNAL-NET flags S keep state group 80   # insist on right address!
              pass  out     quick on $PROTECT proto udp from any to $INTERNAL-NET         keep state group 80
              block out     quick on $PROTECT           all                                          group 80
         #
         #
         block in  all
         block out all
         #
         # last rule wins in the event we get here!
         #
    
    

  16. Copy this file to the firewall.conf and ipfrules.conf directories:
          cp ipf.rules firewall.conf
          cp ipf.rules ipfrules.conf
     
  17. Delete any bridge files:
          rm -f /etc/bridge*
     
  18. Initiate the firewall:
          cd /etc/firewall.conf
          cp * ..
          reboot
     
  19. The rebooted system will be a firewall.
     
  20. For firewall maintenance, to disable the firewall and enable communication on the internal network only from the firewall system:
          cd /etc/internal.conf
          cp * ..
          rm -f /etc/mygate /etc/hostname.if1
          reboot
     
  21. Once maintenance is completed, steps 17 and 18 above can be used to restore firewall operation.

Text templates for each of the files to be created can be loaded from these links: