This question requires some thought. You can try to organize them to
optimize speed (minimize the number of rule-checks for the most common
packets) or to increase manageability.

If you have an intermittent link, say a PPP link, you might want to
set the first rule in the input chain to be set to `-i ppp0 -j DENY' at
boot time, then have something like this in your ip-up script:

There are some things you should be aware of before you start
filtering out everything you don't want.

ICMP packets

ICMP packets are used (among other things) to indicate failure for
other protocols (such as TCP and UDP). `destination-unreachable'
packets in particular. Blocking these packets means that you will
never get `Host unreachable' or `No route to host' errors; any
connections will just wait for a reply that never comes. This is
irritating, but rarely fatal.

A worse problem is the role of ICMP packets in MTU discovery. All
good TCP implementations (Linux included) use MTU discovery to try to
figure out what the largest packet that can get to a destination
without being fragmented (fragmentation slows performance, especially
when occasional fragments are lost). MTU discovery works by sending
packets with the "Don't Fragment" bit set, and then sending smaller
packets if it gets an ICMP packet indicating "Fragmentation needed but
DF set" (`fragmentation-needed'). This is a type of
`destination-unreachable' packet, and if it is never received, the
local host will not reduce MTU, and performance will be abysmal or
non-existent.

Note that it is common to block all ICMP redirect messages (type 5);
these can be used to manipulate routing (although good IP stacks have
safeguards), and so are often seen as slightly risky.

TCP Connections to DNS (nameservers)

If you're trying to block outgoing TCP connections, remember that DNS
doesn't always use UDP; if the reply from the server exceeds 512
bytes, the client uses a TCP connection (still going to port number
53) to get the data.

This can be a trap because DNS will `mostly work' if you disallow such
TCP transfers; you may experience strange long delays and other
occasional DNS problems if you do.

If your DNS queries are always directed at the same external source
(either directly by using the nameserver line in
/etc/resolv.conf or by using a caching nameserver in forward
mode), then you need only allow TCP connections to port domain
on that nameserver from the local domain port (if using a caching
nameserver) or from a high port (> 1023) if using
/etc/resolv.conf.

FTP Nightmares

The classic packet filtering problem is FTP. FTP has two modes;
the traditional one is called active mode and the more recent one
is called passive mode. Web browsers usually default to passive
mode, but command-line FTP programs usually default to active mode.

In active mode, when the remote end wants to send a file (or even the
results of an ls or dir command) it tries to open a TCP
connection to the local machine. This means you can't filter out
these TCP connections without breaking active FTP.

If you have the option of using passive mode, then fine; passive mode
makes data connections from client to server, even for incoming data.
Otherwise, it is recommended that you only allow TCP connections to
ports above 1024 and not between 6000 and 6010 (6000 is used for
X-Windows).

Linux boxes are now immune to the famous Ping of Death, which
involves sending an illegally-large ICMP packet which overflows
buffers in the TCP stack on the receiver and causes havoc.

If you are protecting boxes which might be vulnerable, you could simply
block ICMP fragments. Normal ICMP packets aren't large enough to
require fragmentation, so you won't break anything except big pings.
I have heard (unconfirmed) reports that some systems required only the
last fragment of an oversize ICMP packet to corrupt them, so blocking
only the first fragment is not recommended.

While the exploit programs I have seen all use ICMP, there is no
reasons that TCP or UDP fragments (or an unknown protocol) could not
be used for this attack, so blocking ICMP fragments is only a
temporary solution.

Teardrop and Bonk are two attacks (mainly against Microsoft Windows NT
machines) which rely on overlapping fragments. Having your Linux
router do defragmentation, or disallowing all fragments to your
vulnerable machines are the other options.

Some less-reliable TCP stacks are said to have problems dealing with
large numbers of fragments of packets when they don't receive all the
fragments. Linux does not have this problem. You can filter out
fragments (which might break legitimate uses) or compile your kernel
with `IP: always defragment' set to `Y' (only if your Linux box is the
only possible route for these packets).

There are some timing issues involved in altering firewall rules. If
you are not careful, you can let packets through while you are
half-way through your changes. A simplistic approach is to do the
following:

If your changes are restricted to a single chain, you might want to
create a new chain with the new rules, and then replace (`-R') the
rule that pointed to the old chain with one that points to the new
chain: then you can delete the old chain. This replacement will occur
atomically.

IP spoofing is a technique where a host sends out packets which claim
to be from another host. Since packet filtering makes decisions based
on this source address, IP spoofing is uses to fool packet filters.
It is also used to hide the identity of attackers using SYN attacks,
Teardrop, Ping of Death and the like (don't worry if you don't know
what they are).

The best way to protect from IP spoofing is called Source Address
Verification, and it is done by the routing code, and not firewalling
at all. Look for a file called
/proc/sys/net/ipv4/conf/all/rp_filter. If this exists, then
turning on Source Address Verification at every boot is the right
solution for you. To do that, insert the following lines somewhere in
your init scripts, before any network interfaces are initialized:

# This is the best method: turn on Source Address Verification and get
# spoof protection on all current and future interfaces.
if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ]; then
echo -n "Setting up IP spoofing protection..."
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo 1 > $f
done
echo "done."
else
echo PROBLEMS SETTING UP IP SPOOFING PROTECTION. BE WORRIED.
echo "CONTROL-D will exit from this shell and continue system startup."
echo
# Start a single user shell on the console
/sbin/sulogin $CONSOLE
fi

If you cannot do this, you can manually insert rules to protect every
interface. This requires knowledge of each interface. The 2.1
kernels automatically reject packets claiming to come from the 127.*
addresses (reserved for the local loopback interface, lo).

For example, say we have three interfaces, eth0, eth1 and
ppp0. We can use ifconfig to tell us the address and
netmask of the interfaces. Say eth0 was attached to a network
192.168.1.0 with netmask 255.255.255.0, eth1 was attached to a
network 10.0.0.0 with netmask 255.0.0.0, and ppp0 connected to
the Internet (where any address except the reserved private IP
addresses are allowed), we would insert the following rules:

There is a userspace library I have written which is included with the
source distribution called `libfw'. It uses the ability of IP Chains
1.3 and above to copy a packet to userspace (using the
IP_FIREWALL_NETLINK config option).

The mark value can be used to specify the Quality of Service
parameters for packets, or to specify how packets should be
port-forwarded. I've never used either, but if you want to write
about it, please contact me.

Things such as stateful inspection (I prefer the term
dynamic firewalling) can be implemented in userspace using this
library. Other nifty ideas include controlling packets on a per-user
basis by doing a lookup in a userspace daemon. This should be pretty
easy.

SPF: Stateful Packet Filtering

ftp://ftp.interlinx.bc.ca/pub/spf is the site of Brian
Murrell's SPF project, which does connection tracking in userspace.
It adds significant security for low-bandwidth sites.

There's little documentation at present, but here's a post to the
mailing list in which Brian answered some questions:

> I believe it does exactly what I want: Installing a temporary
> "backward"-rule to let packets in as a response to an
> outgoing request.
Yup, that is exactly what it does. The more protocols it
understands, the more "backward" rules it gets right. Right
now it has support for (from memory, please excuse any errors
or omissions) FTP (both active and passive, in and out), some
RealAudio, traceroute, ICMP and basic ICQ (inbound from the ICQ
servers, and direct TCP connections, but alas the secondary
direct TCP connections for things like file transfer, etc. are
not there yet)
> Is it a replacement for ipchains or a supplement?
It is a supplement. Think of ipchains as the engine to allow
and prevent packets from travelling across a Linux box. SPF is
the driver, constantly monitoring traffic and telling ipchains
how to change it's policies to reflect the changes in traffic
patterns.

Michael Hasenstein's ftp-data hack

Firewalling and NAT have being redesigned for 2.4. Plans and
discussions are available on the netfilter list (see
http://lists.samba.org). These
enhancements should clear up many outstanding usability issues
(really, firewalling and masquerading shouldn't be this
hard), and allow growth for far more flexible firewalling.