September 10, 2004
November 12, 2004 (revisions)
May 8, 2005 (more revisions)
Two-Faced: Setting up a Simple Linux Firewall
(Debian GNU/Linux, Shorewall, and you)
This is an overview of the things I think
you need to know if you're going to try and set up a
simple firewall using linux on an old PC (really it's
an excuse for me to whine about the hassles I went
through doing this, but I've got to get something out
First of all, ask yourself why you're doing this.
You can buy a simple off-the-shelf firewall/router
gadget pretty cheap these days, and I hear at least
some of them have fairly easy-to-use administration
features (e.g. via a web browser).
Saving money by using that old PC you've got
kicking around is unlikely. Acceptable answers
include "learning experience" and "insanity".
|ABCs of Hardware:
For a PC to be used as a firewall, it needs two
ethernet cards (aka NICs or "Network Interface Cards").
If you need to buy a second card to do this with,
see the above point. Ditto if you need to buy a 10baseT hub.
When you plug ethernet gadgets together you should see
pretty green lights come on. This is a hardware level
check, and should be looked at before you touch the software.
| Some caveats:
Don't assume that a firewall is the ultimate in
security. It is true that if the security of some of the boxes on your
internal network is poor, then the firewall might help cover
for this, but it's not a substitute for trying
to improve your internal security. Also, the kind of "two-interface firewall"
I'm discussing here (see Diagram, below)
a too simple: arguably the webserver should
be in a "DMZ", hung off the firewall on a third
(see the quickstart for Three-Interface Firewall
and possibly the Shorewall FAQ).
The approach I settled on here is somewhat,
shall we say, "controversial". I've since been told that
netfilter and Shorewall both do in fact work with the
Debian stable branch (aka "woody"). It was
a mystery to me for some
time as to why I couldn't get them to work. My
central problem was that I thought that Debian releases
had specific associated kernel versions. I thought that
Woody came with the 2.2 kernel and if you needed the 2.4
kernel for something, you had to switch to Sarge.
As it turns out, Woody just defaults to a 2.2. kernel,
but also comes with an option to use a 2.4 kernel. You just
need to know the magic incantation "bf24" to use in response
to the "boot:" prompt.
Also, one of my premises behind
switching to the Debian testing branch (aka sarge)
was that sarge was just about ready to become the
new stable -- then I heard about the delays
and only now (six months later) are we hearing about
an imminent release. So as it happens,
was a bigger gamble than I thought;
abandoning Debian stable for a
security related use is not to be done lightly
(the security team releases updates only
for the stable branch).
| Think "iptables", aka "netfilter":
The kernel developers can't make their minds up about how to
do ip routing with linux, so the documentation is always out
of date. Over the years, the Right Way to do
it has progressed through:
If you're reading something that talks about the first two
items on that list, you should stop. The iptables/netfilter mechanism
has been stable for a while now, and it seems to work,
so maybe they won't throw it away in six months (*knock* *knock*).
- iptables (i.e. netfilter).
(Some pointers to things that are worth reading are collected
below in references).
I strongly suggest using the Debian GNU/Linux distribution (see
the Why Debian? section below).
If you don't know what the following things mean, you
read up on them
before messing with Debian:
- apt-get install <package name>
- dpkg -l 'foo*'
- apt-cache search '<some key phrase>'
- apt-get clean
By the way. The Debian trick called "Pinning" is
pretty dubious, though I'm using it anyway. See:
Apt-Pinning for Beginners.
Me, I've got a two-level set up pinning
sarge and sid together, where sarge takes precedence.
The problem with this, of course, is that
you can get incompatible versions of things installed
on the same box.
However, my expectation is that nearly any package I apt-get will
come out of sarge, but that on occasion there may be some
small utility (perl modules? emacs lisp code?) that will
only be in sid. If these don't work, it's not going to be
a big deal.
Of course, doing pinning on a firewall is probably
at least mildly dumb, so I may strip this "feature" out later:
the key reason I included it is that the shorewall "quickstart"
docs presumed the presence of the "iproute" package, and that
was sid-only back in September of 2004.
|Automating iptables set-up: Shorewall:
Don't try and set up iptables manually. I realize that it
sounds pretty simple to do it when you read about how they
work, but I guarantee it'll be a worse problem than you think.
Use some software to set up netfilter for you.
I started learning to use gshield once, and I liked it quite a bit.
But I couldn't find a Debian package for it, though web
searches revealed announcements that it had been accepted by
Debian a few years ago. I went around on this
for a while, before concluding that it had been dumped from
Debian without much fanfare. I guess the maintainer has abandoned
it, and no one has picked it up, which means people are
voting with their feet for using something else...
I'd say the winner is Shorewall.
Shorewall requires a 2.4 kernel compiled with the "netfilter"
options, which rules out Debian stable, aka woody -- (or so
I thought... see the above "Caveats").
Shorewall comes with a daunting quantity of documentation.
The one you want to read for the purpose at hand is the quickstart guide:
Basic Two-Interface Firewall
(or as I like to think of it, "2face").
The extensive comments in the config files may be all you need
for further reference. Of course, there's also a daunting quantity of config files, but
you don't need to bother with many of them. Most likely
you'll just work with these (found in /etc/shorewall):
By the way, for those of you who swing that way, there is a GUI
interface available to work with Shorewall: it's supported
by Webmin. I don't
know what the big deal is about this myself... Would you
want someone setting up your firewall who needed a GUI to do
it? Anyway, I'm inclined to agree with
on the subject.
|The Debian upgrade process:
Surprisingly enough, despite it's reputation for easy
upgradability, I ran into some rough spots in the Debian
upgrade process. I started off my installation with some
Debian 3.0 CDs, which means I ended up with woody, and
needed to switch to sarge (or so I thought... etc.). My
understanding was that the way to go on this was just these
But I had continual troubles with the puny disk
resources on the old Compaq 2000 I was trying to do this
on. Throughout this entire project I kept having to do various
things to clean up space (okay, first I'll blow away /usr/share/doc,
that'll give me some wiggle room to run dselect and get rid of anything
related to X, gnome, KDE... and I was excited to discover apt-get clean).
- edit /etc/sources.list
- apt-get update
- apt-get dist-upgrade
- ... and then reboot.
Many mysterious (to me) things kept happening:
dist-upgrade or dselect would give me more stuff
than I expected, I'd run out of disk again (once right
at the end of an hours long kernel build!), and I'd have
to run around again cleaning up.
Originally, I had some naive hopes that "dist-upgrade"
would do everything for me, showing the superiority of
the Debian Way to the classic Redhat kernel RPM gotcha.
But once again, I found myself stuck rebuilding a
kernel from source, though a little reflection shows
why this is probably necessary: there are hundreds of
kernel build option settings, so getting a single generic
kernel that would keep most people happy is probably a near impossibility,
kernel modules or no.
Oh, by the way: don't forget to reboot after you do a "dist-upgrade",
or you may find yourself wondering what happened to your network connection
(yeah, yeah, I know this is linux, maybe you don't really need to
reboot -- you could carefully restart all processes that need to be
restarted and skip the ones that don't -- but come on, life is too short.)
Actually, in view of the need to build your own kernel next,
I was impressed that you can just reboot. A complete dist-upgrade
does not hork the system, even if you're running with a stale kernel.
|Kernel builds under debian:
Then the build process:
- Start with this to find out what source packages are available:
apt-cache search kernel-source
- Pick one out of the list, and get it in the usual way:
apt-get install kernel-source-2.4.27
- But you also need to do this:
apt-get install libc6-dev
- And while you're at it, you should probably do something
like this (to make sure your tools are up to date):
apt-get install binutils e2fsprogs gcc make
apt-get install modul-init-tools procps util-linux
apt-get install kernel-package expectk
- (I like this better than checking the versions yourself,
as recommended in some places. Doing another "install"
does nothing if you've already got the latest, so why not?)
- First we unpack
- cd /usr/src
- tar xvfj kernel-source-*
- Update the symlink
- rm linux
- ln -s /usr/src/kernel-source-2.4.27 /usr/src/linux
- Edit the file
- Updating the EXTRAVERSION line with the
current date in the form -YYYMMDD, in my case:
- EXTRAVERSION = -20040906
- And then it's the old familiar:
- make config
- (Though, maybe I should've tried "menuconfig". Note: "xconfig" wasn't an option: no X.)
Anyway, don't forget to say "yes" to CONFIG_NETFILTER. A
(possibly) relevant excerpt from my .config is included below
After that the Debian Way begins to help out again:
make-kpkg buildpackage -rev Custom.1 kernel-image
dpkg -i kernel_image-2.4.27_Custom.1-i386.deb
- And then it's time to reboot.
|No libc6 dependencie for kernel source:
What was really shocking here was that the Debian package
system doesn't cover a really important dependency: just installing a
kernel-source package doesn't give you the libc6
package that you need to build it, so the build fails with some
misleading error messages (it says it can't find various *.h
files, but if you dig around it looks like it's all
there). This is evidentially a
too bad it hasn't been fixed yet.
Anyway, you need something like that explicit
apt-get install libc6-dev instruction up there to get it to work.
Another problem: the handling of configuration files.
I don't remember the order of events
at this point, but somehow I started hacking on
Shorewall version 1.2, but ended up getting a version
upgrade to 2.0. That's great, except that there were
some big changes in the format of the configuration files,
and the Debian installation process
is (quite properly) paranoid about over-writing the
configuration files that you've already edited.
I wasted some time there trying to get Shorewall to work with
the wrong vintage files.
Presumably Debian warned me about this during the upgrade,
but I don't remember anything like that. And oddly enough,
shorewall itself doesn't have a mechanism
to check for this version difference and warn you about it.
| Joys of Linux Network Admin:
A Linux system admin gripe:
- route -n displays your routing table.
- If you want to change it, you use commands like this:
route add -net 184.108.40.206 netmask 255.255.255.0 dev eth0
But when you reboot, you'll lose any changes you make this way.
To make permanent changes you need to work on
some config files in /etc.
So you need to understand three different
representations of the same information.
And just to make it fun, exactly which config files and
what changes you need to make vary among the different
(In an ideal world, I'd like to see something like
an "edit-route" tool that would let you make changes directly to
something that looks like the output of the route -n command.
Doing a "save" should make the necessary changes to your /etc files.)
But thankfully, with Debian, the changes you need to make to your
/etc files are pretty minimal. Mostly you need to work on this
Joys of Linux Admin, part II:
ethernet card driver name change:
To get this machine in shape as a firewall, I needed to
slap another ethernet card into it. It wasn't
particularly difficult to get it working really, I just
needed to add an alias line for it to
/etc/modutils/aliases and append a few lines
for it with the relevant ip address to
/etc/network/interfaces (See the section below for the details).
There was one really bad piece of trouble which hopefully you
will never run into: they had changed the name of the
driver I needed to use. Originally working with
woody, I did some research, and figured out that I
probably needed to use the rtl8139 driver.
Except that that didn't work, and I started wondering
what the rtl8139-scyld driver might do, so I
tried that on speculation and it did work. (I
infer that the "-scyld" suffix implies that it's the
latest driver straight from Donald Becker's machine).
So then I did my upgrade from woody to sarge, and had a
hard time finding the right driver... some web searches
turned up the interesting piece of information that it
had been re-named as 8139too.
I'm sure there are some fascinating sociological reasons
for this sort of name dance, but I really wish the programmers
would not inflict this kind of stuff on the outside world.
Anyway, if you need to debug problems like this some day,
it's not too difficult to just keep trying different
drivers. Stick a name in your alias eth1 <name>
line, do a modprobe eth1 and see if it complains.
(Imagine what this job would've been like in the days before
kernel modules. Ugh.)
|Forget not thy ip_forwarding:
The last problem I had before getting everything working
was solved when I was just poking around and noticed in
/etc/network/options I had a suspicious looking line: ip_forward=no.
I changed that to a "yes", restarted everything, and that was
pretty much it. I was somewhat shocked that shorewall
didn't make this change for me, and as it happens it's
quite willing to do so, except that in shorewall.conf,
I still had: IP_FORWARDING=Keep, which evidentially
does just what the comments say it does:
# If you set this variable to "Keep" or "keep", Shorewall will neither
# enable nor disable packet forwarding.
And I see that the
doc tells you about this, I just missed it somehow.
So: don't get distracted by any other documentation
(including this web page), read that quickstart.
|Don't forget what you don't need:
What's the first thing they tell you about how to secure a linux box?
That's right, "Shut off unneeded services." Then your next question is
"How do I know what services I need?" and then they lose interest
in talking to you.
I took a look inside the /etc/inetd.conf on my
brand new Debian Firewall, and the one thing that leaped
out at me as being (currently) useless was the
smtp / exim line. I don't have a
reason to run a mail server on my firewall (and if I
did, I'd go with postfix, though exim probably isn't a
bad choice either). So should I stick a "#" in
front of that line?
But actually, doing a ps ax doesn't turn up anything
like "exim"... and in fact it doesn't turn up anything that looks
to my eye like I want to get rid of it.
Conclusion: the Debian defaults are not bad, security
wise, and my understanding of the Linux boot process
needs some fine-tuning.
(Reading this might be a good start.)
Appendix: a "2face" example
This is the kind of set-up I'm talking about:
| ADSL, Cable, etc.
| For me this is the
| static ip: 220.127.116.11
_____|_____ (which has the domain name
| | obsidianrook.com)
| Bridge |
| eth0 is assigned the IP address
_______|__________ provided by your provider,
| | in my case it's static: 18.104.22.168
| eth0 | (there're ways to do this with DHCP also).
| Firewall PC |
| eth1 | eth1 is assigned an internal
|________________| IP address, selected from one of
| the ranges used for that purpose.
_____|_________ I use: 192.168.1.1
| 10baseT hub |
| | |
| | |
| | |________________________
| | |
___| |________ |
| | |
| | |
________|_______ ______|___________ ___|____________
| | | | | |
| PC | | PC | | PC |
| (Work | | (living room | | (Web- |
| station) | | web-terminal) | | server) |
| | | | | |
| 192.168.1.6 | | 192.168.1.4 | | 192.168.1.3 |
|______________| |________________| |______________|
An example solution: summary of the active lines from my config files
Presented for your edification, these are the
significant (i.e. non-comment) lines from every file in
my /etc tree that I modified to get my firewall
working. Note that my external IP address is
22.214.171.124, and that much at least would be
different for you in your version of the following.
Essentially, I just ran the following command to get
this listing. This works because I'm an emacs user,
thus any file I change has a backup file with a tilde
appended to the name. (Note: this is a "one-liner",
with line breaks added for clarity):
find /etc -type f -name '*~' |
perl -ne '
print grep !/^\s*$/, grep /^[^#]/, <IN>
Here's the output, with some uninteresting chunks elided ([...]):
alias eth1 8139too
iface lo inet loopback
iface eth0 inet static
iface eth1 inet static
deb ftp://linux.csua.berkeley.edu/debian sarge main
deb ftp://ftp.us.debian.org/debian sarge main contrib non-free
deb ftp://linux.csua.berkeley.edu/debian sid main
deb ftp://ftp.us.debian.org/debian sid main contrib non-free
deb-src http://security.debian.org sarge/updates main contrib non-free
DNS_1_IP=126.96.36.199 # really, 192.2?
INTERNAL_INTERIM_WEB_SERVER=192.168.1.1 # until 3, aka latveria is ready
# Networking options
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER_DEBUG is not set
# CONFIG_IP_ROUTE_FWMARK is not set
# CONFIG_IP_ROUTE_MULTIPATH is not set
# CONFIG_IP_ROUTE_TOS is not set
# CONFIG_IP_ROUTE_VERBOSE is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_PIMSM_V1 is not set
# CONFIG_IP_PIMSM_V2 is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# IP: Netfilter Configuration
# CONFIG_IP_NF_AMANDA is not set
# CONFIG_IP_NF_TFTP is not set
# CONFIG_IP_NF_MATCH_ECN is not set
# CONFIG_IP_NF_MATCH_DSCP is not set
# CONFIG_IP_NF_MATCH_AH_ESP is not set
# CONFIG_IP_NF_MATCH_TTL is not set
# CONFIG_IP_NF_MATCH_TCPMSS is not set
# CONFIG_IP_NF_TARGET_ECN is not set
# CONFIG_IP_NF_TARGET_DSCP is not set
# CONFIG_IP_NF_TARGET_MARK is not set
# CONFIG_IP_NF_ARP_MANGLE is not set
# IP: Virtual Server Configuration
# CONFIG_IP_VS is not set
# CONFIG_XFRM_USER is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
| Why Debian?
This is why I used the Debian GNU/Linux distribution (and perhaps it's why you should too):
- The Debian package management system (*.deb files, handled
by the "apt" suite of tools, apt-get, apt-cache, etc.)
works really well to automatically deal with the problem
of cascading dependencies. (It could be that the Redhat
world is lurching toward a way to get you out of Rpm Hell,
but Debian has had one in place for years.)
- Because Debian is not a commercial entity, there is no
financial pressure on them to add "features".
They maintain three flavors of sub-distributions,
"stable", "testing" and "unstable", and they remain
very conservative with what happens to stable. They back
port security fixes to stable long after many a commercial
distro would have abandoned the code base.
- Because of all of the above, it's fairly simple
to make security upgrades automatic. You can make
it a near certainty that you won't get nailed on
a known exploit (which is the way most machines
get cracked). And also, you can be reasonably
certain that a security upgrade won't break
| Why not Redhat?
There are lots of reasons I'm getting away from the Redhat
distro. These are inflammatory enough to move
from here to "The Whinery":
The Whinery: Farewell Redhat
|Honorable mentions: freebsd, openbsd, knoppix
But maybe you should think about using openbsd or freebsd.
Kernel upgrades in Debian are only slightly less
painful than in other distros. Maybe the Freebsd ports system
would work better? And Openbsd is supposedly
designed with security in mind, no code is included
without undergoing a heavy security audit. (So why didn't I use
Openbsd? To limit the amount of stuff I needed to learn to get
the job done. I insist that this is valid, despite the academic
attitude you get from many quarters: "Learning is good! You should
try and learn everything! What, are you lazy or something?"
Realistically, you need to call your shots.)
(Why didn't I use the Debian-based Knopix with it's excellent
There's not enough disk on the ancient Compaq Deskpro 2000
I'm using as a firewall. And it's a little light on memory to run
X -- a mere 65Mb -- so all that KDE stuff would be doubly useless.)
- More than you will (hopefully) need to know to turn on those pretty green lights:
- A really good networking reference. Note the section: "25.7.2 Debian networking scripts" (Read this.):
Introduction to IP
- And here's probably more detail than you want (at the moment) on internet routing:
- This looks kind of interesting also... didn't find it until I didn't need it any longer:
- Ditto for this one, I'm not sure how I missed it (but
it's probably just as well... this is the kind of
"howto" that if you understand it, maybe you don't
Securing Debian HOWTO
- Here's one I skipped on purpose (ipfwadm? ipchains?
Could be this needs an update):
| Some books I used (or tried to):
It may be my imagination, but that basic piece of information
about which IP address ranges are reserved for internal network use seems
to be missing from "TCP/IP Network Administration".
I needed to look it up again in
though it's also in:
Introduction to IP
- "Learning Debian Gnu/Linux" by Bill McCarty (O'Reilly, 1st ed, 1999)
This has way too much stuff in it I didn't need to hear
about again (an Introduction to Bash!), but there's
an appendix in the back about dpkg and apt-get that
I found useful. This doesn't talk about "apt-cache search"
though, which is close to essential, but that's what I get for
using ancient books.
- "Running Linux" by Matt Welsh and Lar Kaufman (O'Reilly, 2nd ed, 1996)
- "TCP/IP Network Administration" by Craig Hunt (O'Reilly, 2nd ed, 1998)
I flipped through these books off and on to try and convince
myself I understood routing tables. These books generally
gave me the feeling I didn't really understand them,
but as it turns out none of my problems were in the "route
This page has received some comments/suggestions/criticisms, etc.
I'm going to try and summarize some of them here...
| stable has iptables/netfilter and shorewall
I thought that iptables couldn't be made to work
with the 2.2 kernel and the Debian stable branch (woody).
I'm not sure where I got this idea. A contributing factor
might be the history of netfilter/iptables:
Finally, the fourth-generation tool, `iptables', and another
kernel rewrite occurred in mid-1999 for Linux 2.4. It is
this iptables which this HOWTO concentrates on.
And the netfilter.org
site leads off with this remark:
netfilter and iptables are building blocks of a framework inside the Linux 2.4.x and 2.6.x kernel.
But hopefully this isn't all that lead me astray, because
while stable/woody is based on the 2.2 kernel, one of the
significant things about Debian stable is that the security
team backports security related improvements. You might not
assume that netfilter was backported, but you'd certainly
expect that that was at least considered.
Also, stable/woody does come equipped with Shorewall,
though it is an older version (1.2 vs. 2.0).
You might wonder if the stock kernel that comes with 3.0
Debian was compiled with netfilter, but evidentally it is:
The standard Debian 2.2 kernel (also 2.2) provides the
packet filter ipchains firewall, Debian 3.0 standard
kernel (kernel 2.4) provides the stateful packet filter
iptables (netfilter) firewall.
And there's a trick that I hadn't even occurred to me to
wonder about: you can upgrade to the 2.4 kernel
and still run stable:
Note that Debian 3.0 woody allows users to install 2.4
kernels (selecting flavors), however the default kernel
is 2.2 (save for some architectures for which kernel 2.2
was not ported). If you consider this a bug consider Bug
145244 before sending it.
10 Sep 2004