LDP/LDP/guide/docbook/nag2/ch09.sgm

3574 lines
136 KiB
Plaintext

<chapter id="X-087-2-firewall"><title>TCP/IP Firewall</title>
<indexterm id="chfw.tcp.ip.firewall" class="startofrange"><primary>TCP/IP (Transmission Control Protocol/Internet Protocol)</primary><secondary>firewalls</secondary></indexterm>
<INDEXTERM id="chfw.firewalls.tcp.ip" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>TCP/IP</SECONDARY></INDEXTERM>
<para>
<indexterm><primary>firewalls</primary><secondary>security</secondary></indexterm>
<indexterm><primary>security</primary><secondary>network</secondary></indexterm>
<indexterm><primary>security</primary><secondary>firewalls</secondary></indexterm>
Security is increasingly important for companies and individuals alike.
The Internet has provided them with a powerful tool to distribute information
about themselves and obtain information from others, but it has
also exposed them to dangers that they have previously been exempt from.
Computer crime, information theft, and malicious damage are all potential
dangers.
</para>
<para>
An unauthorized and unscrupulous person who gains access to
a computer system may guess system passwords or
exploit the bugs and idiosyncratic behavior of certain programs to obtain
a working account on that machine. Once they are able to log in to the
machine, they may have access to information that may be damaging, such as
commercially sensitive information like marketing plans,
new project details, or customer information databases. Damaging or modifying
this type of data can cause severe setbacks to the company.
</para>
<para>
The safest way to avoid such widespread damage is to prevent unauthorized
people from gaining network access to the machine. This is where firewalls
come in.
</para>
<warning><para>
<indexterm><primary>firewalls</primary><secondary>warning</secondary></indexterm>
Constructing secure firewalls is an art. It involves a good understanding
of technology, but equally important, it requires an understanding
of the philosophy behind firewall designs. We won't cover
everything you need to know in this book; we strongly recommend you
do some additional research before trusting any particular firewall design,
including any we present here.
</para></warning>
<para>
There is enough material on firewall configuration and design
to fill a whole book, and indeed there are some good resources that you might
like to read to expand your knowledge on the subject. Two of these are:
<?troff .Nd 10>
<variablelist>
<varlistentry>
<term><emphasis>Building Internet Firewalls</emphasis></term>
<listitem><para>
by D. Chapman and E. Zwicky (O'Reilly). A guide
explaining how to design and install firewalls for Unix, Linux, and
Windows NT, and how to configure Internet services to work with the
firewalls.
</para></listitem>
</varlistentry>
<varlistentry>
<term><emphasis>Firewalls and Internet Security</emphasis></term>
<listitem><para>
by W. Cheswick and S. Bellovin (Addison Wesley). This book covers the
philosophy of firewall design and implementation.
</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>
We will focus on the Linux-specific technical issues in this chapter. Later
we will present a sample firewall configuration that should serve as a useful
starting point in your own configuration, but as with all security-related
matters, trust no one. Double check the design, make sure you understand it,
and then modify it to suit your requirements. To be safe, be sure.
</para>
<sect1 id="x-082-2-firewall.attacks"><title>Methods of Attack</title>
<para>
<indexterm><primary>firewalls</primary><secondary>methods of attack</secondary></indexterm>
<indexterm><primary>security</primary><secondary>methods of attack</secondary></indexterm>
As a network administrator, it is important that you understand the nature of
potential attacks on computer security. We'll briefly
describe the most important types of attacks so that you can better understand
precisely what the Linux IP firewall will protect you against. You should do
some additional reading to ensure that you are able to protect your
network against other types of attacks. Here
are some of the more important methods of attack and ways of protecting
yourself against them:
</para>
<variablelist>
<varlistentry><term>Unauthorized access</term>
<listitem><para>
This simply means that people who shouldn't use your computer services are
able to connect and
use them. For example, people outside your company might try to
connect to your company accounting machine or to your NFS server.
</para>
<para>
There are various ways to avoid this attack by carefully specifying who
can gain access through these services. You can prevent network access
to all except the intended users.
</para></listitem>
</varlistentry>
<varlistentry><term>Exploitation of known weaknesses in programs</term>
<listitem><para>
Some programs and network services were not originally designed with strong
security in mind and are inherently vulnerable to attack. The BSD remote
services (rlogin, rexec, etc.) are an example.
</para>
<para>
The best way to protect yourself against this type of attack is to disable
any vulnerable services or find alternatives. With Open Source, it is
sometimes possible to repair the weaknesses in the software.
</para></listitem>
</varlistentry>
<varlistentry><term>Denial of service</term>
<listitem><para>
<INDEXTERM><PRIMARY>denial of service attacks</PRIMARY></INDEXTERM>
Denial of service attacks cause the service or program to cease functioning or
prevent others from making use of the service or program. These may be
performed at the network layer by sending carefully crafted and malicious
datagrams that cause network connections to fail. They may also be performed
at the application layer, where carefully crafted application commands are
given to a program that cause it to become extremely busy or stop functioning.
</para>
<para>
Preventing suspicious network traffic from reaching your hosts and preventing
suspicious program commands and requests are the best ways of minimizing the
risk of a denial of service attack. It's useful to know the details of the
attack method, so you should educate yourself about each new attack as it
gets publicized.
</para></listitem>
</varlistentry>
<varlistentry><term>Spoofing</term>
<listitem><para>
<INDEXTERM><PRIMARY>spoofing</PRIMARY><SECONDARY>attacks</SECONDARY></INDEXTERM>
This type of attack causes a host or application to mimic the
actions of another. Typically the attacker pretends to be an innocent host
by following IP addresses in network packets. For example, a
well-documented exploit of the BSD rlogin service can use this method to mimic a
TCP connection from another host by guessing TCP sequence numbers.
</para>
<para>
To protect against this type of attack, verify the authenticity of datagrams
and commands. Prevent datagram routing with invalid source addresses.
Introduce unpredictablility into connection control mechanisms, such as TCP
sequence numbers and the allocation of dynamic port addresses.
</para></listitem>
</varlistentry>
<varlistentry><term>Eavesdropping</term>
<listitem><para>
<INDEXTERM><PRIMARY>eavesdropping programs</PRIMARY></INDEXTERM>
This is the simplest type of attack. A host is configured to "listen" to and
capture data not belonging to it. Carefully written eavesdropping programs
can take usernames and passwords from user login network connections.
Broadcast networks like Ethernet are especially vulnerable to this type of
attack.
</para>
<para>
To protect against this type of threat, avoid use of broadcast
network technologies and enforce the use of data encryption.
</para></listitem>
</varlistentry>
</variablelist>
<para>
IP firewalling is very useful in preventing or reducing unauthorized access,
network layer denial of service, and IP spoofing attacks. It not very useful
in avoiding exploitation of weaknesses in network services or programs and
eavesdropping.
</para>
</sect1>
<sect1 id="X-087-2-firewall.introduction"><title>What Is a Firewall?</title>
<para>
<indexterm><primary>firewalls</primary></indexterm>
A firewall is a secure and trusted machine that sits between a private
network and a public network.<footnote id="X-087-2-FW-FN01"><para> The
term <emphasis>firewall</emphasis> comes from a device used to protect
people from fire. The firewall is a shield of material resistant to
fire that is placed between a potential fire and the people it is
protecting.
</para>
</footnote>
The firewall machine is configured with a set of rules that determine
which network traffic will be allowed to pass and which will be blocked
or refused. In some large organizations, you may even find a firewall
located inside their corporate network to segregate sensitive areas
of the organization from other employees. Many cases of computer
crime occur from within an organization, not just from outside.
</para>
<para>
Firewalls can be constructed in quite a variety of ways. The most
sophisticated arrangement involves a number of separate machines and
is known as a <emphasis>perimeter network</emphasis>. Two machines act
as "filters" called chokes to allow only certain types of network
traffic to pass, and between these chokes reside network servers such as a
mail gateway or a World Wide Web proxy server. This configuration can
be very safe and easily allows quite a great range of control over who
can connect both from the inside to the outside, and from the outside
to the inside. This sort of configuration might be used by large
organizations.
</para>
<para>
Typically though, firewalls are single machines that serve all of these
functions. These are a little less secure, because if there is some
weakness in the firewall machine itself that allows people to gain access
to it, the whole network security has been breached. Nevertheless,
these types of firewalls are cheaper and easier to manage than the more
sophisticated arrangement just described.
<xref linkend="X-087-2-firewall.design.graphic"> illustrates the two most
common firewall configurations.</para>
<figure id="X-087-2-firewall.design.graphic" float=1>
<title>The two major classes of firewall design</title>
<!-- <graphic fileref="lag2_0901.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0901.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0901.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
The Linux kernel provides a range of built-in features that allow it
to function quite nicely as an IP firewall. The network implementation
includes code to do IP filtering in a number of different ways, and
provides a mechanism to quite accurately configure what sort of rules
you'd like to put in place. The Linux firewall is flexible enough to
make it very useful in either of the configurations illustrated in
<xref linkend="X-087-2-firewall.design.graphic">. Linux firewall
software provides two other useful features that we'll discuss in
separate chapters: IP Accounting (<xref
linkend="X-087-2-accounting">) and IP masquerade (<xref
linkend="X-087-2-ipmasq">).
</para>
</sect1>
<sect1 id="X-087-2-firewall.filtering"><title>What Is IP Filtering?</title>
<para>
<indexterm><primary>filtering</primary><secondary>IP</secondary></indexterm>
<indexterm><primary>IP (Internet Protocol)</primary><secondary>filtering</secondary></indexterm>
<indexterm><primary>security</primary><secondary>filtering</secondary></indexterm>
<INDEXTERM><PRIMARY>datagrams</PRIMARY><SECONDARY>IP filtering</SECONDARY></INDEXTERM>
IP filtering is simply a mechanism that decides which types of IP
datagrams will be processed normally and which will be discarded. By
<emphasis>discarded</emphasis> we mean that the datagram is deleted
and completely ignored, as if it had never been received. You can
apply many different sorts of criteria to determine which datagrams
you wish to filter; some examples of these are:
<itemizedlist>
<listitem><para>
Protocol type: TCP, UDP, ICMP, etc.
</para></listitem>
<listitem><para>
Socket number (for TCP/UPD)
</para></listitem>
<listitem><para>
Datagram type: SYN/ACK, data, ICMP Echo Request, etc.
</para></listitem>
<listitem><para>
Datagram source address: where it came from
</para></listitem>
<listitem><para>
Datagram destination address: where it is going to
</para></listitem>
</itemizedlist>
</para>
<para>
It is important to understand at this point that IP filtering is a
network layer facility. This means it doesn't understand anything
about the application using the network connections, only about the
connections themselves. For example, you may deny users access to your
internal network on the default telnet port, but if you rely on IP
filtering alone, you can't stop them from using the telnet program
with a port that you do allow to pass trhough your firewall. You can prevent
this sort of problem by using proxy servers for each service that you
allow across your firewall. The proxy servers understand the
application they were designed to proxy and can therefore prevent
abuses, such as using the telnet program to get past a firewall by
using the World Wide Web port. If your firewall supports a World Wide
Web proxy, their telnet connection will always be answered by the
proxy and will allow only HTTP requests to pass. A large number of
proxy-server programs exist. Some are free software and many others
are commercial products. The Firewall-HOWTO discusses one popular set
of these, but they are beyond the scope of this book.
</para>
<para>
The IP filtering ruleset is made up of many combinations of the criteria
listed previously. For example, let's imagine that you wanted to allow World
Wide Web users within the Virtual Brewery network to have no access to the
Internet except to use other sites' web servers. You would configure your
firewall
to allow forwarding of:
<itemizedlist>
<listitem><para>
datagrams with a source address on Virtual Brewery network, a destination
address of anywhere, and with a destination port of 80 (WWW)
</para></listitem>
<listitem><para>
datagrams with a destination address of Virtual Brewery network and a
source port of 80 (WWW) from a source address of anywhere
</para></listitem>
</itemizedlist>
</para>
<para>
Note that we've used two rules here. We have to allow our data to go out,
but also the corresponding reply data to come back in. In practice, as we'll
see shortly, Linux simplifies this and allows us to specify this in one
command.
</para>
</sect1>
<sect1 id="X-087-2-firewall.howto"><title>Setting Up Linux for Firewalling</title>
<para>
<INDEXTERM id="kernel.config.ipfirewall" class=startofrange><PRIMARY>kernels</PRIMARY><SECONDARY>configured with IP firewall</SECONDARY></INDEXTERM>
<INDEXTERM><PRIMARY>configuring</PRIMARY><SECONDARY>kernel</SECONDARY><TERTIARY SORTAS="IP firewall">with IP firewall</TERTIARY></INDEXTERM>
To build a Linux IP firewall, it is necessary to have a kernel built
with IP firewall support and the appropriate configuration utility. In
all production kernels prior to the 2.2 series, you would use the
<command>ipfwadm</command> utility. The 2.2.x kernels marked the
release of the third generation of IP firewall for Linux called
<emphasis>IP Chains</emphasis>. IP chains use a program similar to
<command>ipfwadm</command> called <command>ipchains</command>. Linux
kernels 2.3.15 and later support the fourth generation of Linux IP
firewall called <emphasis>netfilter</emphasis>. The
<emphasis>netfilter</emphasis> code is the result of a large redesign
of the packet handling flow in Linux. The
<emphasis>netfilter</emphasis> is a multifaceted creature, providing
direct backward-compatible support for both <command>ipfwadm</command>
and <command>ipchains</command> as well as a new alternative command
called <command>iptables</command>. We'll talk about the differences
between the three in the next few sections.
</para>
<sect2 id="X-087-2-firewall.howto.kernel"><title>Kernel Configured with IP Firewall</title>
<para>
The Linux kernel must be configured to support IP firewalling. There
isn't much more to it than selecting the appropriate options when
performing a <literal>make menuconfig</literal> of your
kernel.<footnote id="X-087-2-FW-FN02"><para> Firewall packet logging
is a special feature that writes a line of information about each
datagram that matches a particular firewall rule out to a special
device so you can see them.
</para>
</footnote>
We described how to do this is in
<xref linkend="X-087-2-hardware">&rdquo;.
In 2.2 kernels you should select the following options:
<screen width=80>
Networking options --->
[*] Network firewalls
[*] TCP/IP networking
[*] IP: firewalling
[*] IP: firewall packet logging
</screen>
</para>
<para>
In kernels 2.4.0 and later you should select this option instead:
<screen width=80>
Networking options --->
[*] Network packet filtering (replaces ipchains)
IP: Netfilter Configuration ---&gt;
.
&lt;M&gt; Userspace queueing via NETLINK (EXPERIMENTAL)
&lt;M&gt; IP tables support (required for filtering/masq/NAT)
&lt;M&gt; limit match support
&lt;M&gt; MAC address match support
&lt;M&gt; netfilter MARK match support
&lt;M&gt; Multiple port match support
&lt;M&gt; TOS match support
&lt;M&gt; Connection state match support
&lt;M&gt; Unclean match support (EXPERIMENTAL)
&lt;M&gt; Owner match support (EXPERIMENTAL)
&lt;M&gt; Packet filtering
&lt;M&gt; REJECT target support
&lt;M&gt; MIRROR target support (EXPERIMENTAL)
.
&lt;M&gt; Packet mangling
&lt;M&gt; TOS target support
&lt;M&gt; MARK target support
&lt;M&gt; LOG target support
&lt;M&gt; ipchains (2.2-style) support
&lt;M&gt; ipfwadm (2.0-style) support
</screen>
</para>
</sect2>
<sect2 id="X-087-2-firewall.howto.ipfwadm"><title>The ipfwadm Utility</title>
<para>
<indexterm><primary>ipfwadm command</primary></indexterm>
The <command>ipfwadm</command> (IP Firewall Administration) utility is the
tool used to build the firewall rules for all kernels prior to 2.2.0. Its
command syntax can be very confusing because it can do such a complicated
range of things, but we'll provide some common examples that will illustrate
the most important variations of these.
</para>
<para>
The <command>ipfwadm</command> utility is included in most
modern Linux distributions, but perhaps not by default. There may be a
specific software package for it that you have to install. If your
distribution does not include it, you can obtain the source package from
<systemitem role="sitename">ftp.xos.nl</systemitem> in the
<filename>/pub/linux/ipfwadm/</filename> directory, and compile it yourself.
</para>
</sect2>
<sect2 id="X-087-2-firewall.howto.ipchains"><title>The ipchains Utility</title>
<para>
<indexterm><primary>ipchains command</primary></indexterm>
Just as for the <command>ipfwadm</command> utility, the
<command>ipchains</command> utility can be somewhat baffling to use at first.
It provides all of the flexibility of <command>ipfwadm</command> with a
simplified command syntax, and additionally provides a &ldquo;chaining&rdquo; mechanism that allows you to manage multiple
rulesets and link them together. We'll cover rule chaining in a separate
section near the end of the chapter, because for most situations it is an
advanced concept.
</para>
<para>
<indexterm><primary>ipfwadm-wrapper command</primary></indexterm>
The <command>ipchains</command> command appears in most Linux
distributions based on the 2.2 kernels. If you want to compile it
yourself, you can find the source package from its developer's site at
<emphasis>http://www.rustcorp.com/linux/ipchains/</emphasis>.
Included in the source package is a wrapper script called
<command>ipfwadm-wrapper</command> that mimics the
<command>ipfwadm</command> command, but actually invokes the
<command>ipchains</command> command. Migration of an existing firewall
configuration is much more painless with this addition.
</para>
</sect2>
<sect2 id="X-087-2-firewall.howto.iptables"><title>The iptables Utility</title>
<para>
<indexterm><primary>iptables command</primary></indexterm>
The syntax of the <command>iptables</command> utility is quite similar to that
of the <command>ipchains</command> syntax. The changes are improvements and a
result of the tool being redesigned to be extensible through shared libraries.
Just as for <command>ipchains</command>, we'll present
<command>iptables</command> equivalents of the examples so you can compare
and contrast its syntax with the others.
</para>
<para>
The <command>iptables</command> utility is included in the
<emphasis>netfilter</emphasis> source package available at
<emphasis>http://www.samba.org/netfilter/</emphasis>. It will
also be included in any Linux distribution based on the 2.4 series kernels.
</para>
<para>
We'll talk a bit about <emphasis>netfilter</emphasis>'s huge step forward in a section of its own later in this chapter.
</para>
</sect2>
<INDEXTERM startref="kernel.config.ipfirewall" class=endofrange>
</sect1>
<sect1 id="X-087-2-firewall.filteringmethods"><title>Three Ways We Can Do Filtering</title>
<indexterm><primary>filtering</primary><secondary>stages of</secondary></indexterm>
<INDEXTERM><PRIMARY>datagrams</PRIMARY><SECONDARY>stages of processing</SECONDARY></INDEXTERM>
<para>
Consider how a Unix machine, or in fact any machine capable of IP routing,
processes IP datagrams. The basic steps, shown in <xref linkend="X-087-2-firewall.methods.graphic"> are:
</para>
<figure id="X-087-2-firewall.methods.graphic" float=1>
<title>The stages of IP datagram processing</title>
<!-- <graphic fileref="lag2_0902.jpg"> </graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0902.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0902.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<itemizedlist>
<listitem><para>
The IP datagram is received. (1)
</para></listitem>
<listitem><para>
The incoming IP datagram is examined to determine if it is destined for a
process on this machine.
</para></listitem>
<listitem><para>
If the datagram is for this machine, it is processed locally. (2)
</para></listitem>
<listitem><para>
If it is not destined for this machine, a search is made of the routing table
for an appropriate route and the datagram is forwarded to the appropriate
interface or dropped if no route can be found. (3)
</para></listitem>
<listitem><para>
Datagrams from local processes are sent to the routing software for forwarding
to the appropriate interface. (4)
</para></listitem>
<listitem><para>
The outgoing IP datagram is examined to determine if there is a valid route
for it to take, if not, it is dropped.
</para></listitem>
<listitem><para>
The IP datagram is transmitted. (5)
</para></listitem>
</itemizedlist>
<para>
In our diagram, the flow 1&rarr;3&rarr;5 represents our machine
routing data between a host on our Ethernet network to a host
reachable via our PPP link. The flows 1&rarr;2 and 4&rarr;5 represent
the data input and output flows of a network program running on our
local host. The flow 4&rarr;3&rarr;2 would represent data flow via a
loopback connection. Naturally data flows both into and out of network
devices. The question marks on the diagram represent the points where
the IP layer makes routing decisions.
</para>
<para>
The Linux kernel IP firewall is capable of applying filtering at various
stages in this process. That is, you can filter the IP datagrams that come in
to your machine, filter those datagrams being forwarded across your
machine, and filter those datagrams that are ready to be transmitted.
</para>
<para>
In <command>ipfwadm</command> and <command>ipchains</command>, an
Input rule applies to flow 1 on the diagram, a Forwarding rule to flow
3, and an Output rule to flow 5. We'll see when we discuss
<emphasis>netfilter</emphasis> later that the points of interception
have changed so that an Input rule is applied at flow 2, and an
Output rule is applied at flow 4. This has important implications for
how you structure your rulesets, but the general principle holds true
for all versions of Linux firewalling.
</para>
<para>
This may seem unnecessarily complicated at first, but it provides flexibility
that allows some very sophisticated and powerful configurations to be built.
</para>
</sect1>
<sect1 id="X-087-2-firewall.original"><title>Original IP Firewall (2.0 Kernels)</title>
<para>
<indexterm><primary>Cox, Alan</primary></indexterm>
<indexterm><primary>Vos, Jos</primary></indexterm>
<indexterm><primary>Middelink, Pauline</primary></indexterm>
<INDEXTERM id="original.firewall" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>original IP</SECONDARY></INDEXTERM>
<INDEXTERM id="Linux.2.0.kernels" class=startofrange><PRIMARY>2.0 kernels</PRIMARY><SECONDARY>IP firewalls</SECONDARY></INDEXTERM>
<INDEXTERM><PRIMARY>ipfwadm command</PRIMARY></INDEXTERM>
The first generation IP firewall support for Linux appeared in the 1.1
series kernel. It was a port of the BSD ipfw firewall support to Linux
by Alan Cox. The firewall support that appeared in the 2.0 series
kernels and is the second generation was enhanced by Jos Vos, Pauline
Middelink, and others.
</para>
<sect2 id="X-087-2-firewall.usingipfwadm"><title>Using ipfwadm</title>
<para>
The <command>ipfwadm</command> command was the configuration tool for the
second generation Linux IP firewall. Perhaps the simplest way to describe the
use of the <command>ipfwadm</command> command is by example. To begin, let's
code the example we presented earlier.
</para>
<sect3 id="X-087-2-firewall.simpleexample"><title>A na&iuml;ve example</title>
<para>
Let's suppose that we have a network in our organization and that we
are using a Linux-based firewall machine to connect our network to
the Internet. Additionally, let's suppose that we wish the users of
that network to be able to access web servers on the Internet, but to
allow no other traffic to be passed.
</para>
<para>
We will put in place a forwarding rule to allow datagrams with a source
address on our network and a destination socket of port 80 to be forwarded
out, and for the corresponding reply datagrams to be forwarded back via the
firewall.
</para>
<?troff .sp -1p>
<para>
Assume our network has a 24-bit network mask (Class C) and an address
of 172.16.1.0. The rules we might use are:
<screen>
<prompt>#</prompt> <userinput>ipfwadm -F -f</userinput>
<prompt>#</prompt> <userinput>ipfwadm -F -p deny</userinput>
<prompt>#</prompt> <userinput>ipfwadm -F -a accept -P tcp -S 172.16.1.0/24 -D 0/0 80</userinput>
<prompt>#</prompt> <userinput>ipfwadm -F -a accept -P tcp -S 0/0 80 -D 172.16.1.0/24</userinput>
</screen>
</para>
<para>
The <option>-F</option> command-line argument tells
<command>ipfwadm</command> that this is a forwarding rule.
The first command instructs <command>ipfwadm</command> to "flush" all
of the forwarding rules. This ensures we are working from a known
state before we begin adding specific rules.
</para>
<para>
The second rule sets our default forwarding policy. We
tell the kernel to deny or disallow forwarding of IP datagrams. It
is very important to set the default policy, because this describes what will
happen to any datagrams that are not specifically handled by any other
rule. In most firewall configurations, you will want to set your default
policy to "deny," as shown, to be sure that only the traffic you specifically
allow past your firewall is forwarded.
</para>
<para>
The third and fourth rules are the ones that implement our requirement.
The third command allows our datagrams out, and the fourth rule allows
the responses back.
</para>
<para>
Let's review each of the arguments:
<variablelist>
<varlistentry>
<term>-F</term>
<listitem><para>
This is a Forwarding rule.
</para></listitem>
</varlistentry>
<varlistentry><term>-a accept</term>
<listitem><para>
Append this rule with the policy set to "accept," meaning we will forward
any datagrams that match this rule.
</para></listitem>
</varlistentry>
<varlistentry><term>-P tcp</term>
<listitem><para>
This rule applies to tcp datagrams (as opposed to UDP or ICMP).
</para></listitem>
</varlistentry>
<varlistentry><term>-S 172.16.1.0/24</term>
<listitem><para>
The Source address must have the first 24 bits matching those of the
network address 172.16.1.0.
</para></listitem>
</varlistentry>
<varlistentry><term>-D 0/0 80</term>
<listitem><para>
The destination address must have zero bits matching the address 0.0.0.0.
This is really a shorthand notation for "anything." The 80 is the
destination port, in this case WWW. You may also use any entry that
appears in the <filename>/etc/services</filename> file to describe the
port, so <literal>-D 0/0 www</literal> would have worked just as well.
</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>
<command>ipfwadm</command> accepts network masks in a form with which you may
not be familiar. The <literal>/nn</literal> notation is a means of
describing how many bits of the supplied address are significant, or the
size of the mask. The bits are always counted from left to right;
some common examples are listed in <xref linkend="X-087-2-chfw-netmasks">.
</para>
<indexterm><primary>firewalls</primary><secondary>netmask specification</secondary></indexterm>
<table id="X-087-2-chfw-netmasks" tocentry=1>
<title>Common Netmask Bit Values</title>
<tgroup cols=2>
<thead>
<row><entry>Netmask</entry><entry>Bits</entry></row>
</thead>
<tbody>
<row><entry>255.0.0.0</entry><entry>8</entry></row>
<row><entry>255.255.0.0</entry><entry>16</entry></row>
<row><entry>255.255.255.0</entry><entry>24</entry></row>
<row><entry>255.255.255.128</entry><entry>25</entry></row>
<row><entry>255.255.255.192</entry><entry>26</entry></row>
<row><entry>255.255.255.224</entry><entry>27</entry></row>
<row><entry>255.255.255.240</entry><entry>28</entry></row>
<row><entry>255.255.255.248</entry><entry>29</entry></row>
<row><entry>255.255.255.252</entry><entry>30</entry></row>
</tbody>
</tgroup>
</table>
<para>
We mentioned earlier that <command>ipfwadm</command> implements a
small trick that makes adding these sorts of rules easier. This trick
is an option called <emphasis>-b</emphasis>, which makes the command a
bidirectional rule.
</para>
<para>
The bidirectional flag allows us to collapse our two
rules into one as follows:
<screen width=80>
<prompt>#</prompt> <userinput>ipfwadm -F -a accept -P tcp -S 172.16.1.0/24 -D 0/0 80 -b</userinput>
</screen>
</para>
</sect3>
<sect3 id="X-087-2-firewall.simpleexample.refinement"><title>An important refinement</title>
<para>
Take a closer look at our ruleset. Can you see that there is still one method
of attack that someone outside could use to defeat our firewall?
</para>
<para>
Our ruleset allows all datagrams from outside our network with a source port
of 80 to pass. This will include those datagrams with the SYN bit set! The SYN
bit is what declares a TCP datagram to be a connection request. If a person
on the outside had privileged access to a host, they could make a connection
through our firewall to any of our hosts, provided they use port 80 at their
end. This is not what we intended.
</para>
<?troff .Nd 10>
<para>
Fortunately there is a solution to this problem. The
<command>ipfwadm</command> command provides another flag that allows
us to build rules that will match datagrams with the SYN bit
set. Let's change our example to include such a rule:
<screen width=80>
<prompt>#</prompt> <userinput>ipfwadm -F -a deny -P tcp -S 0/0 80 -D 172.16.10.0/24 -y</userinput>
<prompt>#</prompt> <userinput>ipfwadm -F -a accept -P tcp -S 172.16.1.0/24 -D 0/0 80 -b</userinput>
</screen>
</para>
<para>
The <option>-y</option> flag causes the rule to match only if the
SYN flag is set in the datagram. So our new rule says:
"Deny any TCP datagrams destined for our network from anywhere with a source
port of 80 and the SYN bit set," or "Deny any connection requests from hosts
using port 80."
</para>
<para>
Why have we placed this special rule <emphasis>before</emphasis> the
main rule? IP firewall rules operate so that the first match is the
rule that is used. Both rules would match the datagrams we want to
stop, so we must be sure to put the <literal>deny</literal> rule
before the <literal>accept</literal> rule.
</para>
</sect3>
<sect3 id="X-087-2-firewall.listing"><title>Listing our rules</title>
<para>
<?troff .hw command>
<indexterm><primary>ipfwadm command</primary><secondary>listing rules with</secondary></indexterm>
After we've entered our rules, we ask <command>ipfwadm</command> to list
them for us using the command:
<screen width=80>
<prompt>#</prompt> <userinput>ipfwadm -F -l</userinput>
</screen>
This command will list all of the configured forwarding rules. The output
should look something like this:
<screen width=80>
<prompt>#</prompt> <userinput>ipfwadm -F -l</userinput>
IP firewall forward rules, default policy: accept
type prot source destination ports
deny tcp anywhere 172.16.10.0/24 www -> any
acc tcp 172.16.1.0/24 anywhere any -> www
</screen>
The <command>ipfwadm</command> command will attempt to translate the port
number into a service name using the <filename>/etc/services</filename> if
an entry exists there.
</para>
<para>
The default output is lacking in some important detail for us. In the
default listing output, we can't see the effect of the
<literal>-y</literal> argument. The <command>ipfwadm</command> command
is able to produce a more detailed listing output if you specify the
<literal>-e</literal> (extended output) argument too. We won't show the
whole output here because it is too wide for the page, but it includes
an <literal>opt</literal> (options) column that shows the <option>-y</option> option
controlling SYN packets:
</para>
<screen width=120>
<prompt>#</prompt> <userinput>ipfwadm -F -l -e</userinput>
P firewall forward rules, default policy: accept
pkts bytes type prot opt tosa tosx ifname ifaddress source ...
0 0 deny tcp --y- 0xFF 0x00 any any anywhere ...
0 0 acc tcp b--- 0xFF 0x00 any any 172.16.1.0/24 ...
</screen>
</sect3>
</sect2>
<sect2 id="X-087-2-firewall.complexexample"><title>A More Complex Example</title>
<para>
The previous example was a simple one. Not all network services are as
simple as the WWW service to configure; in practice, a typical firewall
configuration would be much more complex. Let's look at another common
example, this time FTP. We want our internal network users to be able
to log into FTP servers on the Internet to read and write files. But we don't
want people on the Internet to be able to log into our FTP servers.
</para>
<para>
We know that FTP uses two TCP ports: port 20 (ftp-data) and port 21 (ftp),
so:
<screen width=80>
<prompt>#</prompt> <userinput>ipfwadm -a deny -P tcp -S 0/0 20 -D 172.16.1.0/24 -y</userinput>
<prompt>#</prompt> <userinput>ipfwadm -a accept -P tcp -S 172.16.1.0/24 -D 0/0 20 -b</userinput>
#
<prompt>#</prompt> <userinput>ipfwadm -a deny -P tcp -S 0/0 21 -D 172.16.1.0/24 -y</userinput>
<prompt>#</prompt> <userinput>ipfwadm -a accept -P tcp -S 172.16.1.0/24 -D 0/0 21 -b</userinput>
</screen>
Right? Well, not necessarily. FTP servers
can operate in two different modes: passive mode and active
mode.<footnote id="X-087-2-FW-FN03">
<para>
FTP active mode is somewhat nonintuitively enabled using the
<command>PORT</command> command. FTP passive mode is enabled using the
<command>PASV</command> command.
</para>
</footnote> In passive mode, the FTP server
listens for a connection from the client. In active mode, the server actually
makes the connection to the client. Active mode is usually the
default. The differences are illustrated in <xref linkend="X-087-2-firewall.ftp.graphic">.
</para>
<figure id="X-087-2-firewall.ftp.graphic" float=1>
<title>FTP server modes</title>
<!-- <graphic fileref="lag2_0903.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0903.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0903.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
Many FTP servers make their data connection from port 20 when operating in
active mode, which simplifies things for us a little, but unfortunately not
all do.<footnote id="X-087-2-FW-FN04">
<para>
The ProFTPd daemon is a good example of an FTP server that doesn't, at least
in older versions.
</para>
</footnote>
</para>
<para>
But how does this affect us? Take a look at our rule for port 20, the
FTP-data port. The rule as we have it now assumes that the connection
will be made by our client to the server. This will work if we
use passive mode. But it is very difficult for us to configure
a satisfactory rule to allow FTP active mode, because we may not know in
advance what ports will be used. If we open up our firewall to allow incoming
connections on any port, we are exposing our network to attack on all
services that accept connections.
</para>
<para>
The dilemna is most safely resolved by insisting that our users operate in
passive
mode. Most FTP servers and many FTP clients will operate this way.
The popular <command>ncftp</command> client also supports passive mode, but
it may require a small configuration change to make it default to passive
mode. Many
World Wide Web browsers such as the Netscape browser also support passive
mode FTP, so it shouldn't be too hard to find appropriate software to use.
Alternatively, you can avoid the issue entirely by using an FTP proxy
server that accepts a connection from the internal network and establishes
connections to the outside network.
</para>
<para>
In building your firewall, you will probably find a number of these
sorts of problems. You should always give careful thought to how a service
actually operates to be sure you have put in place an appropriate ruleset for
it. A real firewall configuration can be quite complex.
</para>
</sect2>
<sect2 id="X-087-2-firewall.ipfwadmargs"><title>Summary of ipfwadm Arguments</title>
<para>
<INDEXTERM id="ipfwadm.firewall.options" class=startofrange><PRIMARY>ipfwadm command</PRIMARY><SECONDARY>firewall options</SECONDARY></INDEXTERM>
The <command>ipfwadm</command> has many different arguments that relate to
IP firewall configuration. The general syntax is:
<screen width=45>
<command>ipfwadm</command> <replaceable>category</replaceable> <replaceable>command</replaceable> <replaceable>parameters</replaceable> <replaceable>[options]</replaceable>
</screen>
</para>
<para>
Let's take a look at each of these.
</para>
<sect3 id="X-087-2-firewall.ipfwadm.categories"><title>Categories</title>
<para>
One and only one of the following must be supplied. The category tells the
firewall what sort of firewall rule you are configuring:
</para>
<?troff .Nd 10>
<variablelist>
<varlistentry><term>-I</term>
<listitem><para>Input rule</para></listitem>
</varlistentry>
<varlistentry><term>-O</term>
<listitem><para>Output rule</para></listitem>
</varlistentry>
<varlistentry><term>-F</term>
<listitem><para>Forwarding rule</para></listitem>
</varlistentry>
</variablelist>
</sect3>
<sect3 id="X-087-2-firewall.ipfwadm.command"><title>Commands</title>
<para>
At least one of the following must be supplied and applies only to
those rules that relate to the supplied category. The command tells the
firewall what action to take.
</para>
<variablelist>
<varlistentry><term>-a [policy]</term>
<listitem><para>Append a new rule</para></listitem>
</varlistentry>
<varlistentry><term>-i [policy]</term>
<listitem><para>Insert a new rule</para></listitem>
</varlistentry>
<varlistentry><term>-d [policy]</term>
<listitem><para>Delete an existing rule</para></listitem>
</varlistentry>
<varlistentry><term>-p policy</term>
<listitem><para>Set the default policy</para></listitem>
</varlistentry>
<varlistentry><term>-l</term>
<listitem><para>List all existing rules</para></listitem>
</varlistentry>
<varlistentry><term>-f</term>
<listitem><para>Flush all existing rules</para></listitem>
</varlistentry>
</variablelist>
<para>
The policies relevant to IP firewall and their meanings are:
<variablelist>
<varlistentry><term>accept</term>
<listitem><para>
Allows matching datagrams to be received, forwarded, or transmitted
</para></listitem>
</varlistentry>
<varlistentry><term>deny</term>
<listitem><para>
Blocks matching datagrams from being received, forwarded, or transmitted
</para></listitem>
</varlistentry>
<varlistentry><term>reject</term>
<listitem><para>
Blocks matching datagrams from being received, forwarded, or transmitted, and
sends the host that sent the datagram and ICMP error message
</para></listitem>
</varlistentry>
</variablelist>
</para>
</sect3>
<sect3 id="X-087-2-firewall.ipfwadm.parameters"><title>Parameters</title>
<para>
At least one of the following must be supplied. Use the parameters
to specify to which datagrams this rule applies:
</para>
<variablelist>
<varlistentry><term>-P protocol</term>
<listitem><para>
Can be TCP, UDP, ICMP, or all. Example:
</para>
<para><literal>-P tcp</literal></para></listitem>
</varlistentry>
<varlistentry><term>-S address[/mask] [port]</term>
<listitem><para>
Source IP address that this rule will match. A netmask of
&ldquo;/32&rdquo; will be assumed if you don't supply one. You may
optionally specify which ports this rule will apply to. You must also
specify the protocol using the <option>-P</option> argument described
above for this to work. If you don't specify a port or port range,
&ldquo;all&rdquo; ports will be assumed to match. Ports may be
specified by name, using their <filename>/etc/services</filename> entry
if you wish. In the case of the ICMP protocol, the port field is used
to indicate the ICMP datagram types. Port ranges may be described; use
the general syntax:
<replaceable>lowport</replaceable>:<replaceable>highport</replaceable>. Here is an example:
</para>
<para><literal>-S 172.29.16.1/24 ftp:ftp-data</literal></para></listitem>
</varlistentry>
<varlistentry><term>-D address[/mask] [port]</term>
<listitem><para>
Specify the destination IP address that this rule will match. The destination
address is coded with the same rules as the source address described previously. Here is an example:
</para>
<para><literal>-D 172.29.16.1/24 smtp</literal></para></listitem>
</varlistentry>
<varlistentry><term>-V address</term>
<listitem><para>
Specify the address of the network interface on which the packet is received
(<option>-I</option>&thinsp;) or is being sent (<option>-O</option>). This
allows us to create rules that apply only to certain network interfaces on our
machine. Here is an example:
</para>
<para><literal>-V 172.29.16.1</literal></para></listitem>
</varlistentry>
<varlistentry><term>-W name</term>
<listitem><para>
Specify the name of the network interface. This argument works in the same way
as the <option>-V</option> argument, except you supply the device name
instead of its address. Here is an example:
</para>
<para><literal>-W ppp0</literal></para></listitem>
</varlistentry>
</variablelist>
</sect3>
<sect3 id="X-087-2-firewall.ipfwadm.optargs"><title>Optional arguments</title>
<para>
These arguments are sometimes very useful:
</para>
<variablelist>
<varlistentry><term>-b</term>
<listitem><para>
This is used for bidirectional mode. This flag matches traffic flowing
in either direction between the specified source and
destination. This saves you from having to create two rules: one for
the forward direction of a connection and one for the reverse.
</para></listitem>
</varlistentry>
<varlistentry><term>-o</term>
<listitem><para>
This enables logging of matching datagrams to the kernel log. Any
datagram that matches this rule will be logged as a kernel
message. This is useful to enable you to detect unauthorized access.
</para></listitem>
</varlistentry>
<varlistentry><term>-y</term>
<listitem><para>
This is used to match TCP connect datagrams. The option causes the
rule to match only datagrams that attempt to establish TCP
connections. Only datagrams that have their SYN bit set, but their ACK
bit unset, will match. This is useful to filter TCP connection
attempts and is ignored for other protocols.
</para></listitem>
</varlistentry>
<varlistentry><term>-k</term>
<listitem><para>
This is used to match TCP acknowledgement datagrams. This option
causes the rule to match only datagrams that are acknowledgements to
packets attempting to establish TCP connections. Only datagrams that
have their ACK bit set will match. This is useful to filter TCP
connection attempts and is ignored for all other protocols.
</para></listitem>
</varlistentry>
</variablelist>
</sect3>
<sect3 id="X-087-2-firewall.ipfwadm.icmp-types"><title>ICMP datagram types</title>
<para>
<indexterm><primary>ICMP (Internet Control Message Protocol)</primary><secondary>datagram types</secondary></indexterm>
<indexterm><primary>RFC-1700</primary></indexterm>
<INDEXTERM><PRIMARY>datagram types, ICMP protocol</PRIMARY></INDEXTERM>
Each of the firewall configuration commands allows you to specify ICMP
datagram types. Unlike TCP and UDP ports, there is no convenient
configuration file that lists the datagram types and their
meanings. The ICMP datagram types are defined in
RFC-1700, the Assigned Numbers RFC. The ICMP datagram types are also
listed in one of the standard C library header files. The
<filename>/usr/include/netinet/ip_icmp.h</filename> file, which
belongs to the GNU standard library package and is used by C
programmers when writing network software that uses the ICMP protocol,
also defines the ICMP datagram types. For your convenience, we've
listed them in <xref linkend="X-087-2-chfw-icmptypes">. The
<command>iptables</command> command interface allows you to specify
ICMP types by name, so we've listed the mnemonics it uses, as well.
</para>
<table id="X-087-2-chfw-icmptypes" tocentry=1>
<title>ICMP Datagram Types</title>
<tgroup cols=3>
<thead>
<row>
<entry>Type Number</entry>
<entry>iptables Mnemonic</entry>
<entry>Type Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>echo-reply</entry>
<entry>Echo Reply</entry>
</row>
<row>
<entry>3</entry>
<entry>destination-unreachable</entry>
<entry>Destination Unreachable</entry>
</row>
<row>
<entry>4</entry>
<entry>source-quench</entry>
<entry>Source Quench</entry>
</row>
<row>
<entry>5</entry>
<entry>redirect</entry>
<entry>Redirect</entry>
</row>
<row>
<entry>8</entry>
<entry>echo-request</entry>
<entry>Echo Request</entry>
</row>
<row>
<entry>11</entry>
<entry>time-exceeded</entry>
<entry>Time Exceeded</entry>
</row>
<row>
<entry>12</entry>
<entry>parameter-problem</entry>
<entry>Parameter Problem</entry>
</row>
<row>
<entry>13</entry>
<entry>timestamp-request</entry>
<entry>Timestamp Request</entry>
</row>
<row>
<entry>14</entry>
<entry>timestamp-reply</entry>
<entry>Timestamp Reply</entry>
</row>
<row>
<entry>15</entry>
<entry>none</entry>
<entry>Information Request</entry>
</row>
<row>
<entry>16</entry>
<entry>none</entry>
<entry>Information Reply</entry>
</row>
<row>
<entry>17</entry>
<entry>address-mask-request</entry>
<entry>Address Mask Request</entry>
</row>
<row>
<entry>18</entry>
<entry>address-mask-reply</entry>
<entry>Address Mask Reply</entry>
</row>
</tbody>
</tgroup>
</table>
</sect3>
<INDEXTERM startref="ipfwadm.firewall.options" class=endofrange>
</sect2>
<INDEXTERM startref="original.firewall" class=endofrange>
<INDEXTERM startref="Linux.2.0.kernels" class=endofrange>
</sect1>
<sect1 id="X-087-2-firewall.fwchains"><title>IP Firewall Chains (2.2 Kernels)</title>
<INDEXTERM id="firewall.ip.chains" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>IP chains</SECONDARY></INDEXTERM>
<INDEXTERM id="ip.firewall.chains" class=startofrange><PRIMARY>IP (Internet Protocol)</PRIMARY><SECONDARY>Firewall Chains</SECONDARY></INDEXTERM>
<INDEXTERM id="chains.IP.firewall" class=startofrange><PRIMARY>chains</PRIMARY><SECONDARY>IP firewall</SECONDARY></INDEXTERM>
<INDEXTERM id="Linux.2.2.kernels" class=startofrange><PRIMARY>2.2 kernels</PRIMARY><SECONDARY>IP firewall chains</SECONDARY></INDEXTERM>
<para>
Most aspects of Linux are evolving to meet the increasing demands of
its users; IP firewall is no exception. The traditional IP firewall
implementation is fine for most applications, but can be clumsy and inefficient
to configure for complex environments. To solve this problem, a new method of
configuring IP firewall and related features was developed. This new method was
called &ldquo;IP Firewall Chains&rdquo; and was first released for general use
in the 2.2.0 Linux kernel.
</para>
<para>
<indexterm><primary>Russell, Paul</primary></indexterm>
<indexterm><primary>Neuling, Michael</primary></indexterm>
The IP Firewall Chains support was developed by Paul
Russell and Michael Neuling.<footnote id="X-087-2-FN05"><para>
Paul can be reached at
<systemitem role="emailaddr">Paul.Russell@rustcorp.com.au</systemitem>.
</para>
</footnote>
<indexterm><primary>IPCHAINS-HOWTO</primary></indexterm>
<INDEXTERM><PRIMARY>HOWTOs</PRIMARY><SECONDARY>IPCHAINS</SECONDARY></INDEXTERM>
Paul has documented the IP Firewall Chains software in the IPCHAINS-HOWTO.
</para>
<para>
IP Firewall Chains allows you to
develop classes of firewall rules to which you may then add and remove hosts
or networks. An artifact of firewall rule chaining is that it may
improve firewall performance in configurations in which there are lots of rules.
</para>
<para>
IP Firewall Chains are supported by the 2.2 series kernels and are also
available as a patch against the 2.0.* kernels. The HOWTO
describes where to obtain the patch and provides lots of useful hints about
how to effectively use the <command>ipchains</command> configuration utility.
</para>
<sect2 id="X-087-2-firewall.usingipchains"><title>Using ipchains</title>
<para>
<indexterm><primary>ipchains command</primary></indexterm>
<indexterm><primary>ipfwadm-wrapper command</primary></indexterm>
There are two ways you can use the <command>ipchains</command> utility. The
first way is to make use of the <command>ipfwadm-wrapper</command> shell
script, which is mostly a drop-in replacement for <command>ipfwadm</command>
that drives the <command>ipchains</command> program in the background. If you
want to do this, then read no further. Instead, reread the previous sections
describing <command>ipfwadm</command>, and substitute
<command>ipfwadm-wrapper</command> in its place. This will work, but there is
no guarantee that the script will be maintained, and you will not be taking
advantage of any of the advanced features that the IP Firewall Chains have to
offer.
</para>
<para>
The second way to use <command>ipchains</command> is to learn its new syntax
and modify any existing configurations you have to use the new syntax instead
of the old. With some careful consideration, you may find you can optimize your
configuration as you convert. The <command>ipchains</command> syntax is easier
to learn than the <command>ipfwadm</command>, so this is a good option.
</para>
<para>
The <command>ipfwadm</command> manipulated three rulesets for the purpose
of configuring firewalling. With IP Firewall Chains you can create arbitrary
numbers of rulesets, each linked to one another, but there are three rulesets
related to firewalling that are always present. The standard rulesets
are direct equivalents of those used with <command>ipfwadm</command>, except
they have names: <literal>input</literal>, <literal>forward</literal> and
<literal>output</literal>.
</para>
<para>
Let's first look at the general syntax of the <command>ipchains</command>
command, then we'll look at how we'd use <command>ipchains</command> instead
of <command>ipfwadm</command> without worrying about any of the advanced
chaining features. We'll do this by revisiting our previous examples.
</para>
</sect2>
<sect2 id="X-087-2-firewall.ipchains.syntax"><title>ipchains Command Syntax</title>
<para>
<INDEXTERM id="ipchains.firewall.options" class=startofrange><PRIMARY>ipchains command</PRIMARY><SECONDARY>firewall options</SECONDARY></INDEXTERM>
The <command>ipchains</command> command syntax is straightforward. We'll now
look at the most important of those. The general syntax of most
<command>ipchains</command> commands is:
<screen width=80>
<command>ipchains</command> <replaceable>command</replaceable> <replaceable>rule-specification</replaceable> <replaceable>options</replaceable>
</screen>
</para>
<sect3 id="X-087-2-firewall.ipchains.commands"><title>Commands</title>
<para>
There are a number of ways we can manipulate rules and rulesets with the
<command>ipchains</command> command. Those relevant to IP firewalling are:
<variablelist>
<varlistentry>
<term>-A chain</term>
<listitem><para>
Append one or more rules to the end of the nominated chain. If a hostname is
supplied as either source or destination and it resolves to more than one IP
address, a rule will be added for each address.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-I chain rulenum</term>
<listitem><para>
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 it resolves to.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-D chain</term>
<listitem><para>
<?troff .hw specification>
Delete one or more rules from the specified chain that matches the
rule specification.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-D chain rulenum</term>
<listitem><para>
Delete the rule residing at position <replaceable>rulenum</replaceable>
in the specified chain. Rule positions start at one for the first rule in the
chain.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-R chain rulenum</term>
<listitem><para>
Replace the rule residing at position <replaceable>rulenum</replaceable>
in the specific chain with the supplied rule specification.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-C chain</term>
<listitem><para>
Check the datagram described by the rule specification against the specific
chain. This command will return a message describing how the datagram was
processed by the chain. This is very useful for testing your firewall
configuration, and we look at it in detail a little later.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-L [chain]</term>
<listitem><para>
List the rules of the specified chain, or for all chains if no chain
is specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-F [chain]</term>
<listitem><para>
Flush the rules of the specified chain, or for all chains if no chain is
specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-Z [chain]</term>
<listitem><para>
Zero the datagram and byte counters for all rules of the specified chain, or
for all chains if no chain is specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-N chain</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-X [chain]</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-P chain policy</term>
<listitem><para>
Set the default policy of the specified chain to the specified policy.
Valid firewalling policies are <literal>ACCEPT</literal>,
<literal>DENY</literal>, <literal>REJECT</literal>,
<literal>REDIR</literal>, or
<literal>RETURN</literal>. <literal>ACCEPT</literal>,
<literal>DENY</literal>, and <literal>REJECT</literal> have the same
meanings as those for the tradition IP firewall
implementation. <literal>REDIR</literal> specifies that the datagram
should be transparently redirected to a port on the firewall host. The
<literal>RETURN</literal> target causes the IP firewall code to return
to the Firewall Chain that called the one containing this rule and
continues starting at the rule after the calling rule.
</para></listitem>
</varlistentry>
</variablelist>
</para>
</sect3>
<sect3 id="X-087-2-firewall.ipchains.rulespec"><title>Rule specification parameters</title>
<para>
A number of <command>ipchains</command> parameters create a rule specification
by determining what types of packets match. If any of these parameters is
omitted from a rule specification, its default is assumed:
</para>
<variablelist>
<varlistentry>
<term>-p [!]protocol</term>
<listitem><para>
Specifies the protocol of the datagram that will match this rule. Valid
protocol names are <literal>tcp</literal>, <literal>udp</literal>,
<literal>icmp</literal>, or <literal>all</literal>. You may also specify a
protocol number here to match other protocols. For example, you might use
<literal>4</literal> to match the <literal>ipip</literal> encapsulation
protocol. If the <literal>!</literal> is supplied, the rule is negated and
the datagram will match any protocol other than the protocol specified. If this
parameter isn't supplied, it will default to <literal>all</literal>.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-s [!]address[/mask] [!] [port]</term>
<listitem><para>
Specifies the source address and port 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 <literal>mask</literal> is the netmask
to use and may be supplied either in the traditional form (e.g.,
/255.255.255.0) or the modern form (e.g., /24). The optional
<literal>port</literal> specifies the TCP or UDP port, or the ICMP
datagram type that will match. You may supply a port specification
only if you've supplied the <option>-p</option> parameter with one of
the <literal>tcp</literal>, <literal>udp</literal>, or
<literal>icmp</literal> protocols. Ports may be specified as a range
by specifying the upper and lower limits of the range with a colon as
a delimiter. For example, <literal>20:25</literal> described all of
the ports numbered from 20 up to and including 25. Again, the
<literal>!</literal> character may be used to negate the values.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-d [!]address[/mask] [!] [port]</term>
<listitem><para>
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
<option>-s</option> parameter.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-j target</term>
<listitem><para>
Specifies the action to take when this rule matches. You can think of
this parameter as meaning &ldquo;jump to.&rdquo; Valid targets are
<literal>ACCEPT</literal>, <literal>DENY</literal>, <literal>REJECT</literal>,
<literal>REDIR</literal>, and <literal>RETURN</literal>. We described the
meanings of each of these targets earlier. However, you may also specify the name of a
user-defined chain where processing will continue. If this parameter is
omitted, no action is taken on matching rule datagrams at all other than to
update the datagram and byte counters.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-i [!]interface-name</term>
<listitem><para>
Specifies the interface on which the datagram was received or is to
be transmitted. Again, the <literal>!</literal> inverts the result of the
match. If the interface name ends with <literal>+</literal>,
then any interface that begins with the supplied string will match. For
example, <literal>-i ppp+</literal> would match any PPP network device and
<literal>-i ! eth+</literal> would match all interfaces except Ethernet
devices.
</para></listitem>
</varlistentry>
<varlistentry>
<term>[!] -f</term>
<listitem><para>
Specifies that this rule applies to everything but the first fragment
of a fragmented datagram.
</para></listitem>
</varlistentry>
</variablelist>
</sect3>
<sect3 id="X-087-2-firewall.ipchains.options"><title>Options</title>
<para>
The following <command>ipchains</command> options are more general in nature.
Some of them control rather esoteric features of the IP chains software:
<variablelist>
<varlistentry>
<term>-b</term>
<listitem><para>
Causes the command to generate two rules. One rule matches the
parameters supplied, and the other rule added matches the corresponding
parameters in the reverse direction.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-v</term>
<listitem><para>
Causes <command>ipchains</command> to be verbose in its output. It
will supply more information.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-n</term>
<listitem><para>
Causes <command>ipchains</command> to display IP address and ports as
numbers without attempting to resolve them to their corresponding names.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-l</term>
<listitem><para>
Enables kernel logging of matching datagrams. Any datagram that matches
the rule will be logged by the kernel using its <function>printk(&thinsp;)</function>
function, which is usually handled by the <command>sysklogd</command> program
and written to a log file. This is useful for making unusual datagrams visible.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-o[maxsize]</term>
<listitem><para>
Causes the IP chains software to copy any datagrams matching the rule to
the userspace &ldquo;netlink&rdquo; device. The
maxsize argument limits the number of bytes from
each datagram that are passed to the netlink device. This option is of most
use to software developers, but may be exploited by software packages in the
future.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-m markvalue</term>
<listitem><para>
Causes matching datagrams to be <emphasis>marked</emphasis> with a value. Mark
values are unsigned 32-bit numbers. In existing implementations this does
nothing, but at some point in the future, it may determine how the datagram is
handled by other software such as the routing code. If a
markvalue begins with a <literal>+</literal> or
<literal>-</literal>, the value is added or subtracted from the existing
markvalue.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-t andmask xormask</term>
<listitem><para>
Enables you to manipulate the &ldquo;type of service&rdquo; bits in the
IP header of any datagram that matches this rule. The type of service bits are
used by intelligent routers to prioritize datagrams before forwarding them. The
Linux routing software is capable of this sort prioritization. The
<replaceable>andmask</replaceable> and <replaceable>xormask</replaceable>
represent bit masks that will be logically ANDed and ORed with the type of
service bits of the datagram respectively. This is an advanced feature that is
discussed in more detail in the IPCHAINS-HOWTO.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-x</term>
<listitem><para>
Causes any numbers in the <command>ipchains</command> output to be
expanded to their exact values with no rounding.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-y</term>
<listitem><para>
Causes the rule to match any TCP datagram with the SYN bit set and the
ACK and FIN bits clear. This is used to filter TCP connection requests.
</para></listitem>
</varlistentry>
</variablelist>
</para>
</sect3>
<INDEXTERM startref="ipchains.firewall.options" class=endofrange>
</sect2>
<sect2 id="X-087-2-firewall.simpleexample.again"><title>Our Na&iuml;ve Example Revisited</title>
<para>
Let's again suppose that we have a network in our organization and
that we are using a Linux-based firewall machine to allow our users
access to WWW servers on the Internet, but to allow no other traffic
to be passed.
</para>
<para>
If our network has a 24-bit network mask (class C) and has an address of
172.16.1.0, we'd use the following <command>ipchains</command> rules:
<screen width=80>
<prompt>#</prompt> <userinput>ipchains -F forward</userinput>
<prompt>#</prompt> <userinput>ipchains -P forward DENY</userinput>
<prompt>#</prompt> <userinput>ipchains -A forward -s 0/0 80 -d 172.16.1.0/24 -p tcp -y -j DENY</userinput>
<prompt>#</prompt> <userinput>ipchains -A forward -s 172.16.1.0/24 -d 0/0 80 -p tcp -b -j ACCEPT</userinput>
</screen>
</para>
<para>
The first of the commands flushes all of the rules from the
<literal>forward</literal> rulesets and the second set of
commands sets the default policy of the <literal>forward</literal>
ruleset to <literal>DENY</literal>. Finally, the third
and fourth commands do the specific filtering we want. The fourth
command allows datagrams to and from web servers on the outside of our
network to pass, and the third prevents incoming TCP connections with
a source port of 80.
</para>
<para>
If we now wanted to add rules that allowed passive mode only access to FTP
servers in the outside network, we'd add these rules:
<screen width=80>
<prompt>#</prompt> <userinput>ipchains -A forward -s 0/0 20 -d 172.16.1.0/24 -p tcp -y -j DENY</userinput>
<prompt>#</prompt> <userinput>ipchains -A forward -s 172.16.1.0/24 -d 0/0 20 -p tcp -b -j ACCEPT</userinput>
<prompt>#</prompt> <userinput>ipchains -A forward -s 0/0 21 -d 172.16.1.0/24 -p tcp -y -j DENY</userinput>
<prompt>#</prompt> <userinput>ipchains -A forward -s 172.16.1.0/24 -d 0/0 21 -p tcp -b -j ACCEPT</userinput>
</screen>
</para>
</sect2>
<sect2 id="X-087-2-firewall.listing.again"><title>Listing Our Rules with ipchains</title>
<para>
<indexterm><primary>ipchains command</primary><secondary>listing rules with</secondary></indexterm>
To list our rules with <command>ipchains</command>, we use its
<option>-L</option> argument. Just as with <command>ipfwadm</command>, there
are arguments that control the amount of detail in the output. In its simplest
form, <command>ipchains</command> produces output that looks like:
<screen width=80>
<prompt>#</prompt> <userinput>ipchains -L -n</userinput>
Chain input (policy ACCEPT):
Chain forward (policy DENY):
target prot opt source destination ports
DENY tcp -y---- 0.0.0.0/0 172.16.1.0/24 80 -> *
ACCEPT tcp ------ 172.16.1.0/24 0.0.0.0/0 * -> 80
ACCEPT tcp ------ 0.0.0.0/0 172.16.1.0/24 80 -> *
ACCEPT tcp ------ 172.16.1.0/24 0.0.0.0/0 * -> 20
ACCEPT tcp ------ 0.0.0.0/0 172.16.1.0/24 20 -> *
ACCEPT tcp ------ 172.16.1.0/24 0.0.0.0/0 * -> 21
ACCEPT tcp ------ 0.0.0.0/0 172.16.1.0/24 21 -> *
Chain output (policy ACCEPT):
</screen>
</para>
<para>
If you don't supply the name of a chain to list,
<command>ipchains</command> will list all rules in all chains. The
<literal>-n</literal> argument in our example tells
<command>ipchains</command> not to attempt to convert any address or
ports into names. The information presented should be
self-explanatory.
</para>
<para>
A verbose form, invoked by the <option>-u</option> option, provides much more
detail. Its output adds fields for the datagram and byte counters,
Type of Service <emphasis>AND</emphasis> and <emphasis>XOR</emphasis> flags, the interface name, the mark, and
the outsize.
</para>
<para>
All rules created with <command>ipchains</command> have datagram and
byte counters associated with them. This is how IP Accounting is
implemented and will be discussed in detail in <xref
linkend="X-087-2-accounting">. By default these counters are presented
in a rounded form using the suffixes <literal>K</literal> and
<literal>M</literal> to represent units of one thousand and one
million, respectively. If the <literal>-x</literal> argument is
supplied, the counters are expanded to their full unrounded form.
</para>
</sect2>
<sect2 id="X-087-2-firewall.ipchainsyay"><title>Making Good Use of Chains</title>
<para>
You now know that the <command>ipchains</command> command is a
replacement for the <command>ipfwadm</command> with a simpler
command-line syntax and some interesting enhancements, but you're no
doubt wanting to know where you'd use the user-defined chains and
why. You'll also probably want to know how to use the support scripts
that accompany the <command>ipchains</command> command in its software
package. We'll now explore these subjects and address the questions.
</para>
<sect3><title>User-defined chains</title>
<para>
<INDEXTERM id="firewalls.userdef.chains" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>user-defined chains</SECONDARY></INDEXTERM>
<INDEXTERM id="chains.userdefined" class=startofrange><PRIMARY>chains</PRIMARY><SECONDARY>user-defined</SECONDARY></INDEXTERM>
The three rulesets of the traditional IP firewall code provided a
mechanism for building firewall configurations that were fairly simple
to understand and manage for small networks with simple firewalling
requirements. When the configuration requirements are not simple, a
number of problems become apparent. Firstly, large networks often
require much more than the small number of firewalling rules we've
seen so far; inevitably needs arise that require firewalling rules
added to cover special case scenarios. As the number of rules grows,
the performance of the firewall deterioriates as more and more tests
are conducted on each datagram and managability becomes an
issue. Secondly, it is not possible to enable and disable sets of
rules atomically; instead, you are forced to expose yourself to attack
while you are in the middle of rebuilding your ruleset.
</para>
<para>
The design of IP Firewall Chains helps to alleviate these problems by
allowing the network administrator to create arbitrary sets of
firwewall rules that we can link to the three inbuilt rulesets. We can
use the <option>-N</option> option of <command>ipchains</command> to
create a new chain with any name we please of eight characters or
less. (Restricting the name to lowercase letters only is probably a
good idea.) The <option>-j</option> option configures the action to
take when a datagram matches the rule specification. The <option>-j</option> option
specifies that if a datagram matches a rule, further testing should be
performed against a user-defined chain. We'll illustrate this with a
diagram.
</para>
<para>
Consider the following <command>ipchains</command> commands:
<screen width=80>
ipchains -P input DENY
ipchains -N tcpin
ipchains -A tcpin -s ! 172.16.0.0/16
ipchains -A tcpin -p tcp -d 172.16.0.0/16 ssh -j ACCEPT
ipchains -A tcpin -p tcp -d 172.16.0.0/16 www -j ACCEPT
ipchains -A input -p tcp -j tcpin
ipchains -A input -p all
</screen>
</para>
<para>
We set the default input chain policy to <literal>deny</literal>. The
second command creates a user-defined chain called
&ldquo;tcpin.&rdquo; The third command adds a rule to the
<literal>tcpin</literal> chain that matches any datagram that was
sourced from outside our local network; the rule takes no action. This
rule is an accounting rule and will be discussed in more detail in
<xref linkend="X-087-2-accounting">. The next two rules match any
datagram that is destined for our local network and either of the
<literal>ssh</literal> or <literal>www</literal> ports; datagrams
matching these rules are accepted. The next rule is when the real
<emphasis>ipchains</emphasis> magic begins. It causes the firewall
software to check any datagram of protocol TCP against the
tcpin user-defined chain. Lastly, we add a rule to our
<literal>input</literal> chain that matches any datagram; this is
another accounting rule. They will produce the following Firewall Chains shown in Figure 9-4.
</para>
<figure id="X-087-2-firewall.ipchains" float=0>
<title>A simple IP chain ruleset</title>
<!-- <graphic fileref="lag2_0904.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0904.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0904.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
Our <literal>input</literal> and <literal>tcpin</literal> chains are populated
with our rules. Datagram processing always beings at one of the inbuilt chains.
We'll see how our user-defined chain is called into play by following the
processing path of different types of datagrams.
</para>
<para>
First, let's look at what happens when a UDP datagram for one of our hosts
is received. <xref linkend="X-087-2-firewall.ipchains.udp"> illustrates the
flow through the rules.
</para>
<figure id="X-087-2-firewall.ipchains.udp" float=0>
<title>The sequence of rules tested for a received UDP datagram</title>
<!-- <graphic fileref="lag2_0905.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0905.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0905.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
The datagram is received by the <literal>input</literal> chain and
falls through the first two rules because they match ICMP and TCP
protocols, respectively. It matches the third rule in the
<literal>input</literal> chain, but it doesn't specify a target, so
its datagram and byte counters are updated, but no other action takes
place. The datagram reaches the end of the <literal>input</literal>
chain, meets with the default <literal>input</literal> chain policy,
and is denied.
</para>
<para>
To see our user-defined chain in operation, let's now consider what
happens when we receive a TCP datagram destined for the
<literal>ssh</literal> port of one of our hosts. The sequence is shown
in <xref linkend="X-087-2-firewall.ipchains.tcp.ssh">.
</para>
<figure id="X-087-2-firewall.ipchains.tcp.ssh" float=0>
<title>The rules flow for a received TCP datagram for ssh</title>
<!-- <graphic fileref="lag2_0906.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0906.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0906.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
This time the second rule in the <literal>input</literal> chain does
match and it specifies a target of <literal>tcpin</literal>, our
user-defined chain. Specifying a user-defined chain as a target
causes the datagram to be tested against the rules in that chain, so
the next rule tested is the first rule in the <literal>tcpin</literal>
chain. The first rule matches any datagram that has a source address
outside our local network and specifies no target, so it too is an
accounting rule and testing falls through to the next rule. The second
rule in our <literal>tcpin</literal> chain does match and specifies a
target of <literal>ACCEPT</literal>. We have arrived at target, so no
further firewall processing occurs. The datagram is accepted.
</para>
<para>
Finally, let's look at what happens when we reach the end of a
user-defined chain. To see this, we'll map the flow for a TCP datagram
destined for a port other than the two we are handling
specifically, as shown in <xref linkend="X-087-2-firewall.ipchains.tcp.other">.
</para>
<figure id="X-087-2-firewall.ipchains.tcp.other" float=0>
<title>The rules flow for a received TCP datagram for telnet</title>
<!-- <graphic fileref="lag2_0907.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0907.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0907.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
The user-defined chains do not have default policies. When all rules
in a user-defined chain have been tested, and none have matched, the
firewall code acts as though a <literal>RETURN</literal> rule were
present, so if this isn't what you want, you should ensure you supply
a rule at the end of the user-defined chain that takes whatever action
you wish. In our example, our testing returns to the rule in the
<literal>input</literal> ruleset immediately following the one that
moved us to our user-defined chain. Eventually we reach the end of the
<literal>input</literal> chain, which does have a default policy and
our datagram is denied.
</para>
<para>
This example is very simple, but illustrates our point. A more practical use of
IP chains would be much more complex. A slightly more sophisticated example is
provided in the following list of commands:
</para>
<programlisting id="X-087-2-firewall.ipchains.example" width=80>
#
# Set default forwarding policy to REJECT
ipchains -P forward REJECT
#
# create our user-defined chains
ipchains -N sshin
ipchains -N sshout
ipchains -N wwwin
ipchains -N wwwout
#
# Ensure we reject connections coming the wrong way
ipchains -A wwwin -p tcp -s 172.16.0.0/16 -y -j REJECT
ipchains -A wwwout -p tcp -d 172.16.0.0/16 -y -j REJECT
ipchains -A sshin -p tcp -s 172.16.0.0/16 -y -j REJECT
ipchains -A sshout -p tcp -d 172.16.0.0/16 -y -j REJECT
#
# Ensure that anything reaching the end of a user-defined chain is rejected.
ipchains -A sshin -j REJECT
ipchains -A sshout -j REJECT
ipchains -A wwwin -j REJECT
ipchains -A wwwout -j REJECT
#
# divert www and ssh services to the relevant user-defined chain
ipchains -A forward -p tcp -d 172.16.0.0/16 ssh -b -j sshin
ipchains -A forward -p tcp -s 172.16.0.0/16 -d 0/0 ssh -b -j sshout
ipchains -A forward -p tcp -d 172.16.0.0/16 www -b -j wwwin
ipchains -A forward -p tcp -s 172.16.0.0/16 -d 0/0 www -b -j wwwout
#
# Insert our rules to match hosts at position two in our user-defined chains.
ipchains -I wwwin 2 -d 172.16.1.2 -b -j ACCEPT
ipchains -I wwwout 2 -s 172.16.1.0/24 -b -j ACCEPT
ipchains -I sshin 2 -d 172.16.1.4 -b -j ACCEPT <?troff .ne 10>
ipchains -I sshout 2 -s 172.16.1.4 -b -j ACCEPT
ipchains -I sshout 2 -s 172.16.1.6 -b -j ACCEPT
#
</programlisting>
<para>
In this example, we've used a selection of user-defined chains both to
simplify management of our firewall configuration and improve the
efficiency of our firewall as compared to a solution involving only the
built-in chains.
</para>
<para>
Our example creates user-defined chains for each of the
<literal>ssh</literal> and <literal>www</literal> services in each
connection direction. The chain called <literal>wwwout</literal> is
where we place rules for hosts that are allowed to make outgoing World
Wide Web connections, and <literal>sshin</literal> is where we define
rules for hosts to which we want to allow incoming ssh
connections. We've assumed that we have a requirement to allow and
deny individual hosts on our network the ability to make or receive
<literal>ssh</literal> and <literal>www</literal> connections. The
simplication occurs because the user-defined chains allow us to neatly
group the rules for the host incoming and outgoing permissions rather
than muddling them all together. The improvement in efficiency occurs
because for any particular datagram, we have reduced the average number
of tests required before a target is found. The efficiency gain
increases as we add more hosts. If we hadn't used user-defined chains,
we'd potentially have to search the whole list of rules to determine
what action to take with each and every datagram received. Even if we
assume that each of the rules in our list matches an equal proportion
of the total number of datagrams processed, we'd still be searching
half the list on average. User-defined chains allow us to avoid
testing large numbers of rules if the datagram being tested doesn't
match the simple rule in the built-in chain that jumps to them.
</para>
<INDEXTERM startref="firewalls.userdef.chains" class=endofrange>
<INDEXTERM startref="chains.userdefined" class=endofrange>
</sect3>
<sect3><title>The ipchains support scripts</title>
<para>
<INDEXTERM><PRIMARY>ipchains command</PRIMARY><SECONDARY>support scripts</SECONDARY></INDEXTERM>
The <command>ipchains</command> software package is supplied with
three support scripts. The first of these we've discussed briefly
already, while the remaining two provide an easy and convenient means
of saving and restoring your firewall configuration.
</para>
<para>
<indexterm><primary>ipfwadm-wrapper command</primary></indexterm>
The <command>ipfwadm-wrapper</command> script emulates the
command-line syntax of the <command>ipfwadm</command> command, but
drives the <command>ipchains</command> command to build the firewall
rules. This is a convenient way to migrate your existing firewall
configuration to the kernel or an alternative to learning the
<command>ipchains</command> syntax. The
<command>ipfwadm-wrapper</command> script behaves differently from the
<command>ipfwadm</command> command in two ways: firstly, because the
<command>ipchains</command> command doesn't support specification of
an interface by address, the <command>ipfwadm-wrapper</command> script
accepts an argument of <option>-V</option> but attempts to convert it
into the <command>ipchains</command> equivalent of a
<option>-W</option> by searching for the interface name configured
with the supplied address. The <command>ipfwadm-wrapper</command>
script will always provide a warning when you use the
<option>-V</option> option to remind you of this. Secondly, fragment
accounting rules are not translated correctly.
</para>
<para>
<INDEXTERM><PRIMARY>firewalls</PRIMARY><SECONDARY>IP chains</SECONDARY><TERTIARY>restoring/saving</TERTIARY></INDEXTERM>
<indexterm><primary>ipchains-save command</primary></indexterm>
<indexterm><primary>ipchains-restore command</primary></indexterm>
The <command>ipchains-save</command> and <command>ipchains-restore</command>
scripts make building and modifying a firewall configuration much simpler.
The <command>ipchains-save</command> command reads the current firewall
configuration and writes a simplified form to the standard output. The
<command>ipchains-restore</command> command reads data in the output format
of the <command>ipchains-save</command> command and configures the IP firewall
with these rules. The advantage of using these scripts over directly modifying
your firewall configuration script and testing the configuration is the ability
to dynamically build your configuration once and then save it. You can then
restore that configuration, modify it, and resave it as you please.
</para>
<para>
To use the scripts, you'd enter something like:
<screen width=80>
<userinput><command>ipchains-save</command> &gt;/var/state/ipchains/firewall.state</userinput>
</screen>
to save your current firewall configuration. You'd restore it, perhaps at
boot time, with:
<screen width=80>
<userinput><command>ipchains-restore</command> &lt;/var/state/ipchains/firewall.state</userinput>
</screen>
</para>
<para>
The <command>ipchains-restore</command> script checks if any user-defined
chain listed in its input already exists. If you've supplied the
<literal>-f</literal> argument, it will automatically flush the rules from
the user-defined chain before configuring those in the input. The default
behavior asks you whether to skip this chain or to flush it.
</para>
</sect3>
</sect2>
<INDEXTERM startref="firewall.ip.chains" class=endofrange>
<INDEXTERM startref="ip.firewall.chains" class=endofrange>
<INDEXTERM startref="chains.IP.firewall" class=endofrange>
<INDEXTERM startref="Linux.2.2.kernels" class=endofrange>
</sect1>
<sect1 id="X-087-2-firewall.future"><title>Netfilter and IP Tables (2.4 Kernels)</title>
<INDEXTERM id="firewalls.netfilter" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>netfilter</SECONDARY></INDEXTERM>
<INDEXTERM id="Linux.2.4.kernels" class=startofrange><PRIMARY>2.4 kernels</PRIMARY><SECONDARY>netfilter and IP tables</SECONDARY></INDEXTERM>
<INDEXTERM id="netfilter.IP.tables" class=startofrange><PRIMARY>netfilter</PRIMARY><SECONDARY>IP tables and</SECONDARY></INDEXTERM>
<para>
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 <emphasis>netfilter</emphasis>.
</para>
<note><para>
At the time of preparation of this book the
<emphasis>netfilter</emphasis> design had not yet stabilized. We hope
you'll forgive any errors in the description of
<emphasis>netfilter</emphasis> or its associated configuration tools
that result from changes that occurred after preparation of this
material. We considered the <emphasis>netfilter</emphasis> 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
<emphasis>netfilter</emphasis> configuration.
</para></note>
<para>
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 <xref
linkend="X-087-2-ipmasq">) 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.
</para>
<para>
Still, there were other problems. In particular, the
&ldquo;input&rdquo; chain described input to the IP networking layer
as a whole. The input chain affected both datagrams to be
<emphasis>destined for</emphasis> this host and datagrams to be
<emphasis>routed by</emphasis> 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.
</para>
<para>
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. <emphasis>netfilter</emphasis> 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.
</para>
<para>
<INDEXTERM><PRIMARY>datagrams</PRIMARY><SECONDARY>IP chains vs. netfilter</SECONDARY></INDEXTERM>
Let's take a look at two of the key changes made. <xref
linkend="X-087-2-firewall.routing.ipchains"> illustrates how datagrams
are processed in the IP chains implementation, while <xref
linkend="X-087-2-firewall.routing.netfilter"> illustrates how they are
processed in the <emphasis>netfilter</emphasis> 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 <command>iptables</command> was created.
</para>
<para>
<?troff .hw irrespective>
<?troff .hw config-urations>
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 <emphasis>netfilter</emphasis>,
the input chain applies <emphasis>only</emphasis> to datagrams
destined for the local host, and the forward chain applies only to
datagrams destined for <emphasis>another</emphasis> 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
<emphasis>netfilter</emphasis>, the output chain applies
<emphasis>only</emphasis> 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.
</para>
<figure id="X-087-2-firewall.routing.ipchains" float=1>
<title>Datagram processing chain in IP chains</title>
<!-- <graphic fileref="lag2_0908.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0908.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0908.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
In <xref linkend="X-087-2-firewall.routing.ipchains">, the components
labeled &ldquo;demasq&rdquo; and &ldquo;masq&rdquo; are separate
kernel components responsible for the incoming and outgoing processing
of masqueraded datagrams. These have been reimplemented as
<emphasis>netfilter</emphasis> modules.
</para>
<para>
Consider the case of a configuration for which the default policy for each
of the input, forward, and output chains is
<literal>deny</literal>. 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.
</para>
<para>
In the <emphasis>netfilter</emphasis> implementation with
<command>iptables</command>, 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.
</para>
<figure id="X-087-2-firewall.routing.netfilter" float=1>
<title>Datagram processing chain in netfilter</title>
<!-- <graphic fileref="lag2_0909.jpg"></graphic> -->
<!-- 2016-01-28; MAB, TLDP -->
<mediaobject>
<imageobject>
<imagedata fileref="images/lag2_0909.jpg" format="jpg">
</imageobject>
<imageobject>
<imagedata fileref="images/lag2_0909.eps" format="eps">
</imageobject>
</mediaobject>
</figure>
<para>
<indexterm><primary>PACKET-FILTERING-HOWTO</primary></indexterm>
<INDEXTERM><PRIMARY>HOWTOs</PRIMARY><SECONDARY>PACKET-FILTERING</SECONDARY></INDEXTERM>
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.
</para>
<sect2><title>Backward Compatability with ipfwadm<?lb>and ipchains</title>
<para>
The remarkable flexibility of Linux <emphasis>netfilter</emphasis> is
illustrated by its ability to emulate the <command>ipfwadm</command> and
<command>ipchains</command> interfaces. Emulation makes transition to the new
generation of firewall software a little easier.
</para>
<para>
<INDEXTERM><PRIMARY>netfilter</PRIMARY><SECONDARY>kernel modules</SECONDARY></INDEXTERM>
The two <emphasis>netfilter</emphasis> kernel modules called
<filename>ipfwadm.o</filename> and <filename>ipchains.o</filename>
provide backward compatibility for <command>ipfwadm</command> and
<command>ipchains</command>. You may load only one of these modules at
a time, and use one only if the <filename>ip_tables.o</filename>
module is not loaded. When the appropriate module is loaded,
<emphasis>netfilter</emphasis> works exactly like the former
firewall implementation.
</para>
<para>
<emphasis>netfilter</emphasis> mimics the
<command>ipchains</command> interface with the following commands:
<screen>
rmmod ip_tables
modprobe ipchains
ipchains <replaceable>...</replaceable>
</screen>
</para>
</sect2>
<sect2 id="X-087-2-firewall.usingiptables"><title>Using iptables</title>
<para>
<INDEXTERM id="iptables.firewall.options" class=startofrange><PRIMARY>iptables command</PRIMARY><SECONDARY>firewall options</SECONDARY></INDEXTERM>
The <command>iptables</command> utility is used to configure
<emphasis>netfilter</emphasis> filtering rules. Its syntax borrows
heavily from the <command>ipchains</command> command, but differs in
one very significant respect: it is
<emphasis>extensible</emphasis>. 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.
</para>
<para>
Before you can use the <command>iptables</command> command, you must
load the <emphasis>netfilter</emphasis> kernel module that provides
support for it. The easiest way to do this is to use the
<command>modprobe</command> command as follows:
<screen>
modprobe ip_tables
</screen>
</para>
<para>
The <command>iptables</command> command is used to configure both IP
filtering and Network Address Translation. To facilitate this, there are two
tables of rules called <emphasis>filter</emphasis> and
<emphasis>nat</emphasis>. The filter table is assumed if you do not
specify the <option>-t</option> option to override
it. Five built-in chains are also provided. The
<literal>INPUT</literal> and <literal>FORWARD</literal> chains are
available for the <literal>filter</literal> table, the
<literal>PREROUTING</literal> and <literal>POSTROUTING</literal>
chains are available for the <literal>nat</literal> table, and the
<literal>OUTPUT</literal> chain is available for both tables. In this
chapter we'll discuss only the <emphasis>filter</emphasis> table. We'll look
at the <emphasis>nat</emphasis> table in <xref linkend="X-087-2-ipmasq">
</para>
<para>
The general syntax of most <command>iptables</command> commands is:
<screen>
<command>iptables</command> <replaceable>command</replaceable> <replaceable>rule-specification</replaceable> <replaceable>extensions</replaceable>
</screen>
Now we'll take a look at some options in detail, after which we'll review
some examples.
</para>
<sect3 id="X-087-2-firewall.iptables.commands"><title>Commands</title>
<para>
There are a number of ways we can manipulate rules and rulesets with the
<command>iptables</command> command. Those relevant to IP firewalling are:
<variablelist>
<varlistentry>
<term>-A chain</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-I chain rulenum</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-D chain</term>
<listitem><para>
Delete one or more rules from the specified chain matching the rule
specification.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-D chain rulenum</term>
<listitem><para>
Delete the rule residing at position <replaceable>rulenum</replaceable> in the
specified chain. Rule positions start at 1 for the first rule in the chain.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-R chain rulenum</term>
<listitem><para>
Replace the rule residing at position <replaceable>rulenum</replaceable>
in the specific chain with the supplied rule specification.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-C chain</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-L [chain]</term>
<listitem><para>
List the rules of the specified chain, or for all chains if no chain is
specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-F [chain]</term>
<listitem><para>
Flush the rules of the specified chain, or for all chains if no chain is
specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-Z [chain]</term>
<listitem><para>
Zero the datagram and byte counters for all rules of the specified chain, or
for all chains if no chain is specified.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-N chain</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-X [chain]</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-P chain policy</term>
<listitem><para>
Set the default policy of the specified chain to the specified policy. Valid
firewalling policies are <literal>ACCEPT</literal>, <literal>DROP</literal>,
<literal>QUEUE</literal>, and <literal>RETURN</literal>.
<literal>ACCEPT</literal> allows the datagram to pass. <literal>DROP</literal>
causes the datagram to be discarded. <literal>QUEUE</literal> causes the
datagram to be passed to userspace for further processing. The
<literal>RETURN</literal> 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.
</para></listitem>
</varlistentry>
</variablelist>
</para>
</sect3>
<sect3 id="X-087-2-firewall.iptables.rulespec"><title>Rule specification parameters</title>
<para>
There are a number of <command>iptables</command> 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.
</para>
<variablelist>
<varlistentry>
<term>-p [!]protocol</term>
<listitem><para>
Specifies the protocol of the datagram that will match this rule. Valid
protocol names are <literal>tcp</literal>, <literal>udp</literal>,
<literal>icmp</literal>, or a number, if you know the IP protocol
number.<footnote id="X-087-2-X-087-2-FW-FN06"><para>
Take a look at <filename>/etc/protocols</filename> for protocol names and numbers.
</para>
</footnote>
For example, you might use <literal>4</literal> to match the
<literal>ipip</literal> encapsulation protocol. If the <literal>!</literal>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-s [!]address[/mask]</term>
<listitem><para>
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 <literal>mask</literal> 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).
</para></listitem>
</varlistentry>
<varlistentry>
<term>-d [!]address[/mask]</term>
<listitem><para>
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
<option>-s</option> parameter.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-j target</term>
<listitem><para>
Specifies what action to take when this rule matches. You can think of
this parameter as meaning &ldquo;jump to.&rdquo; Valid targets are
<literal>ACCEPT</literal>, <literal>DROP</literal>, <literal>QUEUE</literal>,
and <literal>RETURN</literal>. 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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-i [!]interface-name</term>
<listitem><para>
<?troff .hw separated>
Specifies the interface on which the datagram was received. Again, the
<literal>!</literal> inverts the result of the match. If the interface name
ends with &ldquo;<literal>+</literal>&rdquo; then any interface that begins
with the supplied string will match. For example, <literal>-i ppp+</literal>
would match any PPP network device and <literal>-i ! eth+</literal> would
match all interfaces except ethernet devices.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-o [!]interface-name</term>
<listitem><para>
Specifies the interface on which the datagram is to be transmitted. This
argument has the same coding as the <option>-i</option> argument.
</para></listitem>
</varlistentry>
<varlistentry>
<term>[!] -f</term>
<listitem><para>
Specifies that this rule applies only to the second and later fragments
of a fragmented datagram, not to the first fragment.
</para></listitem>
</varlistentry>
</variablelist>
</sect3>
<sect3 id="X-087-2-firewall.iptables.options"><title>Options</title>
<para>
The following <command>iptables</command> options are more general in nature.
Some of them control rather esoteric features of the
<emphasis>netfilter</emphasis> software.
</para>
<variablelist>
<varlistentry>
<term>-v</term>
<listitem><para>
causes <command>iptables</command> to be verbose in its output; it
will supply more information.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-n</term>
<listitem><para>
causes <command>iptables</command> to display IP address and ports as
numbers without attempting to resolve them to their corresponding names.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-x</term>
<listitem><para>
causes any numbers in the <command>iptables</command> output to be
expanded to their exact values with no rounding.
</para></listitem>
</varlistentry>
<varlistentry>
<term>- -line-numbers</term>
<listitem><para>
causes line numbers to be displayed when listing rulesets. The line number
will correspond to the rule's position within the chain.
</para></listitem>
</varlistentry>
</variablelist>
</sect3>
<sect3 id="X-087-2-firewall.iptables.extensions"><title>Extensions</title>
<para>
<INDEXTERM><PRIMARY>iptables command</PRIMARY><SECONDARY>extensions</SECONDARY></INDEXTERM>
We said earlier that the <command>iptables</command> utility is
extensible through optional shared library modules. There are some standard
extensions that provide some of the features <command>ipchains</command>
provided. To make use of an extension, you must specify its name through the
<option>-m</option> <replaceable>name</replaceable> argument to
<command>iptables</command>. The following list shows the
<option>-m</option> and <option>-p</option> options that set up the extension's
context, and the options provided by
that extension.
</para>
<sect4><title>TCP Extensions: used with -m tcp -p tcp</title>
<variablelist>
<varlistentry>
<term>- -sport [!] [port[:port]]</term>
<listitem><para>
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, <literal>20:25</literal>
described all of the ports numbered 20 up to and including 25. Again, the
<literal>!</literal> character may be used to negate the values.
</para></listitem>
</varlistentry>
<varlistentry>
<term>- -dport [!] [port[:port]]</term>
<listitem><para>
Specifies the port that the datagram destination must be using to match this
rule. The argument is coded identically to the <option>- -sport</option>
option.
</para></listitem>
</varlistentry>
<varlistentry>
<term>- -tcp-flags [!] mask comp</term>
<listitem><para>
<indexterm><primary>RFC-793</primary></indexterm>
Specifies that this rule should match when the TCP flags in the
datagram match those specified by <replaceable>mask</replaceable> and
<replaceable>comp</replaceable>. <replaceable>mask</replaceable> is a
comma-separated list of flags that should be examined when making the
test. <replaceable>comp</replaceable> is a comma-separated list of
flags that must be set for the rule to match. Valid flags are:
<emphasis>SYN</emphasis>, <emphasis>ACK</emphasis>,
<emphasis>FIN</emphasis>, <emphasis>RST</emphasis>,
<emphasis>URG</emphasis>, <emphasis>PSH</emphasis>, <emphasis>ALL</emphasis>
or <emphasis>NONE</emphasis>. 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 <literal>!</literal> character negates the rule.
</para></listitem>
</varlistentry>
<varlistentry>
<term>[!] - -syn</term>
<listitem><para>
Specifies the rule to match only datagrams with the
<literal>SYN</literal> bit set and the <literal>ACK</literal> and
<literal>FIN</literal> 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:
<screen>
<literal>- -tcp-flags SYN,RST,ACK SYN</literal>
</screen>
When you use the negation
operator, the rule will match all datagrams that do not have both the
<literal>SYN</literal> and <literal>ACK</literal> bits set.
</para></listitem>
</varlistentry>
</variablelist>
</sect4>
<sect4>
<title>UDP Extensions: used with -m udp -p udp</title>
<variablelist>
<varlistentry>
<term>- -sport [!] [port[:port]]</term>
<listitem><para>
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, <literal>20:25</literal>
describes all of the ports numbered 20 up to and including 25. Again, the
<literal>!</literal> character may be used to negate the values.
</para></listitem>
</varlistentry>
<varlistentry>
<term>- -dport [!] [port[:port]]</term>
<listitem><para>
Specifies the port that the datagram destination must be using to match this
rule. The argument is coded identically to the <option>- -sport</option>
option.
</para></listitem>
</varlistentry>
</variablelist>
</sect4>
<sect4>
<title>ICMP Extensions: used with <literal>-m icmp -p icmp</literal></title>
<variablelist>
<varlistentry>
<term>- -icmp-type [!] typename</term>
<listitem><para>
<?troff .hw protocol-un-reachable>
Specifies the ICMP message type that this rule will match. The type may be
specified by number or name. Some valid names are:
<literal>echo-request</literal>, <literal>echo-reply</literal>,
<literal>source-quench</literal>, <literal>time-exceeded</literal>,
<literal>destination-unreachable</literal>,
<literal>network-unreachable</literal>, <literal>host-unreachable</literal>,
<literal>protocol-unreachable</literal>, and
<literal>port-unreachable</literal>.
</para></listitem>
</varlistentry>
</variablelist>
</sect4>
<sect4>
<title>MAC Extensions: used with <literal>-m mac</literal></title>
<variablelist>
<varlistentry>
<term>- -mac-source [!] address</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
</variablelist>
</sect4>
</sect3>
<INDEXTERM startref="iptables.firewall.options" class=endofrange>
</sect2>
<sect2><title>Our Na&iuml;ve Example Revisited, Yet Again</title>
<para>
To implement our na&iuml;ve example using the <emphasis>netfilter</emphasis>,
you could simply load the <filename>ipchains.o</filename> module and pretend
it is the <command>ipchains</command> version. Instead, we'll reimplement
it using <command>iptables</command> to illustrate how similar it is.
</para>
<para>
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.
</para>
<para>
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 <command>iptables</command> rules:
<screen width=83>
<prompt>#</prompt> <userinput>modprobe ip_tables</userinput>
<prompt>#</prompt> <userinput>iptables -F FORWARD</userinput>
<prompt>#</prompt> <userinput>iptables -P FORWARD DROP</userinput>
<prompt>#</prompt> <userinput>iptables -A FORWARD -m tcp -p tcp -s 0/0 --sport 80 -d 172.16.1.0/24 /
--syn -j DROP</userinput>
<prompt>#</prompt> <userinput>iptables -A FORWARD -m tcp -p tcp -s 172.16.1.0/24 --sport /
80 -d 0/0 -j ACCEPT</userinput>
<prompt>#</prompt> <userinput>iptables -A FORWARD -m tcp -p tcp -d 172.16.1.0/24 --dport 80 -s 0/0 -j /
ACCEPT</userinput>
</screen>
</para>
<?troff .Nd 10>
<para>
In this example the <command>iptables</command> commands are interpreted
exactly as the equivalent <command>ipchains</command> commands. The major
exception that the <filename>ip_tables.o</filename>
module must load. Note that <command>iptables</command> doesn't support the
<option>-b</option> option, so we must supply a rule for each
direction.
</para>
</sect2>
<INDEXTERM startref="firewalls.netfilter" class=endofrange>
<INDEXTERM startref="Linux.2.4.kernels" class=endofrange>
<INDEXTERM startref="netfilter.IP.tables" class=endofrange>
</sect1>
<sect1 id="X-087-2-firewall.tos.manipulation"><title>TOS Bit Manipulation</title>
<para>
<INDEXTERM id="firewalls.TOS.bit.manip" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>TOS bit manipulation</SECONDARY></INDEXTERM>
<INDEXTERM id="ip.TOS.bits" class=startofrange><PRIMARY>IP (Internet Protocol)</PRIMARY><SECONDARY>TOS (Type Of Service) bits</SECONDARY></INDEXTERM>
<INDEXTERM id="TOS.bits.manip" class=startofrange><PRIMARY>TOS (Type Of Service) bits, manipulating</PRIMARY></INDEXTERM>
The Type Of Service (TOS) bits are a set of four-bit flags in
the IP header. When any one of these bit flags is set, routers may handle the
datagram differently than datagrams with no TOS bits set. Each of the four bits
has a different purpose and only one of the TOS bits may be set at any time, so
combinations are not allowed. The bit flags are called Type of Service bits
because they enable the application transmitting the data to tell the network
the type of network service it requires.
</para>
<para>
The classes of network service available are:
</para>
<variablelist>
<varlistentry><term>Minimum delay</term>
<listitem><para>
Used when the time it takes for a datagram to travel from the source host
to destination host (latency) is most important. A network provider might, for
example, use both optical fiber and satellite network connections. Data carried
across satellite connections has farther to travel and their latency is
generally therefore higher than for terrestrial-based network connections
between the same endpoints. A network provider might choose to ensure that
datagrams with this type of service set are not carried by satellite.
</para></listitem>
</varlistentry>
<varlistentry><term>Maximum throughput</term>
<listitem><para>
Used when the volume of data transmitted in any period of time is
important. There are many types of network applications for which latency
is not particularly important but the network throughput is; for
example, bulk-file transfers. A network provider might choose to route
datagrams with this type of service set via high-latency,
high-bandwidth routes, such as satellite connections.
</para></listitem>
</varlistentry>
<varlistentry><term>Maximum reliability</term>
<listitem><para>
Used when it is important that you have some certainty that the data
will arrive at the destination without retransmission being
required. The IP protocol may be carried over any number of underlying
transmission mediums. While SLIP and PPP are adequate datalink
protocols, they are not as reliable as carrying IP over some other
network, such as an X.25 network. A network provider might make
an alternate network available, offering high reliability, to carry IP
that would be used if this type of service is selected.
</para></listitem>
</varlistentry>
<varlistentry><term>Minimum cost</term>
<listitem><para>
Used when it is important to minimize the cost of data
transmission. Leasing bandwidth on a satellite for a transpacific
crossing is generally less costly than leasing space on a
fiber-optical cable over the same distance, so network providers may
choose to provide both and charge differently depending on which you
use. In this scenario, your &ldquo;minimum cost&rdquo; type of service
bit may cause your datagrams to be routed via the lower-cost satellite
route.
</para></listitem>
</varlistentry>
</variablelist>
<sect2><title>Setting the TOS Bits Using ipfwadm or ipchains</title>
<para>
<INDEXTERM><PRIMARY>ipfwadm command</PRIMARY><SECONDARY>setting the TOS bits</SECONDARY></INDEXTERM>
<INDEXTERM><PRIMARY>ipchains command</PRIMARY><SECONDARY>setting the TOS bits</SECONDARY></INDEXTERM>
The <command>ipfwadm</command> and <command>ipchains</command> commands deal
with the TOS bits in much the same manner. In both cases you specify a rule
that matches the datagrams with particular TOS bits set, and
use the <option>-t</option> argument to specify the change you wish to make.
</para>
<para>
The changes are specified using two-bit masks. The first of these bit masks is
logically ANDed with the IP options field of the datagram and the second is
logically eXclusive-ORd with it. If this sounds complicated, we'll give you
the recipes required to enable each of the types of service in a moment.
</para>
<para>
The bit masks are specified using eight-bit hexadecimal values. Both
<command>ipfwadm</command> and <command>ipchains</command> use the same
argument syntax:
<screen width=80>
<literal>-t <replaceable>andmask</replaceable> <replaceable>xormask</replaceable></literal>
</screen>
</para>
<para>
Fortunately the same mask arguments can be used each time you wish to set a
particular type of service, to save you having to work them out. They are
presented with some suggested uses in
<xref linkend="X-087-2-firewall.ipchains.tos.recipes">.
</para>
<table id="X-087-2-firewall.ipchains.tos.recipes">
<title>Suggested Uses for TOS Bitmasks</title>
<tgroup cols=4><colspec colnum="1" colwidth="1.50i">
<thead>
<row>
<entry>TOS</entry>
<entry>ANDmask</entry>
<entry>XORmask</entry>
<entry>Suggested Use</entry>
</row>
</thead>
<tbody>
<row>
<entry>Minimum Delay</entry>
<entry><literal>0x01</literal></entry>
<entry><literal>0x10</literal></entry>
<entry>ftp, telnet, ssh</entry>
</row>
<row>
<entry>Maximum Throughput</entry>
<entry><literal>0x01</literal></entry>
<entry><literal>0x08</literal></entry>
<entry>ftp-data, www</entry>
</row>
<row>
<entry>Maximum Reliability</entry>
<entry><literal>0x01</literal></entry>
<entry><literal>0x04</literal></entry>
<entry>snmp, dns</entry>
</row>
<row>
<entry>Minimum Cost</entry>
<entry><literal>0x01</literal></entry>
<entry><literal>0x02</literal></entry>
<entry>nntp, smtp</entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2><title>Setting the TOS Bits Using iptables</title>
<para>
<INDEXTERM><PRIMARY>iptables command</PRIMARY><SECONDARY>setting the TOS bits</SECONDARY></INDEXTERM>
The <command>iptables</command> tool allows you to specify rules that
capture only datagrams with TOS bits matching some predetermined value
using the <option>-m tos</option> option, and for setting the TOS
bits of IP datagrams matching a rule using the <literal>-j
TOS</literal> target. You may set TOS bits only on the
<literal>FORWARD</literal> and <literal>OUTPUT</literal> chains. The
matching and the setting occur quite independently. You can configure
all sort of interesting rules. For example, you can configure a rule
that discads all datagrams with certain TOS bit combinations, or a
rule that sets the TOS bits of datagrams only from certain hosts. Most
often you will use rules that contain both matching and setting to
perform TOS bit translations, just as you could for
<command>ipfwadm</command> or <command>ipchains</command>.
</para>
<para>
Rather than the complicated two-mask configuration of
<command>ipfwadm</command> and <command>ipchains</command>,
<command>iptables</command> uses the simpler approach of plainly specifying
what the TOS bits should match, or to what the TOS bits should be set.
Additionally, rather than having to remember and use the hexadecimal value,
you may specify the TOS bits using the more friendly mnemonics listed in
the upcoming table.
</para>
<para>
The general syntax used to match TOS bits looks like:
<screen>
<literal>-m tos --tos <replaceable>mnemonic</replaceable> [<replaceable>other-args</replaceable>] -j <replaceable>target</replaceable></literal>
</screen>
</para>
<para>
The general syntax used to set TOS bits looks like:
<screen>
<literal>[<replaceable>other-args</replaceable>] -j TOS --set <replaceable>mnemonic</replaceable></literal>
</screen>
</para>
<para>
Remember that these would typically be used together, but they can be
used quite independently if you have a configuration that
requires it.
</para>
<informaltable id="X-087-2-firewall.iptables.tos.recipes">
<tgroup cols=2>
<thead>
<row><entry>Mnemonic</entry><entry>Hexadecimal</entry></row>
</thead>
<tbody>
<row><entry>Normal-Service</entry><entry>0x00</entry></row>
<row><entry>Minimize-Cost</entry><entry>0x02</entry></row>
<row><entry>Maximize-Reliability</entry><entry>0x04</entry></row>
<row><entry>Maximize-Throughput</entry><entry>0x08</entry></row>
<row><entry>Minimize-Delay</entry><entry>0x10</entry></row>
</tbody>
</tgroup>
</informaltable>
</sect2>
<INDEXTERM startref="firewalls.TOS.bit.manip" class=endofrange>
<INDEXTERM startref="ip.TOS.bits" class=endofrange>
<INDEXTERM startref="TOS.bits.manip" class=endofrange>
</sect1>
<sect1 id="X-087-2-firewall.checkingconf"><title>Testing a
Firewall Configuration</title>
<para>
<INDEXTERM id="firewall.test.config" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>testing a configuration</SECONDARY></INDEXTERM>
After you've designed an appropriate firewall configuration, it's
important to validate that it does in fact do what you want it to
do. One way to do this is to use a test host outside your network to
attempt to pierce your firewall: this can be quite clumsy and
slow, though, and is limited to testing only those addresses that you can
actually use.
</para>
<para>
A faster and easier method is available with the Linux firewall
implementation. It allows you to manually generate tests and run them
through the firewall configuration just as if you were testing with
actual datagrams. All varieties of the Linux kernel firewall software,
<command>ipfwadm</command>, <command>ipchains</command>, and
<command>iptables</command>, provide support for this style of
testing. The implementation involves use of the relevant
<emphasis>check</emphasis> command.
</para>
<para>
The general test procedure is as follows:
</para>
<orderedlist>
<listitem><para>
Design and configure your firewall using <command>ipfwadm</command>,
<command>ipchains</command>, or <command>iptables</command>.
</para></listitem>
<listitem><para>
Design a series of tests that will determine whether your firewall is
actually working as you intend. For these tests you may use any source
or destination address, so choose some address combinations that
should be accepted and some others that should be dropped. If you're
allowing or disallowing only certain ranges of addresses, it is a good
idea to test addresses on either side of the boundary of the
range&mdash;one address just inside the boundary and one address just
outside the boundary. This will help ensure that you have the correct
boundaries configured, because it is sometimes easy to specify
netmasks incorrectly in your configuration. If you're filtering by
protocol and port number, your tests should also check all important
combinations of these parameters. For example, if you intend to accept
only TCP under certain circumstances, check that UDP datagrams are
dropped.
</para></listitem>
<listitem><para>
Develop <command>ipfwadm</command>, <command>ipchains</command>, or
<command>iptables</command> rules to implement each test. It is
probably worthwhile to write all the rules into a script so you can
test and re-test easily as you correct mistakes or change your
design. Tests use almost the same syntax as rule specifications, but
the arguments take on slightly differing meanings. For example, the
source address argument in a rule specification specifies the source
address that datagrams matching this rule should have. The source
address argument in test syntax, in contrast, specifies the source
address of the test datagram that will be generated. For
<command>ipfwadm</command>, you must use the <option>&ndash;c</option>
option to specify that this command is a test, while for
<command>ipchains</command> and <command>iptables</command>, you must
use the <option>&ndash;C</option> option. In all cases you must
<emphasis>always</emphasis> specify the source address, destination
address, protocol, and interface to be used for the test. Other
arguments, such as port numbers or TOS bit settings, are optional.
</para></listitem>
<listitem><para>
Execute each test command and note the output. The output of each test
will be a single word indicating the final target of the datagram
after running it through the firewall configuration&mdash;that is,
where the processing ended. For <command>ipchains</command> and
<command>iptables</command>, user-specified chains will be tested
in addition to the built-in ones.
</para></listitem>
<listitem><para>
Compare the output of each test against the desired result. If there
are any discrepancies, you will need to analyse your ruleset to
determine where you've made the error. If you've written your test
commands into a script file, you can easily rerun the test after
correcting any errors in your firewall configuration. It's a good
practice to flush your rulesets completely and rebuild them from
scratch, rather than to make changes dynamically. This helps ensure
that the active configuration you are testing actually reflects the
set of commands in your configuration script.
</para></listitem>
</orderedlist>
<para>
Let's take a quick look at what a manual test transcript would look
like for our na&iuml;ve example with <command>ipchains</command>. You will remember that our
local network in the example was 172.16.1.0 with a netmask of
255.255.255.0, and we were to allow TCP connections out to web servers
on the net. Nothing else was to pass our forward chain. Start with a
transmission that we know should work, a connection from a local host
to a web server outside:
<screen>
# <userinput>ipchains -C forward -p tcp -s 172.16.1.0 1025 -d 44.136.8.2 80 -i eth0</userinput>
accepted
</screen>
</para>
<para>
Note the arguments had to be supplied and the way they've been used to
describe a datagram. The output of the command indicates that the
datagram was accepted for forwarding, which is what we hoped for.
</para>
<para>
Now try another test, this time with a source address that doesn't
belong to our network. This one should be denied:
<screen>
# <userinput>ipchains -C forward -p tcp -s 172.16.2.0 1025 -d 44.136.8.2 80 -i eth0</userinput>
denied
</screen>
</para>
<para>
Try some more tests, this time with the same details as the first test,
but with different protocols. These should be denied, too:
<screen>
# <userinput>ipchains -C forward -p udp -s 172.16.1.0 1025 -d 44.136.8.2 80 -i eth0</userinput>
denied
# <userinput>ipchains -C forward -p icmp -s 172.16.1.0 1025 -d 44.136.8.2 80 -i eth0</userinput>
denied
</screen>
</para>
<para>
Try another destination port, again expecting it to be denied:
<screen>
# <userinput>ipchains -C forward -p tcp -s 172.16.1.0 1025 -d 44.136.8.2 23 -i eth0</userinput>
denied
</screen>
</para>
<para>
You'll go a long way toward achieving peace of mind if you design a series
of exhaustive tests. While this can sometimes be as difficult as designing
the firewall configuration, it's also the best way of knowing
that your design
is providing the security you expect of it.
</para>
<INDEXTERM startref="firewall.test.config" class=endofrange>
</sect1>
<sect1 id="X-087-2-firewall.example"><title>A Sample Firewall Configuration</title>
<para>
<INDEXTERM id="firewalls.samp.config" class=startofrange><PRIMARY>firewalls</PRIMARY><SECONDARY>sample configuration</SECONDARY></INDEXTERM>
We've discussed the fundamentals of firewall configuration. Let's now
look at what a firewall configuration might actually look like.
</para>
<para>
The configuration in this example has been designed to be easily
extended and customized. We've provided three versions. The first
version is implemented using the <command>ipfwadm</command> command
(or the <command>ipfwadm-wrapper</command> script), the second uses
<command>ipchains</command>, and the third uses
<command>iptables</command>. The example doesn't attempt to exploit
user-defined chains, but it will show you the similarities and
differences between the old and new firewall configuration tool
syntaxes:
</para>
<programlisting width=80>
#!/bin/bash
##########################################################################
# IPFWADM VERSION
# This sample configuration is for a single host firewall configuration
# with no services supported by the firewall machine itself.
##########################################################################
# USER CONFIGURABLE SECTION
# The name and location of the ipfwadm utility. Use ipfwadm-wrapper for
# 2.2.* kernels.
IPFWADM=ipfwadm
# The path to the ipfwadm executable.
PATH="/sbin"
# Our internal network address space and its supporting network device.
OURNET="172.29.16.0/24"
OURBCAST="172.29.16.255"
OURDEV="eth0"
# The outside address and the network device that supports it.
ANYADDR="0/0"
ANYDEV="eth1"
# The TCP services we wish to allow to pass - "" empty means all ports
# note: space separated
TCPIN="smtp www"
TCPOUT="smtp www ftp ftp-data irc"
# The UDP services we wish to allow to pass - "" empty means all ports
# note: space separated
UDPIN="domain"
UDPOUT="domain"
# The ICMP services we wish to allow to pass - "" empty means all types
# ref: /usr/include/netinet/ip_icmp.h for type numbers
# note: space separated
ICMPIN="0 3 11"
ICMPOUT="8 3 11"
# Logging; uncomment the following line to enable logging of datagrams
# that are blocked by the firewall.
# LOGGING=1
# END USER CONFIGURABLE SECTION
###########################################################################
# Flush the Incoming table rules
$IPFWADM -I -f
# We want to deny incoming access by default.
$IPFWADM -I -p deny
# SPOOFING
# We should not accept any datagrams with a source address matching ours
# from the outside, so we deny them.
$IPFWADM -I -a deny -S $OURNET -W $ANYDEV
# SMURF
# Disallow ICMP to our broadcast address to prevent "Smurf" style attack.
$IPFWADM -I -a deny -P icmp -W $ANYDEV -D $OURBCAST
# TCP
# We will accept all TCP datagrams belonging to an existing connection
# (i.e. having the ACK bit set) for the TCP ports we're allowing through.
# This should catch more than 95 % of all valid TCP packets.
$IPFWADM -I -a accept -P tcp -D $OURNET $TCPIN -k -b
# TCP - INCOMING CONNECTIONS
# We will accept connection requests from the outside only on the
# allowed TCP ports.
$IPFWADM -I -a accept -P tcp -W $ANYDEV -D $OURNET $TCPIN -y
# TCP - OUTGOING CONNECTIONS
# We accept all outgoing tcp connection requests on allowed TCP ports.
$IPFWADM -I -a accept -P tcp -W $OURDEV -D $ANYADDR $TCPOUT -y
# UDP - INCOMING
# We will allow UDP datagrams in on the allowed ports.
$IPFWADM -I -a accept -P udp -W $ANYDEV -D $OURNET $UDPIN
# UDP - OUTGOING
# We will allow UDP datagrams out on the allowed ports.
$IPFWADM -I -a accept -P udp -W $OURDEV -D $ANYADDR $UDPOUT
# ICMP - INCOMING
# We will allow ICMP datagrams in of the allowed types.
$IPFWADM -I -a accept -P icmp -W $ANYDEV -D $OURNET $UDPIN
# ICMP - OUTGOING
# We will allow ICMP datagrams out of the allowed types.
$IPFWADM -I -a accept -P icmp -W $OURDEV -D $ANYADDR $UDPOUT
# DEFAULT and LOGGING
# All remaining datagrams fall through to the default
# rule and are dropped. They will be logged if you've
# configured the LOGGING variable above.
#
if [ "$LOGGING" ]
then
# Log barred TCP
$IPFWADM -I -a reject -P tcp -o
# Log barred UDP
$IPFWADM -I -a reject -P udp -o
# Log barred ICMP
$IPFWADM -I -a reject -P icmp -o
fi
#
# end.
</programlisting>
<?troff .Nd 10>
<para>
Now we'll reimplement it using the <command>ipchains</command> command:
</para>
<programlisting width=80>
#!/bin/bash
##########################################################################
# IPCHAINS VERSION
# This sample configuration is for a single host firewall configuration
# with no services supported by the firewall machine itself.
##########################################################################
# USER CONFIGURABLE SECTION
# The name and location of the ipchains utility.
IPCHAINS=ipchains
# The path to the ipchains executable.
PATH="/sbin"
# Our internal network address space and its supporting network device.
OURNET="172.29.16.0/24"
OURBCAST="172.29.16.255"
OURDEV="eth0"
# The outside address and the network device that supports it.
ANYADDR="0/0"
ANYDEV="eth1"
# The TCP services we wish to allow to pass - "" empty means all ports
# note: space separated
TCPIN="smtp www"
TCPOUT="smtp www ftp ftp-data irc"
# The UDP services we wish to allow to pass - "" empty means all ports
# note: space separated
UDPIN="domain"
UDPOUT="domain"
# The ICMP services we wish to allow to pass - "" empty means all types
# ref: /usr/include/netinet/ip_icmp.h for type numbers
# note: space separated
ICMPIN="0 3 11"
ICMPOUT="8 3 11"
# Logging; uncomment the following line to enable logging of datagrams
# that are blocked by the firewall.
# LOGGING=1
# END USER CONFIGURABLE SECTION
##########################################################################
# Flush the Input table rules
$IPCHAINS -F input
# We want to deny incoming access by default.
$IPCHAINS -P input deny
# SPOOFING
# We should not accept any datagrams with a source address matching ours
# from the outside, so we deny them.
$IPCHAINS -A input -s $OURNET -i $ANYDEV -j deny
# SMURF
# Disallow ICMP to our broadcast address to prevent "Smurf" style attack.
$IPCHAINS -A input -p icmp -w $ANYDEV -d $OURBCAST -j deny
# We should accept fragments, in ipchains we must do this explicitly.
$IPCHAINS -A input -f -j accept
# TCP
# We will accept all TCP datagrams belonging to an existing connection
# (i.e. having the ACK bit set) for the TCP ports we're allowing through.
# This should catch more than 95 % of all valid TCP packets.
$IPCHAINS -A input -p tcp -d $OURNET $TCPIN ! -y -b -j accept
# TCP - INCOMING CONNECTIONS
# We will accept connection requests from the outside only on the
# allowed TCP ports.
$IPCHAINS -A input -p tcp -i $ANYDEV -d $OURNET $TCPIN -y -j accept
# TCP - OUTGOING CONNECTIONS
# We accept all outgoing TCP connection requests on allowed TCP ports.
$IPCHAINS -A input -p tcp -i $OURDEV -d $ANYADDR $TCPOUT -y -j accept
# UDP - INCOMING
# We will allow UDP datagrams in on the allowed ports.
$IPCHAINS -A input -p udp -i $ANYDEV -d $OURNET $UDPIN -j accept
# UDP - OUTGOING
# We will allow UDP datagrams out on the allowed ports.
$IPCHAINS -A input -p udp -i $OURDEV -d $ANYADDR $UDPOUT -j accept
# ICMP - INCOMING
# We will allow ICMP datagrams in of the allowed types.
$IPCHAINS -A input -p icmp -w $ANYDEV -d $OURNET $UDPIN -j accept
# ICMP - OUTGOING
# We will allow ICMP datagrams out of the allowed types.
$IPCHAINS -A input -p icmp -i $OURDEV -d $ANYADDR $UDPOUT -j accept
# DEFAULT and LOGGING
# All remaining datagrams fall through to the default
# rule and are dropped. They will be logged if you've
# configured the LOGGING variable above.
#
if [ "$LOGGING" ]
then
# Log barred TCP
$IPCHAINS -A input -p tcp -l -j reject
# Log barred UDP
$IPCHAINS -A input -p udp -l -j reject
# Log barred ICMP
$IPCHAINS -A input -p icmp -l -j reject
fi
#
# end.
</programlisting>
<para>
In our <command>iptables</command> example, we've switched to using
the <literal>FORWARD</literal> ruleset because of the difference in
meaning of the <literal>INPUT</literal> ruleset in the
<emphasis>netfilter</emphasis> implementation. This has implications
for us; it means that none of the rules protect the firewall host
itself. To accurately mimic our <command>ipchains</command> example,
we would replicate each of our rules in the <literal>INPUT</literal>
chain. For clarity, we've dropped all incoming datagrams received from
our outside interface instead.
</para>
<programlisting width=103>
#!/bin/bash
##########################################################################
# IPTABLES VERSION
# This sample configuration is for a single host firewall configuration
# with no services supported by the firewall machine itself.
##########################################################################
# USER CONFIGURABLE SECTION
# The name and location of the ipchains utility.
IPTABLES=iptables
# The path to the ipchains executable.
PATH="/sbin"
# Our internal network address space and its supporting network device.
OURNET="172.29.16.0/24"
OURBCAST="172.29.16.255"
OURDEV="eth0"
# The outside address and the network device that supports it.
ANYADDR="0/0"
ANYDEV="eth1"
# The TCP services we wish to allow to pass - "" empty means all ports
# note: comma separated
TCPIN="smtp,www"
TCPOUT="smtp,www,ftp,ftp-data,irc"
# The UDP services we wish to allow to pass - "" empty means all ports
# note: comma separated
UDPIN="domain"
UDPOUT="domain"
# The ICMP services we wish to allow to pass - "" empty means all types
# ref: /usr/include/netinet/ip_icmp.h for type numbers
# note: comma separated
ICMPIN="0,3,11"
ICMPOUT="8,3,11"
# Logging; uncomment the following line to enable logging of datagrams
# that are blocked by the firewall.
# LOGGING=1
# END USER CONFIGURABLE SECTION
###########################################################################
# Flush the Input table rules
$IPTABLES -F FORWARD
# We want to deny incoming access by default.
$IPTABLES -P FORWARD deny
# Drop all datagrams destined for this host received from outside.
$IPTABLES -A INPUT -i $ANYDEV -j DROP
# SPOOFING
# We should not accept any datagrams with a source address matching ours
# from the outside, so we deny them.
$IPTABLES -A FORWARD -s $OURNET -i $ANYDEV -j DROP
# SMURF
# Disallow ICMP to our broadcast address to prevent "Smurf" style attack.
$IPTABLES -A FORWARD -m multiport -p icmp -i $ANYDEV -d $OURNET -j DENY
# We should accept fragments, in iptables we must do this explicitly.
$IPTABLES -A FORWARD -f -j ACCEPT
# TCP
# We will accept all TCP datagrams belonging to an existing connection
# (i.e. having the ACK bit set) for the TCP ports we're allowing through.
# This should catch more than 95 % of all valid TCP packets.
$IPTABLES -A FORWARD -m multiport -p tcp -d $OURNET --dports $TCPIN /
! --tcp-flags SYN,ACK ACK -j ACCEPT
$IPTABLES -A FORWARD -m multiport -p tcp -s $OURNET --sports $TCPIN /
! --tcp-flags SYN,ACK ACK -j ACCEPT
# TCP - INCOMING CONNECTIONS
# We will accept connection requests from the outside only on the
# allowed TCP ports.
$IPTABLES -A FORWARD -m multiport -p tcp -i $ANYDEV -d $OURNET $TCPIN /
--syn -j ACCEPT
# TCP - OUTGOING CONNECTIONS
# We will accept all outgoing tcp connection requests on the allowed /
TCP ports.
$IPTABLES -A FORWARD -m multiport -p tcp -i $OURDEV -d $ANYADDR /
--dports $TCPOUT --syn -j ACCEPT
<?troff .sp -12p>
# UDP - INCOMING
# We will allow UDP datagrams in on the allowed ports and back.
$IPTABLES -A FORWARD -m multiport -p udp -i $ANYDEV -d $OURNET /
--dports $UDPIN -j ACCEPT
$IPTABLES -A FORWARD -m multiport -p udp -i $ANYDEV -s $OURNET /
--sports $UDPIN -j ACCEPT
<?troff .sp -12p>
# UDP - OUTGOING
# We will allow UDP datagrams out to the allowed ports and back.
$IPTABLES -A FORWARD -m multiport -p udp -i $OURDEV -d $ANYADDR /
--dports $UDPOUT -j ACCEPT
$IPTABLES -A FORWARD -m multiport -p udp -i $OURDEV -s $ANYADDR /
--sports $UDPOUT -j ACCEPT
<?troff .sp -12p>
# ICMP - INCOMING
# We will allow ICMP datagrams in of the allowed types.
$IPTABLES -A FORWARD -m multiport -p icmp -i $ANYDEV -d $OURNET /
--dports $ICMPIN -j ACCEPT
<?troff .sp -12p>
# ICMP - OUTGOING
# We will allow ICMP datagrams out of the allowed types.
$IPTABLES -A FORWARD -m multiport -p icmp -i $OURDEV -d $ANYADDR /
--dports $ICMPOUT -j ACCEPT
<?troff .sp -12p>
# DEFAULT and LOGGING
# All remaining datagrams fall through to the default
# rule and are dropped. They will be logged if you've
# configured the LOGGING variable above.
#
if [ "$LOGGING" ]
then
# Log barred TCP
$IPTABLES -A FORWARD -m tcp -p tcp -j LOG
<?troff .sp -12p>
# Log barred UDP
$IPTABLES -A FORWARD -m udp -p udp -j LOG
<?troff .sp -12p>
# Log barred ICMP
$IPTABLES -A FORWARD -m udp -p icmp -j LOG
fi
#
# end.
</programlisting>
<para>
In many simple situations, to use the sample all you have to do is edit
the top section of the file labeled &ldquo;USER
CONFIGURABLE section&rdquo; to specify which protocols and datagrams
type you wish to allow in and out. For more complex configurations,
you will need to edit the section at the bottom, as well. Remember,
this is a simple example, so scrutinize it very carefully to ensure it
does what you want while implementing it.
</para>
<INDEXTERM startref="firewalls.samp.config" class=endofrange>
</sect1>
<indexterm class="endofrange" startref="chfw.tcp.ip.firewall">
<INDEXTERM startref="chfw.firewalls.tcp.ip" class=endofrange>
</chapter>