Getting access to the Internet is easy. A great many
Internet service
providers (ISPs) are available, almost always just a
local call away.
Getting safe access to the Internet is completely different.
You want
internal users to have convenient access to information
on the Internet,
but you don't (usually) want outsiders to have any,
let alone easy,
access to your internal information. The best way to
achieve this
selective connectivity is to separate your internal
network from the
Internet with a firewall.
This article shows you how to install and configure
a Linux-based
firewall that connects to the Internet via a demand-dial
PPP link.
My firewall implementation uses a standard SMCEthernet
card for the
firewall host. The connection to the Internet goes through
a high-speed
modem on a dial-up PPP link to our service provider.
(See Figure 1.)
Revise the startup configuration
I recommend using a CD-ROM-based distribution for your
initial
installation. (See the sidebar "Obtaining Linux.")
These distributions
usually include install scripts and instructions that
greatly simplify
the installation process. Also, they include all of
the drivers and most
of the other components you will need, and having all
the necessary
components in one place is a significant time saver.
Typically, these distributions come with prebuilt kernels
for common
configurations. You boot with one of these kernels and
then use that as
a development environment to build a kernel specific
to your machine's
configuration.
Once you have a working, properly configured base kernel
running, you
should configure PPP, or whatever network interface
you will be running,
and download the source tree for a kernel with appropriate
firewall
support. At this point, you should also download any
other packages you
may need to upgrade. Specifically, you will need current
versions of
ipfw, PPP, SLIP, and IP masquerading.
Once you have the source for all the firewall components,
you need to
build yet another kernel, this time configuring it to
enable IP
forwarding and other firewall-related features.
With the firewall-configured kernel running, the last
steps are to
configure the firewall packet filtering rules, configure
an appropriate
nameserver, and revise the startup sequence so that
only a minimum of
daemons are running.
Upgrading the Kernel Source
For this firewall, I chose the most recent kernel available
version
1.3.68, as of this writing. By the time you read this,
there will no
doubt be an even newer version of Linux available, maybe
even Linux 2.0.
I assume any newer versions will have the same, or at
least a very
comparable, version of the firewall code in the kernel.
I have a few reasons for choosing this kernel version.
First, the
firewall code of the kernel has improved. Version 1.3.68
allows you to
specify rules for three types of traffic: incoming,
outgoing, and
forwarding. This in turn, enables you to precisely specify
which traffic
is trusted and which traffic is considered dangerous.
Furthermore, the
IP masquerading has improved as well.
To use the new firewall rulesets, you need a special
version of the
firewall administration program, ipfwadm. This version
"knows" about
these new rules. You cannot use older versions (up to
kernel version
1.3.65), because they are not compatible and will definitely
cause
trouble. You can download this new ipfwadm program from
:
ftp://ftp.xos.nl/pub/linux
And you need at least the 2.0 beta version. When you
start to build this
new kernel, you first need to do:
make config
to enable and disable kernel features.
During this configuration, you will enable the different
hardware
devices of your hardware platform. In my firewall setup,
I have a
SMC8013 Ethernet card for connection to the local network,
and use a PPP
dial-up link to the Internet. (The complete layout of
this test network
is shown in Figure 2.) I chose to enable the PPP support
as dynamically
loadable modules. Unlike statically linked drivers,
modules can be
loaded and unloaded at runtime. With PPP configured
as a loadable
module, I can really take the firewall off-line by just
unloading the
PPP module.
I also enable support for SLIP as a loadable module.
Even though I use
PPP and not SLIP as my dial-up Internet protocol, I
need to enable SLIP
to make the dial-on-demand daemon, diald (version 0.12),
available. This
daemon will automatically call the Internet service
provider if it
detects traffic destined for the Internet.
Listing 1 shows all the make config options related
to the firewall and
masquerading code. You should use these same responses
when building
your firewall kernel.
After configuring the kernel you need to do:
make dep; make clean; make zImage
to build it. After building, you can boot this kernel
as the software
foundation for your firewall.
You can compile both ipfwadm and diald out of the box.
After you build
and install them, they will be available for use.
Configuring the Firewall Rules
Again, the kernel's firewall supports three distinct
groups of packet
filtering rules: input, output, and forward. Each of
these groups has
its own set of firewall rules and, thus, needs to be
configured
appropriately.
The rules for the input group describe which traffic
is allowed into the
firewall. These rules apply to all network interfaces
on the firewall,
not just the Internet interface. Each rule gives a combination
of source
address, destination address, and interface address.
When an IP packet
matches a rule, it is processed according to the action
in the rule.
The rules for the output group specify which packets
may leave the
firewall. These rules resemble the input rules; it is
just the direction
of the traffic that differs.
The rules for the forward group specify which packets
may flow from one
interface to another. These rules really make the firewall
a firewall,
either allowing or blocking traffic. Also in the forwarding
group you
can specify whether or not a packet should be masqueraded.
The
forwarding rules are the only place where masquerading
can be
configured. The other two groups only concern the traffic
on the
physical interface.
These rules are constructed using various options of
the ipfwadm command
(See Listing 2). It is very important to become familiar
with these
options. Incorrect rules may create subtle and not so
subtle backdoors
through your firewall.
Here are the most important options. The first option
states the group
for which the rule is intended. The -I is for the input
group, the -O
for the output group, and the -F for the forwarding
group. You can then
specify whether a rule should be added (-a), deleted
(-d), or inserted
(-i). The parameter of this option is the policy for
the rule. This
policy can be accept (accept the packet), reject (reject
the packet), or
deny (ignore the packet).
Neither reject nor deny allows matching packets in,
but there is a
subtle, yet important difference. A packet that is rejected
will result
in an ICMP message transmission to the sender of the
original packet.
The user originating the rejected message will get some
sort of error
message stating "connection refused." This
error message does give
potential intruders some information. It tells them
that some host (the
one sending the ICMP messages) "owns" the
refused address. So, the
intruder now knows that perhaps some other attempt will
succeed at that
host.
A denied packet is silently ignored; thus the intruder
cannot tell
whether there is no host responding or the packets are
just tossed away.
So, my advice is to always use a deny policy instead
of a reject policy
for your Internet connection. Connections on the local
net may be
rejected, so the local user will know they've been refused.
Using the -D and -S options of the ipfwadm command,
you can specify the
source and destination address. You can even mask bits
from the address
to specify a group of hosts belonging to the same subnet.
This will save
you a lot of typing and speed up the matching process
in the firewall.
Note that 0.0.0.0 matches all IP addresses (i.e., the
world). The next
two important options are -k and -y. These two specify
whether the ACK
and SYNC flags in the TCP header should be set. You
can use these
options to block anyone from initiating a connection
to your firewall.
Although blocking SYNC packets originating in the Internet
is generally
a good idea, it does cause problems with SMTP and FTP
protocols, as
detailed later.
The last important option is the -p option. It specifies
the default
policy. The default policy is activated when no rule
matches. This rule
is a safety net of sorts; it closes all the unspecified
possibilities in
your packet filtering. For my firewall, I have set the
default policy
for all groups to deny, so all unknown packets are silently
ignored. A
few examples of these rules are shown in Listing 3.
Special Input Rules
A normal firewall will not allow a client on the Internet
to initiate a
connection. So, all input rules related to the Internet
interface have
the -k option set (ACK flag must be set in TCP header).
This causes two
problems, however. First, if your firewall will be running
an SMTP
daemon refusing all SYNC packets will cause the SMTP
daemon to hang. If
a client on the Internet wants to send you mail via
SMTP, it opens port
25 on your firewall. You can bypass this problem by
specifying a special
input rule for the SMTP port. The SMTP rule should specify
that anybody
on the Internet may open a connection to port 25, and
only port 25. This
rule may look like this:
# Add input rule for Internet -> me for mail (stops at firewall)
ipfwadm -I -a accept -P tcp -S 0.0.0.0/0 -D 194.109.13.150 25
This connection will stop at the firewall, so it does
not need an
accompanying output or forwarding rule.
The second problem with refusing SYNC packets is created
by ftp (the
file transfer protocol). When transfering files, ftp
opens two
connections. The first connection is a control channel,
which ftp uses
to send commands such as change directory, obtain file
listings, etc.
This control connection is initiated by the machine
on the local net and
thus follows the normal flow (output directed traffic).
However, when the ftp client retrieves a directory or
file, ftp uses its
second connection, the data connection for the transfer.
The client
sends the server a port command that tells the server
which port on the
client should be opened for transferring the data. Thus,
the data
connection is initiated in reverse (from outside into
the local net).
With all SYNC packets denied, the firewall would deny
such a connection,
blocking the data transfer.
The general solution is to define a special set of rules
for this ftp
data connection. Because the server also uses port 20
as its end for the
data connection, you can enable data transfer by including
a rule that
accepts connections initiated on that port number. The
newer Linux
kernels now fully support these port-specific rules.
The pertinent rules
involved for this are shown in Listing 4.
Even without this rule, some ftp clients may be able
to successfully
transfer data from your host. Some ftp clients know
a "passive" mode. In
this mode, the client asks the ftp server to create
a port for
transferring data. The resulting transfer is accomplished
with ACK
packets, avoiding the SYNC restrictions.
The Nameserver
All of these IP mechanisms need access to a name server
to resolve names
for various destination machines. Running the nameserver
on the firewall
is not a good idea. First, it's always good practice
to limit the number
of daemons on the firewall; fewer daemons translate
into fewer
opportunities for a would-be intruder. Second, the nameserver
mapping
tables contain information on the structure of your
local network. So,
you need a nameserver, but it needs to run on some machine
other than
the firewall. Where?
The simple answer is to host the nameserver on one of
the machines in
your local network. This local nameserver should be
configured to
resolve all name references involving local machines
and to forward
requests it cannot resolve to some nameserver on the
Internet. The
firewall will require special rules to properly handle
these requests
directed to the external name server. These special
rules are shown in
Listing 5.
All nameserver traffic is based on the UDP protocol.
The firewall itself
may need to contact the nameserver, this is described
in the rules
nameserver > me and me > nameserver. The other
rules are used for name
queries from the nameserver to a machine on the Internet
and back.
Wherever possible, the traffic is limited to port 53,
the nameserver
port.
Revising the Startup Process
Once you have the kernel and the associated utilities
installed, you can
start modifying the kernel startup files. If you used
Slackware 3.0 to
build your Linux system, you need to change a number
of configuration
files. Most of these files are located in the /etc/rc.d
directory. The
files in this directory are executed when the system
changes its running
state (e.g., from single user to multiuser or back).
First, make certain that only the necessary daemons
are started. The
default configuration will also start lpd and others,
but you do not
need those on a firewall. You also do not need inetd,
as you do not want
to offer services like telnet and ftp on the firewall
itself.
Last but not least, add startup commands to set the
firewall rules
automatically when booting. This ensures that your system
won't come up
in a "totally open" mode after a power outage.
I place these rule commands in a special rc file (rc.internet)
in the
/etc/rc.d directory. Make certain that the rc.local
script invokes the
rc.internet script. With this arrangement, the firewall
rules and
Internet-related modules are guaranteed to be loaded
on every boot
cycle. As its final act, this script should start the
diald daemon. The
complete source for the rc.internet script and its associated
files is
shown in Listing 6, Listing 7,
Listing 8, and Listing 9.
The two most important files in the /etc/rc.d directory
are rc.inet1 and
rc.inet2. They take care of starting all the network-related
daemons. To
ensure that you aren't starting any unnecessary daemons,
you should
probably remove the call to these two files from the
rc.internet script
and explicitly add invocations for any daemons you really
need. Listing 10
shows my rc.internet script. Once you have managed
to tune these
scripts you will get a very lean firewall machine with
a minimum of
processes running. Listing 11 shows a typical process
listing from an
active firewall.
Conclusions
With the system in this article, you can build an Internet
firewall
without a large number of complicated applications.
You can use a simple
configuration on your local network, without the need
for proxy daemons.
The firewall itself is also a straightforward machine,
with a minimum of
processes running.
The Linux kernel used in this firewall, 1.3.68, is relatively
new. It
will have to prove itself in the long run, but it looks
promising.
The hardest part of building a good firewall lies in
building good
packet rules. Careful analysis is important to building
good rules, but
the ultimate proof is thorough testing. Test these rules,
test them
again, and then test them some more.
One good test strategy is to probe your firewall using
Satan running on
some Internet host. I cannot stress this enough, the
heart of your
security lies in the rules you specify for your firewall.
The rules
given here work for me, but that doesn't mean they'll
give you a secure
installation. I would never presume that they are completely
watertight.
If you use these rules verbatim, be warned: you do so
at your own risk.
This caution isn't meant to be intimidating; I simply
want to make it
clear to you that constructing comprehensive and effective
rules is not
a trivial task.
About the Author
Arthur Donkers graduated from the Delft Universiy of
Technology with a
degree in Electrical Engineering and a major in Computer
Architecture.
Since then he has worked for a number of major software
houses in the
Netherlands and participated in several major projects.
His primary
field of interest in these projects has been, and still
is,
datacommunications, especially the integration of multivendor
networksystems. For the last four years he has worked
as an independant
consultant for his own company, Le Reseau (french for
"The Network").