One of the least expensive ways to provide your network with firewall protection is to build a Linux firewall yourself. Since you only need to install a basic Linux system, you can usually get away with using a superannuated PC, so there are no hardware or software costs involved. The only element that may cost money is a second network card but that will only cost a £10 to £20.
For the purposes of this How To, we'll assume you’ve already installed some flavour of Linux on the candidate PC. We chose Red Hat 9, but it doesn't really matter which distribution you go for. Just remember to choose the "minimal" installation - you don't need X-Windows, printer support, Web servers and the like, as they won't get used and will take space. Make sure too that you make all changes as the "root" user, since you'll need supervisory privileges to make the required changes.
The first thing is to check which network adaptor is which in your machine. The easiest way is to check the label on each adaptor card for its MAC address, and to make a note of which card has which address. Our test machine has an SMC card with address 00:E0:29:3D:79:50 and a NetGear one with address 00:02:E3:03:F7:D0. Now we can use the ifconfig command to see what Linux has called each adaptor.
[[email protected] root]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:E0:29:3D:79:50
inet addr: Bcast: Mask:
RX packets:288 errors:0 dropped:0 overruns:0 frame:0
TX packets:145 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:35206 (34.3 Kb) TX bytes:13280 (12.9 Kb)
Interrupt:5 Base address:0x4800

eth1 Link encap:Ethernet HWaddr 00:02:E3:03:F7:D0
inet addr: Bcast: Mask:
RX packets:274 errors:0 dropped:0 overruns:0 frame:0
TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:16662 (16.2 Kb) TX bytes:890 (890.0 b)
Interrupt:10 Base address:0xc000
We can see, then, that adaptor eth0 is the SMC card, and that eth1 is the NetGear one. You can also see that we've given each card an IP address – this was done using the ifconfig command again, for example:
[[email protected] root]# ifconfig eth0 netmask
[[[email protected] root]# ifconfig eth1 netmask

You'll see that eth0 has an address in the 192.168.1.x "private" address range; this will be our internal, or "trusted" interface, while eth1 is the external, "untrusted" port. The final basic configuration we need to do is tell the system where the default route to the Internet is – in this case a router with the address
[[email protected] root]# route add –net default gw
Now we can go ahead and configure the firewall rules themselves. We're going to use the IPTables packet filtering system that ships as standard with Red Hat 9, and whose rule-set you can build up with a sequence of commands on the Linux command line. If you've done a minimal installation of Linux, you'll probably find that it hasn't installed the IPTables software, which you can check by running:
[[email protected] root]# rpm –qa | grep –i iptables
If the package is installed, the rpm command should return something like iptables-1.2.7a-2. If it's not there, you'll need to stuff in the CD (or download IPTables from a site such as and then use rpm –i to install it. You'll need packet filtering capabilities turned on in your kernel, but so long as you're using version 2.2 or later of the kernel, this should be turned on by default anyway.
Now we've got the software installed, we just need to set up our firewall rules. When we installed the IPTables package, it placed a startup file in /etc/init.d that'll be used by Linux at startup to turn on our firewall rules. The first thing we need to do, then, is start up the IPTables process:
[[email protected] root]# /etc/init.d/iptables start

Once the program is running, we can add our rules. We do this by executing the iptables command; this injects our commands one-by-one into the firewall rule table. First, let's flush any existing rules:
[[email protected] root]# iptables –F
First we need to think about what our firewall trusts implicitly. First of all, we're going to allow all connections from the firewall itself (via the "loopback" interface):
[[email protected] root]# iptables –A FORWARD –i lo –j ACCEPT
[[email protected] root]# iptables –A INPUT –i lo –j ACCEPT
...and those coming in through the "trusted" Ethernet interface, eth0:
[[email protected] root]# iptables –A FORWARD –i eth0 –j ACCEPT
[[email protected] root]# iptables –A INPUT –i eth0 –j ACCEPT

The "ACCEPT" instruction tells the firewall to permit the connection immediately instead of looking at later rules. The directive specifying the FORWARD connection type deals with packets passing through the firewall and heading on somewhere; the INPUT type deals with packets that are destined for the firewall itself.
Next, we want to accept packets coming in on the external interface (eth1), but only those that are related to connections that have been established from inside our world (e.g. the incoming response to an outgoing HTTP request). There's a special flavour of the forwarding rules that lets us do this:
[[email protected] root]# iptables –A FORWARD –i eth1 –o eth0 –m state –state RELATED,ESTABLISHED –j ACCEPT
Now we simply need to tell it to drop everything that doesn't match the rules it's had already:
[[email protected] root]# iptables –A FORWARD –j REJECT

Right, nearly there. The only thing we've not considered so far is that the IP addresses on our internal network live in the "private" ranges defined by the Internet standards, which means that remote machines will be unable to actually route packets back in. We therefore need to implement Network Address Translation (NAT) on our firewall. This means that the firewall will stamp outgoing packets with its own "untrusted" interface's IP address instead of the real IP address of the calling machine; it also means that when packets come back into the firewall, it can shove them back to the appropriate internal machine:
[[email protected] root]# iptables –t nat –A POSTROUTING –o eth1 –j SNAT –-to-source
It sounds weird, but we don't actually now have to save these settings. The next time we gracefully restart the machine, the start/stop scripts will handle this for us. It's probably worth us storing the settings in case the machine gets shut down ungracefully, though, and we can do this with the iptables-save command:
[[email protected] root]# iptables-save > fw-config-17-feb-2004.txt
This will save the firewall configuration to a file called fw-config-17-feb-2004.txt, which we could use to restore the settings later (should we need to) using the iptables-restore command.
Now we've got the IPTables settings sorted, the last thing to do is make Linux act as a router. The kernel that comes with our Red Hat installation is able to do IP routing out of the box, though it's turned off by default. All we need to do to tell it to turn its routing feature on is change the system control configuration file (/etc/sysctl.conf) to include the line:
net.ipv4.ip_forward = 1
… and instruct the system to re-read its settings:
[[email protected] root]# sysctl -p
We now have a basic firewall that permits all outgoing traffic but drops all incoming traffic. Because we've changed the settings in /etc/sysctl.conf, the system will automatically turn on IP routing the next time it starts up; all we need to do is ensure that the IPTables script (/etc/init.d/iptables) is run at each startup – a concept we've already covered in a recent HowTo.
And that's it. The nice thing is that if we want to start getting complicated and, say, running an internal mail or Web server, IPTables is more than capable of allowing us to add rules for externally-initiated connections. But we'll leave that for another day.