Generating Firewall Rules with Perl

With all of the evil-doers on the Internet, even most new computer users understand the importance of having a secure firewall.

Like most Linux users, I started out using a simple Bash script to configure the firewall policy on my Linux machines. Eventually, I got tired of writing the same code over and over again, so I decided to use a few program loops to try to factor out some of the redundancy. I also decided that I'd like to separate the actual policy from the rest of the program; this meant that the program would be reading external configuration files. As my Perl skills are vastly better than my Bash skills, I decided to write my firewall rules in Perl.

The program I'm outlining in this article could just as easily have been written in Bash or another scripting language (or even C++, for that matter). The language isn't important. The important thing to realize is that once you write a program like this and debug it, all you have to do to modify security rules is change a configuration file and rerun the script. The configuration files should have an intuitive format so that they are easy for humans to read, understand and modify.

Listing 1 shows the Perl script. I practice top-down programming, so the first several lines of code should give you a good idea of what the program does. Hopefully, you should be able to follow what the program does even if you aren't a Perl programmer.

As you can see, the program isn't very long and certainly isn't very complicated. However, the program is flexible enough to allow me to whitelist or blacklist either individual machines or entire networks completely. As we'll see later on, the build_chains() and add_rules() functions implement a rule-pruning algorithm that keeps the Linux kernel from having to evaluate irrelevant rules.

The set_ip_forwarding() function does what its name implies; it tells the Linux kernel either to forward IP packets, or not to forward packets. The function accepts a single parameter, either 0 or 1, which determines whether the kernel will forward. The script initially turns all forwarding off while it loads the firewall policy. Then, right before the script exits, the script turns forwarding back on. The reason for these extra steps is that we want the router to be in a safe state while we load the actual rules. It's better to block all traffic than it is to allow even one attack through.

The load interfaces() function reads in the names of the network interfaces and assigns mnemonic labels to them. These labels are then used in the rest of the configuration to refer to the actual interfaces. Being able to refer to an interface as lan or even vpn_to_work cuts down on misconfigurations. This also makes it easy to make changes in order to tailor the firewall for use by my friends. In many cases, I simply adjust the interfaces.conf file to reflect my friend's network and suddenly, my friend has a reasonable firewall configuration.

The script works via four configuration files: interfaces.conf, good_hosts.conf, bad_hosts.conf and ports.conf.

Listing 2 shows the contents of my interfaces.conf file. As you can see, I've got six network interfaces in my router. My Internet connection is on eth5. I've got a 10/100TX Ethernet for the house wiring. I've got a Gigabit Ethernet connecting my MythTV PVR to the router for file storage. I've got interfaces for the Wi-Fi and VoIP. Finally, I have a VPN connection to some of my friend's computers. It's much easier to remember that lan is my 10/100 copper network as opposed to trying to remember whether eth3 is my VoIP or Wi-Fi interface. The last thing you want to do is apply the right firewall rule to the wrong interface.


Mike Diehl is a freelance Computer Nerd specializing in Linux administration, programing, and VoIP. Mike lives in Albuquerque, NM. with his wife and 3 sons. He can be reached at


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Error in add_good_hosts subroutine

sebyte's picture

Hi Mike,

Trying to get this working.

I've only one good host, namely loopback so my good_hosts.conf looks like this: loopback

and I'm getting the following error on stdout when I run the script:

Setting IP forwarding to 0.
Try `iptables -h' or 'iptables --help' for more information.
X: (512) iptables -A INPUT -s loopback -j ACCEPT
Try `iptables -h' or 'iptables --help' for more information.
X: (512) iptables -A OUTPUT -d loopback -j ACCEPT
Setting IP forwarding to 1.

I'm not much a Perl coder I'm afraid, and by the looks of it it's an iptables issue rather than a Perl issue.

Any help much appreciated.


Error in add_good_hosts subroutine

Mike  Diehl's picture

Are you putting a TAB after the IP address, or a SPACE? The script splits on tab. I'll bet this fixes your errors.

Email me directly if it doesn't. My address in in the article.