Advanced Firewall Configurations with ipset

iptables is the user-space tool for configuring firewall rules in the
Linux kernel. It is actually a part of the larger netfilter framework.
Perhaps because iptables is the most visible part of the netfilter framework,
the framework is commonly referred to collectively as iptables.
iptables has been the Linux firewall solution since the 2.4 kernel.

ipset is an extension to iptables that allows you to create firewall
rules that match entire "sets" of addresses at once. Unlike normal
iptables chains, which are stored and traversed linearly, IP sets are
stored in indexed data structures, making lookups very efficient, even
when dealing with large sets.

Besides the obvious situations where you might imagine this would be
useful, such as blocking long lists of "bad" hosts without worry of
killing system resources or causing network congestion, IP sets also
open up new ways of approaching certain aspects of firewall
design and simplify many configuration scenarios.

In this article, after quickly discussing ipset's installation
requirements, I spend a bit of time on iptables' core fundamentals and
concepts. Then, I cover ipset usage and
syntax and show how it integrates with iptables to accomplish various
configurations. Finally, I provide some detailed and fairly advanced
real-world examples of how ipsets can be used to solve all sorts of
problems.

With significant performance gains and powerful extra features—like
the ability to apply single firewall rules to entire groups of hosts
and networks at once—ipset may be iptables' perfect match.

Because ipset is just an extension to iptables, this article is as much
about iptables as it is about ipset, although the focus is those features
relevant to understanding and using ipset.

Getting ipset

ipset is a simple package option in many distributions, and since
plenty of other installation resources are available, I don't
spend a whole lot of time on that here.

The important thing to understand is that like iptables, ipset consists
of both a user-space tool and a kernel module, so you need both for
it to work properly. You also need an "ipset-aware" iptables binary
to be able to add rules that match against sets.

Start by simply doing a search for "ipset" in your
distribution's package management tool.
There is a good chance you'll be able to find an easy
procedure to install ipset in a turn-key way. In Ubuntu (and
probably Debian), install the ipset and xtables-addons-source
packages. Then, run module-assistant auto-install
xtables-addons, and
ipset is ready to go in less than 30 seconds.

If your distro doesn't have built-in support, follow the manual
installation procedure listed on the ipset home page (see Resources)
to build from source and patch your kernel and iptables.

The versions used in this article are ipset v4.3 and iptables v1.4.9.

iptables Overview

In a nutshell, an iptables firewall configuration consists of a set
of built-in "chains" (grouped into four "tables") that each comprise a
list of "rules". For every packet, and at each stage of processing, the
kernel consults the appropriate chain to determine the fate of the packet.

Chains are consulted in order, based on the "direction" of the packet
(remote-to-local, remote-to-remote or local-to-remote) and its current
"stage" of processing (before or after
"routing"). See Figure 1.

Figure 1. iptables Built-in Chains Traversal Order

When consulting a chain, the packet is compared to each and every one
of the chain's rules, in order, until it matches a rule. Once the first match
is found, the action specified in the rule's target is taken. If the
end of the chain is reached without finding a match, the action of the
chain's default target, or policy, is taken.

A chain is nothing more than an ordered list of rules, and a rule is
nothing more than a match/target combination. A simple example of a
match is "TCP destination port 80". A simple example of a target is
"accept the packet". Targets also can redirect to other
user-defined chains,
which provide a mechanism for the grouping and subdividing of rules, and
cascading through multiple matches and chains to arrive finally at an
action to be taken on the packet.

Every iptables command for defining rules, from the very short to the very long,
is composed of three basic parts that specify the table/chain (and
order), the match and the target (Figure 2).

Figure 2. Anatomy of an iptables Command

To configure all these options and create a complete firewall
configuration, you run a series of iptables commands in a specific order.

iptables is incredibly powerful and extensible. Besides its many built-in
features, iptables also provides an API for custom "match
extensions"
(modules for classifying packets) and "target extensions" (modules for
what actions to take when packets match).

Enter ipset

ipset is a "match extension" for iptables. To use it, you create and
populate uniquely named "sets" using the ipset command-line tool,
and then separately reference those sets in the match specification of
one or more iptables rules.

A set is simply a list of addresses stored efficiently for fast lookup.

Take the following normal iptables commands that would block inbound
traffic from 1.1.1.1 and 2.2.2.2:

The match specification syntax -s 1.1.1.1 above
means "match packets
whose source address is 1.1.1.1". To block both 1.1.1.1 and 2.2.2.2,
two separate iptables rules with two separate match specifications
(one for 1.1.1.1 and one for 2.2.2.2) are defined above.

Alternatively, the following ipset/iptables commands achieve the same
result:

The ipset commands above create a new set (myset of
type iphash)
with two addresses (1.1.1.1 and 2.2.2.2).

The iptables command then references the set with the match specification
-m set --set myset src, which means "match packets whose source header
matches (that is, is contained within) the set named myset".

The flag src means match on "source".
The flag dst would match on
"destination", and the flag src,dst would match on both source and
destination.

In the second version above, only one iptables command is required,
regardless of how many additional IP addresses are contained within the
set. Although this example uses only two addresses, you could just as easily
define 1,000 addresses, and the ipset-based config still would require
only a single iptables rule, while the previous approach, without the benefit
of ipset, would require 1,000 iptables rules.

The flag src means match on "source". The flag dst would match on "destination", and the flag src,dst would match on both source and destination.

When multiple flags are specified, the effect depends on the type of the set. If the type is for example ipportmap, the source IP and destination port should match the pair in the set. If the set is something like an iphash, only the source should match (unless there is a binding).