Securing Hosts with IP FilterBy 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.
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
modloadcommand. 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,
ipnatallows 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
ipnatby 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.
ipfstattakes 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
iptestagainst 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
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/makeand 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
/usr/sbin/sparcv9and links their counterparts in
/usr/lib/isaexecfor ease of use. The loadable kernel modules reside in
/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
After creating the package, add it to each desired host with the
pkgaddcommand: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.
IP Filter configuration rules reside in the files
/etc/opt/ipf/ipnat.conffor NAT and
/etc/opt/ipf/ipf.conffor filtering. If
/etc/init.d/ipfbootstartup script will run
ipnat, and if
/etc/opt/ipf/ipf.confexists, the script will run
ipf. The two files are independent of each other, and
ipnatmay be run singly or together on any given machine.
ipnatprovides 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.confto 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
ipnatrulesets is described in BNF notation in the
ipnat(5) man page. The grammar listed is incomplete and outdated, but the use of
ipnatis 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
ipnatdetermines 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.conffile with the
bimapdirective. 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
rdrdirective 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
ipnatdirectives can be found in the
ipnat(5)man page and in the ipf HOWTO document.
/etc/opt/ipf/ipf.conffile 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
logaction. If more than one qualifier is used, they must be specified in the following order:
body- Log the first 128 bytes of the packet contents after logging the headers.
first- If being used in conjunction with the
keepoption (described below), log only the first packet in the session and ignore other packets sharing the state information.
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
- 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
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
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:
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:
log- Log the packet if this rule is the last that matches. The qualifiers mentioned above in the description of the
logaction may also be specified here under the
quick- If the packet matches this rule, stop processing the packet and take whatever action this rule lists.
on <iface>- Make the rule apply only to the specified interface.
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.
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.
tos- Filter based on the packet's Type Of Service. The TOS mask can be expressed as a hexadecimal or decimal number.
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.
proto- Filter based on the packet's protocol. Protocol names listed in
/etc/protocolsor the decimal number of the protocol may be used.
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
anywhich matches all. Ports can be specified by name as listed in
/etc/services, or by decimal number.
with- Filter based on the listed IP option. The
withparameter may be prepended with the
nooptions to indicate that the rule should match only if the listed option is not present.
flags- Filter based on the listed TCP flag. The
flagsparameter is therefore only useful with TCP rules. The list of possible options to the
These options can be ANDed together and masked to produce various combinations. For example,
- F - FIN
- S - SYN
- R - RST
- P - PUSH
- A - ACK
- U - URG
flags SA/AUPRFSCand will match and packet with only the SYN and ACK flags set. On the other hand, specifying
flags S/SAwill only match a packet with just the SYN flag set out of the SYN-ACK pair.
icmp-type- Filter based on the ICMP type. This parameter should only be used when
proto icmpis specified and should not be used in conjunction with
keep state- Keep information about the session to which the packet is attached. State can be kept for TCP, UDP, and ICMP packets.
keep frags- Keep information about fragmented packets to later apply to other fragments.
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 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.
group <number>- Add the rule to the group
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
ipmonprogram. Make sure that logging occurs for each rule that processes the packet in question.
The other useful debugging tools are
ipnatprogram provides NAT statistics as well as controlling the application or rulesets. If you are encountering a NAT issue, use
ipnat -v, and
ipnat -s. If the issue occurs with the filtering rules, the
ipfstatprogram provides a wealth of information about packet authentication, fragment information, per rule or protocol and overall statistics, state information, and a
toplike 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/systemmay prove useful (note that the timers run "two ticks to a second", so the 172800 ticks for
ipf:fr_tcpidletimeoutlisted 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 Sto 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/systemand 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/systemand 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
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