While developing IP Firewall Chains, Paul Russell decided that IP firewalling
should be less difficult; he soon set about the task of simplifying aspects of
datagram processing in the kernel firewalling code and produced a filtering
framework that was both much cleaner and much more flexible. He called
this new framework netfilter.
Note: At the time of preparation of this book the
netfilter design had not yet stabilized. We hope
you'll forgive any errors in the description of
netfilter or its associated configuration tools
that result from changes that occurred after preparation of this
material. We considered the netfilter work
important enough to justify the inclusion of this material, despite
parts of it being speculative in nature. If you're in any doubt, the
relevant HOWTO documents will contain the most accurate and up-to-date
information on the detailed issues associated with the
netfilter configuration.
So what was wrong with IP chains? They vastly improved the efficiency
and management of firewall rules. But the way they processed datagrams
was still complex, especially in conjunction with firewall-related
features like IP masquerade (discussed in Chapter 11) and other forms of address
translation. Part of this complexity existed because IP masquerade and
Network Address Translation were developed independently of the IP
firewalling code and integrated later, rather than having been
designed as a true part of the firewall code from the start. If a
developer wanted to add yet more features in the datagram processing
sequence, he would have had difficulty finding a place to insert the
code and would have been forced to make changes in the kernel in order
to do so.
Still, there were other problems. In particular, the
“input” chain described input to the IP networking layer
as a whole. The input chain affected both datagrams to be
destined for this host and datagrams to be
routed by this host. This was somewhat
counterintuitive because it confused the function of the input chain
with that of the forward chain, which applied only to datagrams to be
forwarded, but which always followed the input chain. If you wanted to
treat datagrams for this host differently from datagrams to be
forwarded, it was necessary to build complex rules that excluded one
or the other. The same problem applied to the output chain.
Inevitably some of this complexity spilled over into the system
administrator's job because it was reflected in the way that rulesets
had to be designed. Moreover, any extensions to filtering required
direct modifications to the kernel, because all filtering policies
were implemented there and there was no way of providing a transparent
interface into it. netfilter addresses both the
complexity and the rigidity of older solutions by implementing a
generic framework in the kernel that streamlines the way datagrams are
processed and provides a capability to extend filtering policy without
having to modify the kernel.
Let's take a look at two of the key changes made. Figure 9-8 illustrates how datagrams
are processed in the IP chains implementation, while Figure 9-9 illustrates how they are
processed in the netfilter implementation. The
key differences are the removal of the masquerading function from the
core code and a change in the locations of the input and output
chains. To accompany these changes, a new and extensible configuration
tool called iptables was created.
In IP chains, the input chain applies to all datagrams received by the
host, irrespective of whether they are destined for the local host or routed to some other host. In netfilter,
the input chain applies only to datagrams
destined for the local host, and the forward chain applies only to
datagrams destined for another host. Similarly,
in IP chains, the output chain applies to all datagrams leaving the
local host, irrespective of whether the datagram is generated on the
local host or routed from some other host. In
netfilter, the output chain applies
only to datagrams generated on this host and does
not apply to datagrams being routed from another host. This change
alone offers a huge simplification of many firewall configurations.
In Figure 9-8, the components
labeled “demasq” and “masq” are separate
kernel components responsible for the incoming and outgoing processing
of masqueraded datagrams. These have been reimplemented as
netfilter modules.
Consider the case of a configuration for which the default policy for each
of the input, forward, and output chains is
deny. In IP chains, six rules would
be needed to allow any session through a firewall host: two each in
the input, forward, and output chains (one would cover each forward
path and one would cover each return path). You can imagine how this
could easily become extremely complex and difficult to manage when you
want to mix sessions that could be routed and sessions that could
connect to the local host without being routed. IP chains allow
you to create chains that would simplify this task a little, but the
design isn't obvious and requires a certain level of expertise.
In the netfilter implementation with
iptables, this complexity disappears
completely. For a service to be routed across the firewall host, but
not terminate on the local host, only two rules are required: one
each for the forward and the reverse directions in the forward
chain. This is the obvious way to design firewalling rules, and will
serve to simplify the design of firewall configurations immensely.
The PACKET-FILTERING-HOWTO offers a detailed list of the
changes that have been made, so let's focus on the more practical
aspects here.
The remarkable flexibility of Linux netfilter is
illustrated by its ability to emulate the ipfwadm and
ipchains interfaces. Emulation makes transition to the new
generation of firewall software a little easier.
The two netfilter kernel modules called
ipfwadm.o and ipchains.o
provide backward compatibility for ipfwadm and
ipchains. You may load only one of these modules at
a time, and use one only if the ip_tables.o
module is not loaded. When the appropriate module is loaded,
netfilter works exactly like the former
firewall implementation.
netfilter mimics the
ipchains interface with the following commands:
rmmod ip_tables
modprobe ipchains
ipchains ... |
The iptables utility is used to configure
netfilter filtering rules. Its syntax borrows
heavily from the ipchains command, but differs in
one very significant respect: it is
extensible. What this means is that its
functionality can be extended without recompiling it. It manages this
trick by using shared libraries. There are standard extensions
and we'll explore some of them in a moment.
Before you can use the iptables command, you must
load the netfilter kernel module that provides
support for it. The easiest way to do this is to use the
modprobe command as follows:
The iptables command is used to configure both IP
filtering and Network Address Translation. To facilitate this, there are two
tables of rules called filter and
nat. The filter table is assumed if you do not
specify the -t option to override
it. Five built-in chains are also provided. The
INPUT and FORWARD chains are
available for the filter table, the
PREROUTING and POSTROUTING
chains are available for the nat table, and the
OUTPUT chain is available for both tables. In this
chapter we'll discuss only the filter table. We'll look
at the nat table in Chapter 11
The general syntax of most iptables commands is:
iptables command rule-specification extensions |
Now we'll take a look at some options in detail, after which we'll review
some examples.
There are a number of ways we can manipulate rules and rulesets with the
iptables command. Those relevant to IP firewalling are:
- -A chain
Append one or more rules to the end of the nominated chain. If a hostname is
supplied as either a source or destination and it resolves to more than one IP
address, a rule will be added for each address.
- -I chain rulenum
Insert one or more rules to the start of the nominated chain. Again, if a
hostname is supplied in the rule specification, a rule will be added for each
of the addresses to which it resolves.
- -D chain
Delete one or more rules from the specified chain matching the rule
specification.
- -D chain rulenum
Delete the rule residing at position rulenum in the
specified chain. Rule positions start at 1 for the first rule in the chain.
- -R chain rulenum
Replace the rule residing at position rulenum
in the specific chain with the supplied rule specification.
- -C chain
Check the datagram described by the rule specification against the specific
chain. This command will return a message describing how the chain processed the datagram. This is very useful for testing your firewall
configuration and we will look at it in detail later.
- -L [chain]
List the rules of the specified chain, or for all chains if no chain is
specified.
- -F [chain]
Flush the rules of the specified chain, or for all chains if no chain is
specified.
- -Z [chain]
Zero the datagram and byte counters for all rules of the specified chain, or
for all chains if no chain is specified.
- -N chain
Create a new chain with the specified name. A chain of the same name must not
already exist. This is how user-defined chains are created.
- -X [chain]
Delete the specified user-defined chain, or all user-defined chains if no chain
is specified. For this command to be successful, there must be no references
to the specified chain from any other rules chain.
- -P chain policy
Set the default policy of the specified chain to the specified policy. Valid
firewalling policies are ACCEPT, DROP,
QUEUE, and RETURN.
ACCEPT allows the datagram to pass. DROP
causes the datagram to be discarded. QUEUE causes the
datagram to be passed to userspace for further processing. The
RETURN target causes the IP firewall code to return to the
Firewall Chain that called the one containing this rule, and continue starting
at the rule after the calling rule.
There are a number of iptables parameters that constitute
a rule specification. Wherever a rule specification is required, each of these
parameters must be supplied or their default will be assumed.
- -p [!]protocol
Specifies the protocol of the datagram that will match this rule. Valid
protocol names are tcp, udp,
icmp, or a number, if you know the IP protocol
number.[1]
For example, you might use 4 to match the
ipip encapsulation protocol. If the !
character is supplied, the rule is negated and the datagram will match any
protocol other than the specified protocol. If this parameter isn't supplied, it
will default to match all protocols.
- -s [!]address[/mask]
Specifies the source address of the datagram that will match this rule. The
address may be supplied as a hostname, a network name, or an IP address. The
optional mask is the netmask to use and may be supplied
either in the traditional form (e.g., /255.255.255.0) or in the modern form
(e.g., /24).
- -d [!]address[/mask]
Specifies the destination address and port of the datagram that will
match this rule. The coding of this parameter is the same as that of the
-s parameter.
- -j target
Specifies what action to take when this rule matches. You can think of
this parameter as meaning “jump to.” Valid targets are
ACCEPT, DROP, QUEUE,
and RETURN. We described the meanings of each of these previously in the "Commands" section. You may also specify the name of a user-defined chain where
processing will continue. You may also supply the name of a target supplied
by an extension. We'll talk about extensions shortly. If this parameter is
omitted, no action is taken on matching datagrams at all, other than to
update the datagram and byte counters of this rule.
- -i [!]interface-name
Specifies the interface on which the datagram was received. Again, the
! inverts the result of the match. If the interface name
ends with “+” then any interface that begins
with the supplied string will match. For example, -i ppp+
would match any PPP network device and -i ! eth+ would
match all interfaces except ethernet devices.
- -o [!]interface-name
Specifies the interface on which the datagram is to be transmitted. This
argument has the same coding as the -i argument.
- [!] -f
Specifies that this rule applies only to the second and later fragments
of a fragmented datagram, not to the first fragment.
The following iptables options are more general in nature.
Some of them control rather esoteric features of the
netfilter software.
- -v
causes iptables to be verbose in its output; it
will supply more information.
- -n
causes iptables to display IP address and ports as
numbers without attempting to resolve them to their corresponding names.
- -x
causes any numbers in the iptables output to be
expanded to their exact values with no rounding.
- - -line-numbers
causes line numbers to be displayed when listing rulesets. The line number
will correspond to the rule's position within the chain.
We said earlier that the iptables utility is
extensible through optional shared library modules. There are some standard
extensions that provide some of the features ipchains
provided. To make use of an extension, you must specify its name through the
-m name argument to
iptables. The following list shows the
-m and -p options that set up the extension's
context, and the options provided by
that extension.
- - -sport [!] [port[:port]]
Specifies the port that the datagram source must be using to match this rule.
Ports may be specified as a range by specifying the upper and lower limits of
the range using the colon as a delimiter. For example, 20:25
described all of the ports numbered 20 up to and including 25. Again, the
! character may be used to negate the values.
- - -dport [!] [port[:port]]
Specifies the port that the datagram destination must be using to match this
rule. The argument is coded identically to the - -sport
option.
- - -tcp-flags [!] mask comp
Specifies that this rule should match when the TCP flags in the
datagram match those specified by mask and
comp. mask is a
comma-separated list of flags that should be examined when making the
test. comp is a comma-separated list of
flags that must be set for the rule to match. Valid flags are:
SYN, ACK,
FIN, RST,
URG, PSH, ALL
or NONE. This is an advanced option: refer to a
good description of the TCP protocol, such as RFC-793, for a
description of the meaning and implication of each of these flags.
The ! character negates the rule.
- [!] - -syn
Specifies the rule to match only datagrams with the
SYN bit set and the ACK and
FIN bits cleared. Datagrams with these options are used
to open TCP connections, and this option can therefore be used to manage
connection requests. This option is shorthand for:
- -tcp-flags SYN,RST,ACK SYN |
When you use the negation
operator, the rule will match all datagrams that do not have both the
SYN and ACK bits set.
- - -sport [!] [port[:port]]
Specifies the port that the datagram source must be using to match this rule.
Ports may be specified as a range by specifying the upper and lower limits of
the range using the colon as a delimiter. For example, 20:25
describes all of the ports numbered 20 up to and including 25. Again, the
! character may be used to negate the values.
- - -dport [!] [port[:port]]
Specifies the port that the datagram destination must be using to match this
rule. The argument is coded identically to the - -sport
option.
- - -icmp-type [!] typename
Specifies the ICMP message type that this rule will match. The type may be
specified by number or name. Some valid names are:
echo-request, echo-reply,
source-quench, time-exceeded,
destination-unreachable,
network-unreachable, host-unreachable,
protocol-unreachable, and
port-unreachable.
- - -mac-source [!] address
Specifies the host's Ethernet address that transmitted the datagram
that this rule will match. This only makes sense in a rule in the input or
forward chains because we will be transmitting any datagram that passes the
output chain.
To implement our na�ve example using the netfilter,
you could simply load the ipchains.o module and pretend
it is the ipchains version. Instead, we'll reimplement
it using iptables to illustrate how similar it is.
Yet again, let's suppose that we have a network in our organization
and that we are using a Linux-based firewall machine to allow our
users to be able to access WWW servers on the Internet, but to allow
no other traffic to be passed.
If our network has a 24-bit network mask (class C) and has an address of
172.16.1.0, then we'd use the following iptables rules:
# modprobe ip_tables
# iptables -F FORWARD
# iptables -P FORWARD DROP
# iptables -A FORWARD -m tcp -p tcp -s 0/0 --sport 80 -d 172.16.1.0/24 /
--syn -j DROP
# iptables -A FORWARD -m tcp -p tcp -s 172.16.1.0/24 --sport /
80 -d 0/0 -j ACCEPT
# iptables -A FORWARD -m tcp -p tcp -d 172.16.1.0/24 --dport 80 -s 0/0 -j /
ACCEPT |
In this example the iptables commands are interpreted
exactly as the equivalent ipchains commands. The major
exception that the ip_tables.o
module must load. Note that iptables doesn't support the
-b option, so we must supply a rule for each
direction.