Learning Network Security with Linux Iptables Firewall Scripts

The essence of security is simplicity, and when it comes to workstation or small-office Linux firewalls I have always been a fan of direct iptables use over some of the more popular alternatives ([g]ufw, fwbuilder). While they may be easier to use, they also hide a lot of the details. Especially when you are starting to learn about firewalls and network security, I believe you are better served using customizable firewall scripts like the two I detail below. When you get comfortable with iptables and networking concepts, then you can look to some of the other solutions. At that point, you'll fully understand what they are doing under the hood.

Iptables Scripts

The first aptly-named shell script, 'firewall.sh', is meant to protect a SOHO or home office network behind a dual-homed (two interface) firewall. It doesn't support DMZ hosts, but does support the most common scenario of SOHO or home firewalls doing double-duty as SSH or web servers. It features forwarding, NAT (network address translation), syn-flood protection and rate-limiting for log entries.

The next script, 'bastion-host.sh', is much simpler, and is meant to be used on any host directly connected to the Internet, like a home workstation or laptop. It drops all inbound connections by default. Both scripts are well-commented, with any variables and each section explained. You can download the scripts here:

Startup Options

The way I like to use these scripts on a Debian or Ubuntu system (see below for an alternative if you use network manager) is very simple and is as follows:

First, put your chosen script in /usr/local/sbin, and make it owned by root with permissions 0700.

sudo cp ./firewall.sh /usr/local/sbin; chown root.root /usr/local/sbin/firewall.sh; chmod 0700 /usr/local/sbin/firewall.sh

Edit /etc/network/interfaces, and add the following line to the interface stanza of your external interface (usually eth0):

pre-up /usr/local/sbin/firewall.sh

So the stanza for your external interface will probably look something like this when you are done:

interface eth0 inet dhcp pre-up /usr/local/sbin/bastion-host.sh or interface eth0 inet static address netmask gateway pre-up /usr/local/sbin/firewall.sh

On desktop systems where you are using the network manager application, or on Red Hat, CentOS or Fedora systems, you can put scripts like this in /etc/rc.local (On Red Hat systems the comments and touch command are there already by default):

#!/bin/sh # # This script will be executed *after* all the other init scripts. # You can put your own initialization stuff in here if you don't # want to do the full Sys V style init stuff. touch /var/lock/subsys/local /usr/local/sbin/firewall.sh

Just make sure that if you use this method on Red Hat based systems, you stop the default iptables firewall:

/etc/init.d/iptables stop chkconfig --level 2345 iptables off

If you would rather integrate your firewall into the Red Hat startup scripts, run the firewall script of your choice directly. Then save the rules so they will be read by the iptables init script:

/usr/local/sbin/firewall.sh iptables-save > /etc/sysconfig/iptables service iptables restart

You would then need to do this every time you made a firewall script change.


When you make changes to the script, just run it again directly and check the firewall status (see below). There are times when an erroneous change will lock you or a network client out of your server. If you have direct access to the host, you can correct any errors that occur immediately from the console. If you are making firewall changes over an SSH session, rename the firewall script first, and make changes on the copy, so that you can just reboot the box as a last resort to get a known-good configuration. Some hosting providers also provide a remote console that is ideal for fixing mistakes.

Monitoring Firewall Status

You can view the currently loaded ruleset as follows:

iptables -L -nvx iptables -t nat -L -nvx

The -nvx options give you the most detail possible - showing IP addresses instead of hostnames and full packet counts. This comes in handy if you want to see how often a rule is being hit, or if some rules never get hit. The option -t nat shows just the rules in the NAT table.

One final note, there is an ip6tables command that is the analogue of iptables for IPv6, and can be used independently of and alongside it.