Securing Hosts with IP Filter

By Amy Richs
 
Connection over the Internet is the lifeblood of many of today's businesses, but it also leaves the door open for malicious crackers. To protect their networks, systems administrators employ a variety of tactics to restrict access to only the machines and services deemed necessary. The most widely used method to tighten access permissions is packet filtering and firewalling. Often filtering happens at the company's main connection points to the Internet, but the savvy systems administrator defends not only the routers but individual hosts as well.

Various products, such as Sun's SunScreen, Check Point FireWall-1, iptables, ipfw, OpenBSD pf, and IP Filter exist to perform a combination of stateful packet filtering and Network Address Translation (NAT). IP Filter, written by Darren Reed, provides a good balance of features and OS portability for sites that need to protect heterogeneous environments.


 
An Overview

IP Filter or ipfilter, also known as ipf, runs on the Solaris Operating System (SPARC and x86 Platform Editions), SunOS, FreeBSD, NetBSD, OpenBSD, HP-UX, Tru64, Irix, and several other operating systems. The portion that interacts with the kernel can be compiled into the kernel itself, compiled as a standalone kernel module, or both (but only one at a time), depending on the OS. Under the Solaris OS, ipfilter is loaded as a kernel module with the modload command. Because of the drastic differences in the Linux kernel design, however, very few versions of Linux will support ipfilter (see the IP Filter FAQ).

The ipfilter package consists of several programs:

  • ipf: This binary allows the user to specify a set of filter rules, either from a file or on the command line, which are then added to the kernel's current filter list. The ipf program also allows the user to enable or disable filtering entirely, delete individual rules or the entire ruleset, and reset the statistics counters.
  • ipnat: This binary functions as the NAT-controlling counterpart to ipf. It reads in rules from standard in or a file and applies them to the existing NAT table. In addition, ipnat allows the user to individually delete or entirely flush NAT rulesets and monitor NAT statistics.
  • ipfs: This binary saves and restores information for NAT and state tables.
  • ipmon: This binary, as the name suggests, monitors both ipf and ipnat by reading the log device (the default is /dev/ipl) and sending data to standard out, a file, or directly to syslog.
  • ipfstat: This binary allows the users to query the kernel to monitor statistics on ipf's packet processing. ipfstat takes a number of different flags, resulting in finer or coarser statistic output.
  • ipftest: This binary reads a ruleset from standard in or a file and then applies sample IP packets to said rules. This allows the user to test and debug new rulesets before making them an active part of the actual firewall ruleset.
  • iptest: This binary contains a set of test "programs" that send out a series of IP packets aimed at testing the strength of the TCP/IP stack of the target host. Running iptest against a target machine may crash it.
  • ipsend: This binary generates arbitrary IP packets for Ethernet-connected machines.
  • ipresend: This binary reads in a data file of saved IP packets from a program like snoop, tcpdump, or etherfind, and replays the session. This is useful for debugging rulesets with the exact same set of data every time.

 
Obtaining and Installing IP Filter

IP Filter needs little in the way of supporting software but does require a 64-bit-capable compiler if the target machine runs a 64-bit kernel. The UltraSPARC III processors, for example, no longer support 32-bit applications and necessitate building 64-bit binaries. Solaris users can install gcc version 3.3.2 (known to produce 64-bit safe code) or later, or they can opt to use Sun's own commercial compiler. Also, ensure that make is defined as /usr/ccs/bin/make and not GNU make, regardless of the compiler vendor. The last two steps below automatically create a Solaris package, `/usr/bin/uname -p`-`/usr/bin/uname -r`/ipf.pkg, which can be copied to other hosts for installation. If ipfilter is compiled on a 64-bit machine, this package will include both 64- and 32-bit versions of select binaries and the kernel module.

wget http://coombs.anu.edu.au/~avalon/ip-fil3.4.33pre1.tar.gz
gtar zxf ip-fil3.4.33pre1.tar.gz 
cd ip_fil3.4.33pre1/
make solaris
cd SunOS5
make package

The resulting package installs the binaries ipf, ipnat, ipfstat, and ipfs into /usr/sbin/sparcv7 and /usr/sbin/sparcv9 and links their counterparts in /usr/sbin with /usr/lib/isaexec for ease of use. The loadable kernel modules reside in /usr/kernel/drv/sparcv9/ipf and /usr/kernel/drv/ipf. The module loaded depends on whether the machine booted the 64- or 32-bit kernel. Architecture-independent binaries install into /opt/ipf/bin, man pages into /opt/ipf/man, header files into /usr/include/netinet, examples into /opt/ipf/examples, and the system init file into /etc/init.d/ipfboot (symlinked to by /etc/rc2.d/S65ipfboot).

After creating the package, add it to each desired host with the pkgadd command:

pkgadd -d `/usr/bin/uname -p`-`/usr/bin/uname -r`/ipf.pkg

This installs the software and loads the kernel module, but does not enable any filtering or NAT rulesets. The next step requires building a filter and/or NAT ruleset based on the company's access policy.


 
Configuration

IP Filter configuration rules reside in the files /etc/opt/ipf/ipnat.conf for NAT and /etc/opt/ipf/ipf.conf for filtering. If /etc/opt/ipf/ipnat.conf exists, the /etc/init.d/ipfboot startup script will run ipnat, and if /etc/opt/ipf/ipf.conf exists, the script will run ipf. The two files are independent of each other, and ipf and ipnat may be run singly or together on any given machine.

Configuring NAT

ipnat provides Network and Port Translation (NPAT), allowing the user to change any of the source and destination IP addresses and ports. Four directives are used in /etc/opt/ipf/ipnat.conf to accomplish this:

  • map - Map one address or network to another using a round-robin algorithm.
  • map-block - Set up static IP address-based translation. The mapping is based on an algorithm designed to force the addresses to be translated into the destination range.
  • bimap - Set up bidirectional NAT between an external and an internal IP address.
  • rdr - Redirect packets destined for one IP address and port pair to another address and port pair.

The grammar for ipnat rulesets is described in BNF notation in the ipnat(5) man page. The grammar listed is incomplete and outdated, but the use of ipnat is actually quite simple. The most commonly used directive is map, and the most basic example is mapping all packets from one address or range of addresses to another address.

The following example is known as a many-to-one mapping, or IP masquerading, and is most often used by small organizations that use only one Internet-facing server. These two rules map any packets originating from the class C sized network 192.168.1.0/24 and destined for the hme1 interface to the IP address 10.1.1.1. The first rule remaps the port number for each TCP and UDP connection so that multiple hosts can send data to the same ports without collisions. The second rule changes the appearance of the packet's source address.

map hme1 192.168.1.0/24 -> 10.1.1.1/32 portmap tcp/udp 10000:65000
map hme1 192.168.1.0/24 -> 10.1.1.1/32

Often the notation 0/32 replaces the actual IP address of the machine running ipnat, and the auto keyword replaces the port range so that ipnat determines which ports are free on its own. The preceding example, running on the machine with the hme1 "external" interface of 10.1.1.1, would be written as the following instead:

map hme1 192.168.1.0/24 -> 0/32 portmap tcp/udp auto
map hme1 192.168.1.0/24 -> 0/32

The preceding example is a many-to-one mapping, but sometimes a many-to-many mapping is desired instead. This kind of mapping becomes useful when a small set of statically assigned addresses for services in a DMZ needs to be mapped to internal addresses in use behind a router. The following example, using the directive map-block, remaps the addresses in the class C sized network 192.168.1.0/24 to the class C sized network 10.1.1.0/24:

map-block hme1 192.168.1.0/24 -> 10.1.1.0/24 auto

The last type of NAT is a one-to-one mapping, accomplished in the ipnat.conf file with the bimap directive. The following example makes the interface with the IP of 192.168.1.1 look like it has the IP address of 10.1.1.1:

bimap hme1 192.168.1.1/32 -> 10.1.1.1/32

The rdr directive usually comes into play when trying to provide transparent proxying for a service. The following example redirects connections TCP on port 80 of 10.1.1.1 to port 8080 of 192.168.1.1, allowing a web server to be hidden inside the internal network and running on a non-standard port:

rdr 10.1.1.1/32 port 80 -> 192.168.1.1 port 8080 tcp

A lengthier explanation and more examples of each of the ipnat directives can be found in the ipnat(5) man page and in the ipf HOWTO document.

Configuring Filtering

The /etc/opt/ipf/ipf.conf file contains all of the filtering rules for a host and is read and matched from top to bottom. People usually choose one of two policies: block everything and then allow certain packets, or pass everything and block only certain packets. The former is more restrictive and therefore more secure, but may not be appropriate in all situations. The default filtering rules should be based on the policy at the site in question.

The filter rules use eight action keywords which are applied to packets matching the parameters of the rule. In general, the first three are the most heavily used in any filtering configuration:

  • block - Block a packet.
  • pass - Pass a packet.
  • log - Log the action taken on the packet. The following qualifiers can be appended to the log action. If more than one qualifier is used, they must be specified in the following order:
    1. body - Log the first 128 bytes of the packet contents after logging the headers.
    2. first - If being used in conjunction with the keep option (described below), log only the first packet in the session and ignore other packets sharing the state information.
    3. on-block - If the filter is unable to block the packet (if the log reader is too slow, for example), treat the rule as if the action were block.
    4. level <loglevel> - Use the given priority and, if given, facility to log information about this packet using ipmon -s.
  • count - Include the packet in the accounting statistics kept by ipfstat.
  • call - Call the named function in the kernel. This action is not well documented and is only for use by experienced hackers.
  • skip <n> - Skip over the next n filter rules.
  • auth - Hold the packet in an internal buffer and call an external program to determine whether or not the packet is valid. An example external program might request authentication, such as a password, from the user before allowing the packet through.
  • preauth - Look at the pre-authenticated list for a match. If no match is found, drop the packet. If a match is found, use the result from that ruleset instead.

After specifying the action to take on the packet, the next word must be either in or out, defining whether the rule is for packets inbound to the kernel (just received on an interface) or outbound from the kernel (processed by the stack and on its way to an interface). The next keywords are optional, but when used must be listed in the order below:

  1. log - Log the packet if this rule is the last that matches. The qualifiers mentioned above in the description of the log action may also be specified here under the log keyword.
  2. quick - If the packet matches this rule, stop processing the packet and take whatever action this rule lists.
  3. on <iface> - Make the rule apply only to the specified interface.
  4. dup-to <iface> - Copy the packet and send the duplicate to the specified interface. This option is useful for logging on remote hosts or when using a network sniffer.
  5. to <iface> - Move the packet to the outbound queue on the specified interface. Use this option to circumvent further kernel processing, making the machine on which ipfilter runs appear to be a transparently filtering hub or switch rather than a router.
After specifying any options, the rest of the rule consists of keyword parameters that determine whether or not the packet matches the rule. If more than one parameter is listed in a rule, they must be specified in the following order:
  1. tos - Filter based on the packet's Type Of Service. The TOS mask can be expressed as a hexadecimal or decimal number.
  2. ttl - Filter based on the packet's Time-To-Live value. The decimal value specified in the rule must exactly match that of the packet.
  3. proto - Filter based on the packet's protocol. Protocol names listed in /etc/protocols or the decimal number of the protocol may be used.
  4. from/to - Filter based on the source or destination IP address and/or port number. IP addresses can be specified as an address/mask pair, a dotted quad, a valid hostname, or the special keyword any which matches all. Ports can be specified by name as listed in /etc/services, or by decimal number.
  5. with - Filter based on the listed IP option. The with parameter may be prepended with the not or no options to indicate that the rule should match only if the listed option is not present.
  6. flags - Filter based on the listed TCP flag. The flags parameter is therefore only useful with TCP rules. The list of possible options to the flags parameter includes:
    • F - FIN
    • S - SYN
    • R - RST
    • P - PUSH
    • A - ACK
    • U - URG
    These options can be ANDed together and masked to produce various combinations. For example, flags SA becomes flags SA/AUPRFSC and will match and packet with only the SYN and ACK flags set. On the other hand, specifying flags S/SA will only match a packet with just the SYN flag set out of the SYN-ACK pair.
  7. icmp-type - Filter based on the ICMP type. This parameter should only be used when proto icmp is specified and should not be used in conjunction with flags.
  8. keep state - Keep information about the session to which the packet is attached. State can be kept for TCP, UDP, and ICMP packets.
  9. keep frags - Keep information about fragmented packets to later apply to other fragments.
  10. head <number> - Create a new grouping of filter rules, denoted by the tag <number>. Multiple rule groupings allow for a hierarchy of rules and shorter searches through the lists. For example, the two rule groupings could be for proto tcp and proto udp. If a packet is UDP, it will first fail the head rule of the tcp group and then ignore the rest of the rules in that group. The processed packet therefore skips all other rules that apply only to TCP packets.
  11. group <number> - Add the rule to the group number.

Filtering Examples

The following examples illustrate some common uses of ipf. These examples provide a good starting place for filtering configurations, but are by no means complete. If using these rulesets as a starting base, be sure to tailor them to the specific needs of the site.

This first case shows a machine acting as a router between the RFC 1918 address space 192.168.1.0/24 and the outside world. This host follows a mostly closed policy and begins by blocking and logging everything and then allowing specified services out.

This example is a mostly closed configuration which resides on a host with one network connection. This machine hosts a high-volume web server, and the rules for ports 80 and 443 come first to lessen the number of rules searched for most packets.

This example shows a mostly open configuration on a host with one interface that just blocks a few hosts and ports.

 


 
Troubleshooting and Tuning

Occasionally packets that you think should make it past your filter are blocked, or some mapping doesn't appear to be translated in the manner you think it should. When this happens, there are several tools available for debugging and fine tuning. The first of these is the NAT/filter log file, the contents of which is controlled by the ipmon program. Make sure that logging occurs for each rule that processes the packet in question.

The other useful debugging tools are ipnat and ipfstat. The ipnat program provides NAT statistics as well as controlling the application or rulesets. If you are encountering a NAT issue, use ipnat -l, ipnat -v, and ipnat -s. If the issue occurs with the filtering rules, the ipfstat program provides a wealth of information about packet authentication, fragment information, per rule or protocol and overall statistics, state information, and a top like facility (ipfstat -t) for doing real-time monitoring.

Some common problems that occur with NAT and filtering involve timeouts for idle or partially closed connections and running out of table space. For the former, the following entries in /etc/system may prove useful (note that the timers run "two ticks to a second", so the 172800 ticks for ipf:fr_tcpidletimeout listed below translates to 24 hours). A reboot is required for the changes to take effect.

* ipf: adjust the default tcp timeouts downward so that
*      idle (dead) and half closed states get killed off quicker.
set ipf:fr_tcpidletimeout = 172800
set ipf:fr_tcphalfclosed = 7200

On servers that see a large amount of traffic where the state is kept as part of the rulesets, it's sometimes necessary to increase the state table size to accommodate the load. It's also wise to add flags S to each rule where state is kept, so that only the first packet of the session is recorded. To adjust the state table size so that there are enough buckets for large servers, add the following to /etc/system and reboot the machine:

* ipf: adjust the state table sizes so we have enough buckets.
*      IPSTATE_MAX (=fr_statemax) should be ~70% of IPSTATE_SIZE
*      IPSTATE_SIZE (=fr_statesize) has to be a prime number
set ipf:fr_statemax = 7000
set ipf:fr_statesize = 10009

To increase the table size for NAT, add the following to /etc/system and reboot the machine:

* ipf: adjust the NAT table sizes so we have enough buckets.
*      generally you have fewer than 127 rules in ipnat.conf
*      so no need to waste memory for more.
set ipf:ipf_nattable_sz = 10009
set ipf:ipf_natrules_sz = 127
set ipf:ipf_rdrrules_sz = 127

 
Resources

Many useful online resources exist for ipfilter on a variety of platforms. The sites listed here provide a wealth of examples as well as technical help from other ipfilter users and the author himself.

 

 

 


Last changes: Sunday, February 13, 2005 03:15:08 AM,
:P 2004-2005 filibeto.org, site statistics