- Free Software Firewall Guide -

Specific Applications of IP Filter - Things that don't fit, but should be mentioned anyway.

Keep State With Servers and Flags

Keeping state is a good thing, but it's quite easy to make a mistake in the direction that you want to keep state in. Generally, you want to have a keep state keyword on the first rule that interacts with a packet for the connection. One common mistake that is made when mixing state tracking with filtering on flags is this:
block in all
pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S
pass out all keep state
That certainly appears to allow a connection to be created to the telnet server on 20.20.20.20, and the replies to go back. If you try using this rule, you'll see that it does work--Momentarily. Since we're filtering for the SYN flag, the state entry never fully gets completed, and the default time to live for an incomplete state is 60 seconds.
We can solve this by rewriting the rules in one of two ways:

1)
block in all
pass in quick proto tcp from any to 20.20.20.20/32 port = 23 keep state
block out all
or:
2)
block in all
pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S keep state
pass out all keep state
Either of these sets of rules will result in a fully established state entry for a connection to your server.

Coping With FTP

FTP is one of those protocols that you just have to sit back and ask "What the heck were they thinking?" FTP has many problems that the firewall administrator needs to deal with. What's worse, the problems the administrator must face are different between making ftp clients work and making ftp servers work.

Within the FTP protocol, there are two forms of data transfer, called active and passive. Active transfers are those where the server connects to an open port on the client to send data. Conversely, passive transfers are those where the client connects to the server to recieve data.

Running an FTP Server

In running an FTP server, handling Active FTP sessions is easy to setup. At the same time, handling Passive FTP sessions is a big problem. First we'll cover how to handle Active FTP, then move on to Passive. Generally, we can handle Active FTP sessions like we would an incoming HTTP or SMTP connection; just open the ftp port and let keep state do the rest:
pass in quick proto tcp from any to 20.20.20.20/32 port = 21 flags S keep state
pass out proto tcp all keep state
These rules will allow Active FTP sessions, the most common type, to your ftp server on 20.20.20.20.

The next challenge becomes handling Passive FTP connections. Web browsers default to this mode, so it's becoming quite popular and as such it should be supported. The problem with passive connections are that for every passive connection, the server starts listening on a new port (usually above 1023). This is essentially like creating a new unknown service on the server. Assuming we have a good firewall with a default-deny policy, that new service will be blocked, and thus Active FTP sessions are broken. Don't despair! There's hope yet to be had.

A person's first inclination to solving this problem might be to just open up all ports above 1023. In truth, this will work:
pass in quick proto tcp from any to 20.20.20.20/32 port > 1023 flags S keep state
pass out proto tcp all keep state
This is somewhat unsatisfactory, though. By letting everything above 1023 in, we actually open ourselves up for a number of potential problems. While 1-1023 is the designated area for server services to run, numerous programs decided to use numbers higher than 1023, such as nfsd and X.

The good news is that your FTP server gets to decide which ports get assigned to active sessions. This means that instead of opening all ports above 1023, you can allocate ports 15001-19999 as ftp ports and only open that range of your firewall up. In wu-ftpd, this is done with the passive ports option in ftpaccess. Please see the man page on ftpaccess for details in wu-ftpd configuration. On the ipfilter side, all we need do is setup corresponding rules:
pass in quick proto tcp from any to 20.20.20.20/32 port 15000 >< 20000 flags S keep state
pass out proto tcp all keep state
If even this solution doesn't satisfy you, you can always hack IPF support into your FTP server, or FTP server support into IPF.

Running an FTP Client

While FTP server support is still less than perfect in IPF, FTP client support has been working well since 3.3.3. As with FTP servers, there are two types of ftp client transfers: passive and active.

The simplest type of client transfer from the firewall's standpoint is the passive transfer. Assuming you're keeping state on all outbound tcp sessions, passive transfers will work already. If you're not doing this already, please consider the following:
pass out proto tcp all keep state
The second type of client transfer, active, is a bit more troublesome, but nonetheless a solved problem. Active transfers cause the server to open up a second connection back to the client for data to flow through. This is normally a problem when there's a firewall in the middle, stopping outside connections from coming back in. To solve this, ipfilter includes an ipnat proxy which temporarily opens up a hole in the firewall just for the FTP server to get back to the client. Even if you're not using ipnat to do nat, the proxy is still effective. The following rules is the bare minimum to add to the ipnat configuration file (ep0 should be the interface name of the outbound network connection):
map ep0 0/0 -> 0/32 proxy port 21 ftp/tcp
For more details on ipfilter's internal proxies, see section 3.6

Assorted Kernel Variables

There are some useful kernel tunes that either need to be set for ipf to function, or are just generally handy to know about for building firewalls. The first major one you must set is to enable IP Forwarding, otherwise ipf will do very little, as the underlying ip stack won't actually route packets.
IP Forwarding:

openbsd:
net.inet.ip.forwarding=1
freebsd:
net.inet.ip.forwarding=1
solaris:
ndd -set /dev/ip ip_forwarding 1
Ephemeral Port Adjustment:
openbsd:
net.inet.ip.portfirst = 25000
freebsd:
net.inet.ip.portrange.first = 25000 net.inet.ip.portrange.last = 49151
solaris:
ndd -set /dev/tcp tcp_smallest_anon_port 25000
ndd -set /dev/tcp tcp_largest_anon_port 65535
Other Useful Values:
openbsd:
net.inet.ip.sourceroute = 0
net.inet.ip.directed-broadcast = 0
freebsd:
net.inet.ip.sourceroute=0
net.ip.accept_sourceroute=0
solaris:
ndd -set /dev/ip ip_forward_directed_broadcasts 0
ndd -set /dev/ip ip_forward_src_routed 0
ndd -set /dev/ip ip_respond_to_echo_broadcast 0
In addition, freebsd has some ipf specific sysctl variables.
net.inet.ipf.fr_flags: 0
net.inet.ipf.fr_pass: 514
net.inet.ipf.fr_active: 0
net.inet.ipf.fr_tcpidletimeout: 864000
net.inet.ipf.fr_tcpclosewait: 60
net.inet.ipf.fr_tcplastack: 20
net.inet.ipf.fr_tcptimeout: 120
net.inet.ipf.fr_tcpclosed: 1
net.inet.ipf.fr_udptimeout: 120
net.inet.ipf.fr_icmptimeout: 120
net.inet.ipf.fr_defnatage: 1200
net.inet.ipf.fr_ipfrttl: 120
net.inet.ipf.ipl_unreach: 13
net.inet.ipf.ipl_inited: 1
net.inet.ipf.fr_authsize: 32
net.inet.ipf.fr_authused: 0
net.inet.ipf.fr_defaultauthage: 600

 
     << Previous section: Advanced firewalling