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.
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,
ipfwadm, ipchains, and
iptables, provide support for this style of
testing. The implementation involves use of the relevant
check command.
The general test procedure is as follows:
Design and configure your firewall using ipfwadm,
ipchains, or iptables.
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.
Develop ipfwadm, ipchains, or
iptables 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
ipfwadm, you must use the –c
option to specify that this command is a test, while for
ipchains and iptables, you must
use the –C option. In all cases you must
always 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.
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 ipchains and
iptables, user-specified chains will be tested
in addition to the built-in ones.
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.
Let's take a quick look at what a manual test transcript would look
like for our na�ve example with ipchains. 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:
# ipchains -C forward -p tcp -s 172.16.1.0 1025 -d 44.136.8.2 80 -i eth0
accepted |
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 that the
datagram was accepted for forwarding, which is what we hoped for.
Now try another test, this time with a source address that doesn't
belong to our network. This one should be denied:
# ipchains -C forward -p tcp -s 172.16.2.0 1025 -d 44.136.8.2 80 -i eth0
denied |
Try some more tests, this time with the same details as the first test,
but with different protocols. These should be denied, too:
# ipchains -C forward -p udp -s 172.16.1.0 1025 -d 44.136.8.2 80 -i eth0
denied
# ipchains -C forward -p icmp -s 172.16.1.0 1025 -d 44.136.8.2 80 -i eth0
denied |
Try another destination port, again expecting it to be denied:
# ipchains -C forward -p tcp -s 172.16.1.0 1025 -d 44.136.8.2 23 -i eth0
denied |
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.