mirror of https://github.com/tLDP/LDP
3574 lines
136 KiB
Plaintext
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">”.
|
|
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 --->
|
|
.
|
|
<M> Userspace queueing via NETLINK (EXPERIMENTAL)
|
|
<M> IP tables support (required for filtering/masq/NAT)
|
|
<M> limit match support
|
|
<M> MAC address match support
|
|
<M> netfilter MARK match support
|
|
<M> Multiple port match support
|
|
<M> TOS match support
|
|
<M> Connection state match support
|
|
<M> Unclean match support (EXPERIMENTAL)
|
|
<M> Owner match support (EXPERIMENTAL)
|
|
<M> Packet filtering
|
|
<M> REJECT target support
|
|
<M> MIRROR target support (EXPERIMENTAL)
|
|
.
|
|
<M> Packet mangling
|
|
<M> TOS target support
|
|
<M> MARK target support
|
|
<M> LOG target support
|
|
<M> ipchains (2.2-style) support
|
|
<M> 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 “chaining” 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→3→5 represents our machine
|
|
routing data between a host on our Ethernet network to a host
|
|
reachable via our PPP link. The flows 1→2 and 4→5 represent
|
|
the data input and output flows of a network program running on our
|
|
local host. The flow 4→3→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ï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
|
|
“/32” 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,
|
|
“all” 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> ) 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 “IP Firewall Chains” 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 “jump to.” 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( )</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 “netlink” 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 “type of service” 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ï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
|
|
“tcpin.” 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> >/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> </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
|
|
“input” 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 “demasq” and “masq” 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 “jump to.” 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 “<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>-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ïve Example Revisited, Yet Again</title>
|
|
<para>
|
|
To implement our naï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 “minimum cost” 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—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>–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>–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—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ï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 “USER
|
|
CONFIGURABLE section” 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>
|