Section 26.4. Firewalls: Filtering IP Packets

Although TCP wrappers can be used to restrict the set of hosts that can establish connections to certain services on a machine, in many cases it is desirable to exert finer-grained control over the packets that can enter (or leave) a given system. It's also the case that TCP wrappers only work with services configured using inetd or xinetd; some services (such as sshd on some systems) are standalone and provide their own access control features. Still other services don't implement any access control themselves, so it's necessary to provide another level of protection if we wish to control the connections made to these services.

Today it is commonplace for Internet users to protect themselves against the threat of network-based attacks using a technique called IP filtering. IP filtering involves having the kernel inspect each network packet that is transmitted or received and deciding whether to allow it to pass, to throw it away, or to modify it in some way before allowing it through. IP filtering is often called firewalling, because by carefully filtering packets entering or leaving a machine, you are building a firewall between the system and the rest of the Internet. IP filtering won't protect you against virus and Trojan horse attacks or application defects, but it can protect you against many forms of network-based attacks, such as certain types of DoS attacks and IP spoofing (packets that are marked as coming from a system they don't really come from). IP filtering also provides an additional layer of access control that prevents unwanted users from trying to gain access to your system.

To make IP filtering work, we need to know which packets to allow and which to deny. Usually, the decision whether to filter a packet is based on the packet headers, which contain information such as the source and destination IP addresses, the protocol type (TCP, UDP, and so on), and the source and destination port numbers (which identify the particular service for which the packet is destined). Different network services use different protocols and port numbers; for example, most web servers receive requests on TCP port 80. If we wanted to filter out all incoming HTTP traffic from our system, we'd set up an IP filter that rejects all TCP packets destined for port 80.

Sometimes inspecting just the header of a packet is not sufficient to accomplish a particular filtering task, so we need to inspect and interpret the actual data carried within the packet. This technique is sometimes called stateful inspection because a packet is considered in the context of an ongoing network connection rather than in isolation. For example, we might want to allow users inside our network to use FTP servers outside our network. FTP is a complex protocol that uses one TCP connection to send commands to the server, but another to transfer the actual data. Unfortunately, the FTP specification does not mandate a particular port number for data transfers, so the client and server must negotiate port numbers using the command session. Without stateful packet inspection, allowing FTP transfers would require allowing TCP connections to arbitrary ports. Stateful inspection solves this problem by interpreting the port number negotiation between the client and server, and automatically allowing TCP packets on the negotiated port to pass through.

IP filtering is implemented by the Linux kernel, which contains code to inspect each packet that is received and transmitted, applying filtering rules that determine the fate of the packet. The rules are configured using a user-space configuration tool that accepts arguments from the command line and translates them into filter specifications that are stored and used as rules by the kernel.

There have been three generations of kernel-based IP filtering in Linux, and each has had its own configuration mechanism. The first generation was called ipfw (for "IP firewall") and provided basic filtering capability but was somewhat inflexible and inefficient for complex configurations. ipfw is rarely used now. The second generation of IP filtering, called IP chains, improved greatly on ipfw and is still in common use. The latest generation of filtering is called netfilter /iptables . netfilter is the kernel component, and iptables is the user-space configuration tool; these terms are often used interchangeably. netfilter is not only much more flexible to configure than earlier filters, but is extensible as well. In the following sections we describe netfilter and some simple configurations as examples.

26.4.1. netfilter Basics

netfilter is implemented in Linux kernels 2.4.0 and newer. The primary tool for manipulating and displaying the filtering tables is called iptables and is included in all current Linux distributions. The iptables command allows configuration of a rich and complex set of firewall rules and hence has a large number of command-line options. We address the most common of these here. The iptables manpage offers a complete explanation.

Just to whet your appetite, take a look at a sneak preview of where we're heading:

iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

This command installs an IP filtering rule that accepts new incoming connections to TCP port 22 (the ssh service) on our local system. It also uses an extension module called state to perform connection tracking. On the following pages we explain how all this works.

An important concept in netfilter is the notion of a chain, which consists of a list of rules that are applied to packets as they enter, leave, or traverse the system. The kernel defines three chains by default, but the administrator can specify new chains of rules and link them to the predefined chains. The three predefined chains are as follows:


This chain applies to packets that are received by and are destined for the local system.


This chain applies to packets that are transmitted by the local system.


This chain applies whenever a packet will be routed from one network interface to another through this system. It is used whenever the system is acting as a packet router or gateway, and applies to packets that are neither originating from nor destined for this system.

Each rule in a chain provides a set of criteria that specify which packets match the rule, and an action that should be taken on packets that match. Actions that can be taken on a packet include accepting the packet (allowing it to be either received or transmitted), dropping the packet (simply refusing to receive or transmit it), or passing the packet on to another chain. (The latter is useful when building user-defined chains, which allow complex packet-filtering rules to be built up hierarchically.) A packet traverses each rule in the chain until it is accepted, dropped, or reaches the end of the chain; if it reaches the end, the default action of the chain determines the fate of the packet. The default action of a chain can be configured to either accept or drop all packets.

The Linux netfilter supports a number of other interesting things you can do in filtering rules. One of the key advantages of netfilter is that it is extensible. It is possible to develop extensions that enhance the way netfilter operates. Some examples of more sophisticated packet handling actions are the following:

Packet logging

You can create rules that do nothing more than log a description of the matching packet so that it can be captured for analysis later. This is very useful for detecting attacks and for testing a filtering configuration.

Stateful inspection

netfilter includes a set of helper modules that can perform stateful connection inspection, such as management of FTP connections, as described earlier.

Network Address Translation

Network Address Translation (NAT), also called IP masquerading, provides a means of rewriting the IP addresses and port numbers of packets as they pass through a chain. NAT is most commonly used to allow systems on a private network to use a connection to the Internet with a single IP address. NAT is a complex subject that we don't discuss at length, but a simple example is provided later in this chapter. You can learn more about NAT in the NAT HOWTO or in TCP/IP Network Administration, Third Edition (O'Reilly).

Packet and byte accounting

netfilter provides counters that allow you to measure how the network traffic handled each rule. Several IP accounting systems are based on these statistics. These counters are visible when you use iptables to list rulesets in verbose mode; we demonstrate this in Example 26-3, later in this chapter. Using the iptables command

The iptables command is used to make changes to the netfilter chains and rulesets. You can create new chains, delete chains, list the rules in a chain, flush chains (that is, remove all rules from a chain), and set the default action for a chain. iptables also allows you to insert, append, delete, and replace rules in a chain.

The iptables command has a large number of command-line arguments and options, but once you've used it a few times, the syntax becomes fairly obvious. In this section we only cover the most common uses of iptables, so some arguments and options are left out of the following discussion. Specifically, we don't discuss user-defined chains here. Table 26-1 summarizes the iptables arguments that operate on chains, and Table 26-2 summarizes the iptables arguments that operate on individual rules.

Table 26-1. iptables operations on chains



-L chain

List the rules in the specified chain or all chains.

-F chain

Flush (delete) the rules from the specified chain or all chains.

-Z chain

Zero the byte counters in the specified chain or all chains.

-P chain action

Set the default action (policy) of the specified chain to action.

Table 26-2. iptables operations on rules



-A chain rule-specification

Append a rule to chain.

-D chain rulenum

Delete the rule with rule number rulenum from chain.

-R chain rulenum rule-specification

Replace rule number rulenum in chain with rule-specification.

-I chain rulenum rule-specification

Insert a rule into chain at slot number rulenum with specification rule-specification. If no rulenum is specified, 1 is assumed.

Each filtering rule includes parameters that describe which packets match the rule. The most common rule parameters are summarized in Table 26-3. Using an exclamation point (!) before a parameter inverts it. For example, the parameter -dport 80 means "match destination port 80," whereas the parameter -dport ! 80 means "match any destination port except 80."

Table 26-3. iptables rule parameters



-p ! protocol

The packet protocol. Valid settings are tcp, udp, icmp, or all.

-s ! source/mask

Source address of the packet, specified as a hostname or IP address. mask specifies an optional netmask as either a literal netmask or a number of bits. For example, / gives the literal netmask, and /24 gives the number of bits in the mask.

-d ! source/mask

Destination address of the packet. Uses the same syntax as the source address.

-- sport ! port

The source port of the packe, specified as a literal port number or as a service name from /etc/services.

-- dport ! port

The destination port of the packet. Uses the same syntax as the source address.

-i ! interface

The network interface on which the packet was received.

-o ! interface

The network address on which the packet will be sent.

A number of important options are used when building rulesets , summarized in Table 26-4.

Table 26-4. Other important iptables options




Enable verbose output. Most useful when listing rules with -L.


Display IP addresses in numeric form (i.e., avoid DNS lookup).

-m module

Load the iptables extension named module.

In addition to specifying matching parameters, each netfilter rule must specify some action to take for each packet matching the rule. Generally, a rule specifies that a packet should be accepted or dropped, as described next. If no action is specified for a rule, the packet and byte counters for that rule will be incremented and the packet will be passed on to the next rule in the chain. This allows a rule to be used for accounting purposes only. To specify an action for a rule, use the following syntax:

-j target

Here, -j stands for "jump," meaning that if a packet matches this rule, processing will jump to the action named by target. target can be one of the following:


Allow this packet to be transmitted or received.


Drop the packet.


Pass the packet to a userspace program for processing.


If used with a user-defined chain, RETURN causes the packet to be returned to the "calling" chain. If used with a built-in chain, it causes the packet to jump to the end of the chain (where it is subject to the default action for that chain).

When using the -j option, target can also be the name of a user-specified chain, which allows the user to define a "subchain" of rules that will process this packet. As described earlier, the target RETURN is used to cause a packet to return from a user-defined chain back to the "calling" chain.

26.4.2. Developing IP Filtering Rulesets

Often the most difficult part of IP firewall implementation is deciding what you actually want it to do. Do you want to allow outgoing connections freely? Should you allow ICMP packets? What UDP services do you want? What kind of logging do you want to do?

One of the great challenges of building filtering rulesets is that most people aren't accustomed to thinking in terms of addresses, protocols, and port numbers. Instead, we more often think in terms of applications and end users. To build filtering rulesets, we must be able to translate our higher-level requirements into the low-level detail with which the filtering operates.

You can't get around the need to understand a bit about how the services that you are managing with IP filtering actually work. First and foremost, it is important to know whether a service uses TCP or UDP, and which port numbers it uses. The /etc/services file can often provide a good deal of what you need to know. For example, searching for smtp in this file yields tcp/25, which indicates that the SMTP protocol uses TCP port 25. Likewise, searching for the DNS returns two entries, one for udp/53 and another for tcp/53; this means that the service uses port 53, but uses both the TCP and UDP protocols.

Some protocols, such as FTP, have two related but different entries in /etc/services. As described earlier, FTP uses one port for the command session (tcp/21) and another for the data transfer sessions (tcp/20). Unfortunately, FTP clients and servers are free to use different ports for the data transfer session. Therefore, FTP has been somewhat of a nuisance for filtering rules. Fortunately, netfilter provides some assistance with a feature called connection tracking , along with a helper module that specifically understands the FTP service. Because of this, it is necessary only to create a rule for the FTP command session, and netfilter will automatically track and allow the data transfer sessions for you. We demonstrate this later in the chapter in Example 26-2.

If /etc/services doesn't provide enough information, you may need to read the relevant RFC document that specifies the protocol used by the service. Usually you don't need to know much more about a service other than what protocols and ports it uses, which is generally easy to find in the RFC.

26.4.3. IP Filter Management and Script Files

Filtering rules are stored and used by the kernel in much the same way as routing entries: when the system reboots, IP filtering rules must be reconfigured. To ensure that a firewall configuration is reinstated when a reboot occurs, you should place the appropriate iptables commands in a script file that is automatically executed at system boot time. Bundled with the iptables software package are two programs called iptables-save and iptables-restore that respectively save the current netfilter configuration to a file and restore it from that file. These tools greatly simplify the task of managing firewall configuration.

Each Linux distribution takes a slightly different approach to managing firewall configuration:

Red Hat (versions 7.0 and later)

First configure your IP filtering rules using the appropriate iptables commands. Then, execute the following command:

/sbin/service iptables save

This causes the filtering rules to be saved to /etc/sysconfig/iptables, which is automatically read at boot time.


In order to set up iptables rules you either need to write a /etc/init.d script manually or use one of the many packages available that generate firewall rules for you.

SUSE Linux

For a simple, albeit not as flexible, configuration, run yast2 and select the firewall configuration module Security & Users Firewall. Otherwise:

  • Edit /etc/sysconfig/SUSEfirewall2. This file is thoroughly documented.

  • If necessary, define custom filter rules in /etc/sysconfig/scripts/SUSEfirewall2-custom. This requires deeper knowledge about how firewalls work on Linux.

  • Start the firewall by invoking /sbin/SUSEfirewall2 start.

26.4.4. Sample netfilter Configurations

In this section we provide some simple but useful IP filtering configurations. The aim here is not to provide you with a set of solutions that you accept uncritically. Instead, we introduce you to what a useful set of IP filtering rules looks like and provide you with a skeleton on which you can base your own configurations. Simple IP filtering example

Here we demonstrate the basic use of IP filtering, which is similar to our use of TCP wrappers described earlier in the chapter. Here we want to screen out packets from all hosts on the Internet, except for packets destined for the finger daemon from a small set of hosts. Although TCP wrappers can be used to perform the same function, IP filtering can be used to screen many different types of packets (for example, ICMP "ping" packets), and is often necessary to protect services that aren't managed by TCP wrappers.

Unlike TCP wrappers, iptables rules cannot use hostnames to identify the origin or destination of a packet; you must use IP addresses when specifying rules. This is a good idea anyway, since reverse hostname lookup is not a completely secure way to identify a packet (it is possible to spoof DNS, making it appear as though an IP address has a different hostname). In Examples 26-1 and 26-2, we use IP addresses instead of hostnames, which can be obtained using a tool such as host.

Example 26-1. Simple ipchains example
# Load the connection tracking modules if they're not compiled into the
# kernel.
modprobe ip_conntrack
modprobe ip_conntrack_ftp

# Set default policy on the INPUT chain to DROP.
iptables -P INPUT DROP

# ACCEPT packets belonging to an existing connection.
# '-A INPUT' is used to append to the INPUT chain.
# '-m state' uses the stateful inspection module.
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# ACCEPT all packets that have come from the loopback interface, that
# is, from the local host. '-i lo' identifies the loopback interface.
iptables -A INPUT -i lo -j ACCEPT

# ACCEPT new incoming connections, and packets belonging to existing
# connections, to port 22 (ssh).
iptables -A INPUT -m state --state NEW -m tcp -p tcp \
         --dport 22 -j ACCEPT

# ACCEPT new incoming FTP connections from 192.168.1/24.
iptables -A INPUT -m state --state NEW -m tcp -p tcp -s 192.168.1/24 \
         --dport 21 -j ACCEPT

# ACCEPT new incoming FTP connections from,
# which has IP address
iptables -A INPUT -m state --state NEW -m tcp -p tcp -s \
         --dport 21 -j ACCEPT

# ACCEPT new incoming FTP connections from *
# They have two networks: and
iptables -A INPUT -m state --state NEW -m tcp -p tcp -s 172.18.1/24 \
         --dport 21 -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp -s 172.25.3/24 \
         --dport 21 -j ACCEPT

The ruleset specifically accepts all packets that belong to an existing connection. This is needed in the case of FTP, in which the client and server may negotiate an alternate port for the data transfer connection. The connection tracking module (specified with -m state in the rules) ensures that the data transfer connection can be accepted. IP filtering to protect an entire network

The previous example demonstrated IP filtering on a single host. In this section, we deal with the case where a network of machines (such as all the machines in a home or small office) are connected to the Internet through a gateway machine. We can write netfilter rules to filter the traffic between the Internet and the internal network. In Example 26-2, we place rules on both the INPUT and FORWARD chains. Recall that INPUT is used to filter incoming packets destined for this host, whereas FORWARD is used for packets being forwarded by the gateway (i.e., packets destined for the internal network or the Internet). Here, we assume that the gateway machine uses the ppp0 interface to communicate with the Internet.

Example 26-2. Using netfilter to protect an IP network
# Load the connection tracking modules if they're not compiled into the
# kernel.
modprobe ip_conntrack
modprobe ip_conntrack_ftp

# Set default policy on INPUT and FORWARD chains to DROP.
iptables -P INPUT DROP
iptables -P FORWARD DROP

# ACCEPT all packets from the loopback interface.
iptables -A INPUT -i lo -j ACCEPT

# Create a new user-defined chain. This chain will contain rules
# relevant to both INPUT and FORWARD, so by grouping them together on
# a single chain we avoid stating the rules twice.
iptables -N allowfwdin

# ACCEPT packets belonging to an existing connection.
# Note that this rule (and subsequent rules) are placed
# on the user-defined chain.
iptables -A allowfwdin -m state --state ESTABLISHED,RELATED -j ACCEPT

# ACCEPT new connection requests from machines on the internal network.
# This allows machines on the internal network to establish connections
# to the Internet, but not the other way around. Note the use of
# '-i ! ppp0' to specify packets coming from interfaces other than ppp0.
iptables -A allowfwdin -m state --state NEW -i ! ppp0 -j ACCEPT

# ACCEPT new incoming connections to port 22 (ssh).
iptables -A allowfwdin -m state --state NEW -m tcp -p tcp \
         --dport 22 -j ACCEPT

# ACCEPT new incoming FTP connections from 192.168.1/24.
iptables -A allowfwdin -m state --state NEW -m tcp -p tcp -s 192.168.1/24 \
         --dport 21 -j ACCEPT

# ACCEPT new incoming FTP connections from
iptables -A allowfwdin -m state --state NEW -m tcp -p tcp -s \
         --dport 21 -j ACCEPT

# ACCEPT new incoming FTP connections from *
iptables -A allowfwdin -m state --state NEW -m tcp -p tcp -s 172.18.1/24 \
         --dport 21 -j ACCEPT
iptables -A allowfwdin -m state --state NEW -m tcp -p tcp -s 172.25.3/24 \

# Any packets that have passed through the user-defined chain are now
# subject to the action LOG, which causes them to be logged.
# Use the 'limit' module to prevent logging blocked packets too
# rapidly.
iptables -A allowfwdin -m limit --limit 2/sec -j LOG

# Set default action on the user-defined chain to DROP.
iptables -A allowfwdin -j DROP

# Direct all packets received for INPUT or FORWARD to our user-defined chain.
iptables -A INPUT -j allowfwdin
iptables -A FORWARD -j allowfwdin

# Enable IP routing (required by all IP routers, regardless of the use
# of IP filtering).
echo 1 >/proc/sys/net/ipv4/ip_forward

To keep track of any attempts to breach security, we've added a rule that will log any packets that would be dropped. However, if a large number of bad packets were to arrive, this rule might fill up the disk with log entries, or slow down the gateway to a crawl (as it takes much longer to log packets than it does to forward or filter them). So, we use the limit module, which controls the rate at which a rule action is taken. In the preceding example, we allowed an average rate of two bad packets per second to be logged. All other packets will pass through the rule and simply be dropped.

To view the rules that have been configured (see Example 26-3), use the iptables list option -L. Using the verbose mode (-v) displays more information than the basic output of the command.

Example 26-3. Listing iptables rulesets for Example 26-2
# iptables -L -v
Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
   16  1328 ACCEPT     all  --  lo     any     anywhere             anywhere
    0     0 allowfwdin all  --  any    any     anywhere             anywhere

Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 allowfwdin all  --  any    any     anywhere             anywhere

Chain OUTPUT (policy ACCEPT 9756 packets, 819K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain allowfwdin (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  any    any     anywhere             anywhere  \
    0     0 ACCEPT     all  --  !ppp0  any     anywhere             anywhere  \
    state NEW
    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere  \
    state NEW tcp dpt:ssh
    0     0 ACCEPT     tcp  --  any    any       anywhere  \
    state NEW tcp dpt:ftp
    0     0 ACCEPT     tcp  --  any    any            anywhere  \
    state NEW tcp dpt:ftp
    0     0 ACCEPT     tcp  --  any    any        anywhere  \
    state NEW tcp dpt:ftp
    0     0 ACCEPT     tcp  --  any    any        anywhere  \
    state NEW tcp dpt:ftp
    0     0 LOG        all  --  any    any     anywhere             anywhere  \
    limit: avg 2/sec burst 5 LOG level warning
    0     0 DROP       all  --  any    any     anywhere             anywhere IP masquerading example

netfilter rules can also be used to implement IP masquerading, a specific type of NAT that rewrites packets from an internal network to make them appear as though they are originating from a single IP address. This is often used in cases where one has a number of machines connected to a LAN, with a single Internet-connected machine with one IP address. This is a common situation in home networks where the ISP has allocated a single IP address; using IP masquerading, however, an entire network of machines can share the address. By having the gateway perform IP masquerading, packets from the internal LAN will appear as though they are originating from the gateway machine, and packets from the Internet will be forwarded to the appropriate host on the internal LAN. You can accomplish all of this with a bit of clever packet rewriting using netfilter.

Configuring netfilter to support IP masquerading is much simpler than explaining how it works! More complete information about how IP masquerading and NAT are accomplished is provided in the NAT HOWTO. We'll show the most basic configuration in Example 26-4.

Example 26-4. Basic IP masquerade configuration
# Load the module supporting NAT, if not compiled into the kernel.
modprobe iptables_nat

# Masquerade any routed connections supported by the ppp0 device.
iptables -t nat -A POSTROUTING -p ppp0 -j MASQUERADE

# Enable IP routing.
echo 1 >/proc/sys/net/ipv4/ip_forward

In this configuration we assumed that we have a Linux system that will act as a gateway for an internal network. The gateway has a PPP connection to the Internet on interface ppp0, and a LAN connection to the internal network on interface eth0. This configuration allows outgoing connections from the internal network to the Internet, but will block incoming connections from the Internet to machines on the internal network except for the gateway. As it turns out, we don't need to provide explicit commands to achieve this, as it is the default behavior when using NAT in this fashion.

There are some important details to note in this configuration. The NAT functionality is provided in a module of its own, which must be loaded unless it is built into your kernel. The NAT module uses a new chain called POSTROUTING that processes packets after the kernel performs routing operations on them (that is, decides whether the packets are destined for the Internet or for internal LAN machines). The MASQUERADE target does the hard work of address translation and tracking.

Note that this configuration provides no filtering of outgoing connections. All hosts on the private network will be able to establish outgoing connections to any host and any port. The packet filtering HOWTO provides useful information about how to combine IP filtering with address translation.

Part I: Enjoying and Being Productive on Linux
Part II: System Administration