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.
The ipfwadm command was the configuration tool for the
second generation Linux IP firewall. Perhaps the simplest way to describe the
use of the ipfwadm command is by example. To begin, let's
code the example we presented earlier.
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.
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
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:
The -F command-line argument tells
ipfwadm that this is a forwarding rule.
The first command instructs ipfwadm to "flush" all
of the forwarding rules. This ensures we are working from a known
state before we begin adding specific rules.
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.
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.
Let's review each of the arguments:
This is a Forwarding rule.
Append this rule with the policy set to "accept," meaning we will forward
any datagrams that match this rule.
This rule applies to tcp datagrams (as opposed to UDP or ICMP).
The Source address must have the first 24 bits matching those of the
network address 172.16.1.0.
-D 0/0 80
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 /etc/services file to describe the
port, so -D 0/0 www would have worked just as well.
ipfwadm accepts network masks in a form with which you may
not be familiar. The /nn 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 Table 9-1.
Table 9-1. Common Netmask Bit Values
We mentioned earlier that ipfwadm implements a
small trick that makes adding these sorts of rules easier. This trick
is an option called -b, which makes the command a
The bidirectional flag allows us to collapse our two
rules into one as follows:
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?
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.
Fortunately there is a solution to this problem. The
ipfwadm 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:
The -y 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."
Why have we placed this special rule before 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 deny rule
before the accept rule.
After we've entered our rules, we ask ipfwadm to list
them for us using the command:
#ipfwadm -F -l
This command will list all of the configured forwarding rules. The output
should look something like this:
#ipfwadm -F -l
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
The ipfwadm command will attempt to translate the port
number into a service name using the /etc/services if
an entry exists there.
The default output is lacking in some important detail for us. In the
default listing output, we can't see the effect of the
-y argument. The ipfwadm command
is able to produce a more detailed listing output if you specify the
-e (extended output) argument too. We won't show the
whole output here because it is too wide for the page, but it includes
an opt (options) column that shows the -y option
controlling SYN packets:
#ipfwadm -F -l -e
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 ...
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.
We know that FTP uses two TCP ports: port 20 (ftp-data) and port 21 (ftp),
Right? Well, not necessarily. FTP servers
can operate in two different modes: passive mode and active
mode. 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 Figure 9-3.
Figure 9-3. FTP server modes
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
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.
The dilemna is most safely resolved by insisting that our users operate in
mode. Most FTP servers and many FTP clients will operate this way.
The popular ncftp client also supports passive mode, but
it may require a small configuration change to make it default to passive
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.
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.
At least one of the following must be supplied. Use the parameters
to specify to which datagrams this rule applies:
Can be TCP, UDP, ICMP, or all. Example:
-S address[/mask] [port]
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 -P 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 /etc/services 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:
lowport:highport. Here is an example:
-S 172.29.16.1/24 ftp:ftp-data
-D address[/mask] [port]
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:
-D 172.29.16.1/24 smtp
Specify the address of the network interface on which the packet is received
(-I ) or is being sent (-O). This
allows us to create rules that apply only to certain network interfaces on our
machine. Here is an example:
Specify the name of the network interface. This argument works in the same way
as the -V argument, except you supply the device name
instead of its address. Here is an example:
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.
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.
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.
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.
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
/usr/include/netinet/ip_icmp.h 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 Table 9-2. The
iptables command interface allows you to specify
ICMP types by name, so we've listed the mnemonics it uses, as well.