IPchains: Packet Filtering for Linux 2.2

When Linus released the 2.1.102 development kernel last May, people were surprised that the old packet filtering control program, Jos Vos's ipfwadm, no longer worked. Documentation of the change followed in 2.1.103.

When Linus released the 2.1.102 development kernel last May, people were
surprised that the old packet filtering control program, Jos Vos’s ipfwadm, no longer worked.
Documentation of the change followed in 2.1.103.

So, why did we change, other than to teach people the value of checking that their firewall
setup scripts will detect unexpected failures? There were several enhancements to the old ipfwadm
code which seemed logical to me, and would make setting up a Linux-based firewall simpler to
control, meaning fewer mistakes and wider usage of Linux’s packet filtering system.

What Is A Packet Filter?

To begin, we have to understand what a packet filter is, and why we would want one. All traffic
through a network is sent in the form of packets. For example, downloading an image (say it’s 50k
long) might cause you to receive 36 or so packets of 1460 bytes each.

The beginning of each packet says where it’s going, where it came from, the type of packet it
is, and gives a few other administrative details. This beginning of the packet is called the header.
The rest of the packet, containing the actual data being transmitted, is usually called the

Some protocols, like TCP, which is used for web traffic, mail, and remote logins, use the
concept of a connection — before any packets with actual data are sent, various setup packets (with
special headers) are exchanged saying “I want to connect”, “OK” and “Thanks”. Then normal
data-carrying packets are exchanged.

A packet filter is a piece of software which looks at the header of packets as they pass
through, and decides the fate of the entire packet. It might decide to “deny” the packet
(i.e.,discard the packet as if it had never received it), “accept” the packet (i.e.,let the packet
go through), or “reject” the packet (similar to “deny”, but it tells the machine that sent the
packet that it had been rejected).

Under Linux, packet filtering is built into the kernel, and there are a few trickier things we
can do with packets, but the general principle of looking at the headers and deciding the fate of
the packet is still there.

Most distributions (when they upgrade to the 2.2 kernel series) will probably give you a Linux
kernel with IP Firewalling enabled. If not, you will need to configure your kernel with Network
firewalls and IP: firewalling set to “Y”. If your kernel supports
ipchains, the file /proc/net/ ip_fwchains will exist.

How ipchains Deals With Packets

Figure 1: How packets travel through the Linux 2.2 kernel.

Figure 1 shows where packets which pass through the Linux machine will be passed to the ipchains
subsystem. The user adds rules into the ipchains system: each rule indicates which packets are to
match the rule (for example, all packets going to http//:www.watchguard.com), and what to do with a packet that matches
(e.g., drop the packet as if it was never received).

Rules are organized into three groups (called chains) initially: “input”, “forward” and
“output”. Which chain is used to decide the fate of the packet depends on where (shown in the
figure) the packet was intercepted. The “input” chain is used to control which packets come into the
box. The “forward” chain intercepts packets which come from one person and are destined for someone
else (implying that your machine is set up used as a router between multiple networks), and the
“output” chain examines packets leaving the box.

One of the innovations which the 2.2 kernel introduced is that the user can now create
additional chains. This can make it much easier to organize your rules in a logical manner and can
also make it easier to add and remove a set of rules as a group. Once you created a new chain, you
can create rules in the standard chains to “jump” to the new chain you just created.

Using the ipchains Tool

Let’s look at an example. Here’s a user who wants to set up a very simple firewall (too simple
to actually work, as we’ll see in a moment):

ipchains -N webok

This creates a new chain “webok”. The chain starts empty; no rules are in it, and so it won’t do
anything. So we add two rules:

ipchains -A webok -p TCP -d any/0 www -j ACCEPT

This appends a rule to the webok chain we just created (-A webok), which applies to any
packet of protocol TCP (-p TCP) destined for any IP address on port www (-d any/0
). The -j option says what to do with the matching packets; in this case,
ACCEPT them.

ipchains -A webok -p TCP -s  any/0 www ! -y -j ACCEPT

This rule allows TCP packets back which have a source port of www
(-s any/0 www), but the ! -y flag means not TCP SYN packets (in programming, it is
common to use ! to mean “not”). TCP SYN packets are the first packets used to create a TCP
connection, and you must create a connection before you can send other packets. By not allowing TCP
SYN packet to come in, we ensure that someone pretending to be a web server and attempting to make a
connection into our network would fail.

ipchains -A input -j webok

This rule appends a rule to the (builtin) input chain (-A input) which has no conditions (so it
will match every packet), and says to jump to the webok chain we created.

ipchains -P input DENY

This sets the “policy” of the input chain to DENY. This means that if there is no rule
telling ipchains what to do with the packet, the answer is DENY. This is usually regarded
as a secure approach: if in doubt, don’t let it through. In our case, if the one rule in the webok
chain is not matched, the kernel will go back to the input chain and resume applying the rules that
come after the webok jump. In this case there are no more rules after that, so the policy specifies
what to do with the packet.

There are numerous problems with this simple arrangement:

1) It blocks DNS queries. DNS queries are used to map names to IP addresses. For example, when
we enter “http://www.kernel.org” into the browser, it will look up the name to get the IP address,
then open a web connection to that address.

Even worse, since we specified DENYand not REJECT, the browser will not know
that the DNS packets are being discarded, and will keep retrying. If we use REJECT, an ICMP
“port unreachable” reply will be generated, and the browser can indicate to the user that something
is wrong.

So, we allow outgoing DNS queries to our nameserver, and replies. Usually DNS queries and
replies use a single UDP packet, but if DNS answers are really large, the client (the browser in the
above example) will use TCP. So we add rules to webok to allow this (see Figure 2).

Figure 2

ipchains -A webok -p UDP -d domain -j ACCEPT
ipchains -A webok -p UDP -s domain -j ACCEPT
ipchains -A webok -p TCP -d domain -j ACCEPT
ipchains -A webok -p TCP -s domain ! -y -j ACCEPT

2) It blocks ICMP packets. ICMP packets are the message runners of IP; it is a special protocol
used to report problems. As you can imagine, if these problem reports never get through, the system
doesn’t work all that well. In particular, type 3 packets (“Destination Unreachable”) should never
be blocked, because sometimes TCP relies on them to work at all. So we allow these:

ipchains -A webok -p  ICMP -s any/0  destination-unreachable

3) It treats problem packets with DENY rather than REJECT. It would be nice to
give some warning if your internal users try to do something abnormal, even if you don’t want to do
this for external users. The best way to do this is usually by deciding which network interface is
the internal one (for example, eth0, the first Ethernet card), and creating a final rule
which does a REJECT for packets coming from that interface:

ipchains -A input -i  eth0 -j REJECT

There are various other attributes you can packet filter by, but this introduction should be
sufficient for most people. A complete list is in the HOWTO.

Differences Between
ipfwadm and ipchains

Other differences between ipfwadm (2.0 kernel) and ipchains (2.2 kernel) are:

* Many arguments have been renamed: capitals now indicate a command, and lower case now
indicates an option.

* Arbitrary protocols over IP can be tested for, not just TCP, UDP and ICMP.

* Counters are now 64-bit on 32-bit machines, not 32-bit.

* ICMP codes are now supported.

* Wildcard interfaces are now supported.

* Inverse options are now supported.

* There are several other minor improvements, such as the existence of a comprehensive HOWTO for

Most Common Rules Required

* If no packets are passing your firewall at all, make sure you turned forwarding on (it’s off
by default):

echo 1 >/proc/sys/net/

* Remember that the -i flag has different meanings in different chains. For the input
chain, it’s the interface the packet just came in on. For the forward and output chains, it’s where
the packet will be leaving.

* Don’t forget the loopback interface lo. Local packets talking to other local programs
will go through the output chain, then the input chain, with interface set to -i lo both

* If ipchains -L freezes (it’s supposed to list the rules), try ipchains -L
. Maybe you’re blocking DNS queries?

* If you’re running MASQUERADING, do as much filtering as you can in your forward
chain. If you don’t know what masquerading is, don’t worry.

* Where possible, filter by what interface a packet is coming from or going to, rather than
source or destination address.

Other Linux Network
Security Features

There are two other items, unrelated to packet filtering, which you should know about because
they’re used to solve similar problems.

The first was introduced in 2.2: Source Address Verification. This is a simple check that the
Linux kernel can do to stop packets which claim to come from somewhere they aren’t.

For example, if your internal network has addresses 192.168.1.*, and is connected to the outside
world via a modem line, a packet coming in through the modem shouldn’t have a source address of
(say) It’s called IP Spoofing (pretending to be someone you’re not), and if you packet
filter based on IP address, such a packet might get through your firewall!

Source Address Verification asks, “Where would I send a reply to this packet?”. If the answer is
not the same network interface as the one the packet came in on, the packet is dropped. This feature
is not on by default, as it is possible to have a network arrangement where we want packets to come
in one way and go out another. For most of us, however, this is not the case, so we want to turn
Source Address Verification on. To turn it on, as root do:

echo 1 >

Or you can simply do

echo 1 >

before any network devices are enabled. Debian does this now at boot time.

The second security feature is “tcp wrappers”, which are a topic in themselves. TCP wrappers
only protect applications running on the machine itself, but are very useful for that. All Linux
distributions I know of use TCP wrappers by default: what is allowed and disallowed is controlled by

the files /etc/hosts.allow and /etc/hosts.deny. See man tcpd for more

Other Resources

* The ipchains Homepage:

* The ipchains HOWTO: 3000-lines of thorough instructions, available at the above URL.

* The ipchains Mailing List: Send the word “subscribe” to ipchains-request@rustcorp.com

Paul “Rusty” Russell is now paid by WatchGuard to maintain the current Linux packet filter code
and develop cool new GPL networky stuff for the Linux Kernel while spending the money WatchGuard
sends. He can be reached at paul.russell@rustcorp.com.au.

Comments are closed.