After having a look around the debian mailing lists for firewalls I came across someone recommending a pre-written package that does most of the hard work for you. The iptables init script is not really designed to be used and is only in place to solve a Debian specification requirement. The best way to start the firewall is to have it come up just before the interface comes up. This can be achieved by making it a pre-condition of the interface. Interfaces are configured in the file
a basic default layout of which can be seen below (where xxx.xxx.xxx.xxx replaces an ip addresses)
# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8) # The loopback interface auto lo iface lo inet loopback # The first network card - this entry was created during the Debian installation # (network, broadcast and gateway are optional) auto eth0 iface eth0 inet static address xxx.xxx.xxx.xxx netmask xxx.xxx.xxx.xxx network xxx.xxx.xxx.xxx broadcast xxx.xxx.xxx.xxx gateway xxx.xxx.xxx.xxx auto eth1 iface eth1 inet static address xxx.xxx.xxx.xxx netmask xxx.xxx.xxx.xxx
When the machine boots this file is checked and any interface marked as auto (using "auto <interface_name>") will be passed to ifup to be brought up. It is possible to set pre and post conditions for both bringing up an interface and taking it down again. This is how we will bring up our firewall.
Now would be a really good time to make sure that you are using a kernel that is new enough to support iptables (eg a 2.4.x kernel or better) if not you are going to have to upgrade it so that you can use iptables. If you installed as I did in this, document you will have (at the time of writting - June 2004) a 2.2 kernel even if you do a dist-upgrade since the testing version still contains a 2.2 kernel. If you need to upgrade your kernel I suggest you have a read of this first.
At this point it is worth pointing out that for the most part I am going to be following the instructions that I found here since there is little point in re-inventing the wheel with this. I will point out where I differ and give a quick summary of what I do but if you want more instructions and a deeper understanding that is well worth a read. One of the more important changes I will be making is to ditch the firewall rules that are shipped in the package you can download from the site.
Download the script and rules provided here and unpack them with
tar xvzf iptables_files.tar.gz
this will create a directory called iptables where ever you run that command. Move this directory to "/etc" with the command
mv iptables /etc/
The directory and all it contents should now be in "/etc". Since you don't want just anyone to be modifying the firewall rules you have to change the permissions on the "/etc/iptables" directory and the files it contains. The quickest way to do this is to exectute the following commands
chown -R root:root /etc/iptables chmod 750 /etc/iptables
This produces a set up that is a little more secure than the one on given in the original instructions since it only allows root access which is fine since the interfaces are brought up by root during boot.
It is now really worth the time to read the configuration section of the original document in order to understand the shipped iptables.rules file. It is a very large and complex script that does everything except make the tea afterwards. If you get the configuration of this script wrong you are quite likely to lock yourself out of your machine (except for direct console access). Later on I will replace this script with static rules or my own script since it is far more complex than I require and it is good for the soul to write your own firewall rules!
The "at" Command
As I said above you are likely to lock yourself out of your machine the first time to use this script so it is well worth the time investing in a little insurance against that unfortunate eventuality. The insurance I suggest you choose is the "at" command. This excellent command allows you to schedule a command to be run at some future time. This insurance is not so important if you are working at a local console since it is very hard to lock yourself out but if, like me, you are working remotely I suggest you schedule an "at" command to run that opens the firewall again.
Before I go into how to bring the firewall back down with "at" it is necessary to setup the firewall so that it starts at boot time. This as I said can be done by making it a pre-condition of the external interface coming up. Open the file "/etc/network/interfaces" and add the following two lines to the eth0 definition (under gateway in the example above)
pre-up /etc/iptables/iptables.sh start post-down /etc/iptables/iptables.sh stop
We are now about ready to go. The firewall rules will be generated for us when we next ifup the eth0 interface. The only thing left to do is invest in that insurance.
Produce a file called something like "stop_firewall.sh" and place it in "/etc/iptables". In this file place the commands required to stop the firewall and flush all the rules. This will set the firewall up to accept your connections again. In this case the script is quite simple since the packaged script does this when the interface is taken down. The script I use can be seen below
#!/bin/bash /etc/iptables/iptables.sh stop
You then schedule this command to be run 5 minutes after you activate the interface using this command
at now + 5 minutes -f /etc/iptables/stop_firewall.sh
You are ready to go. Bring up the firewall rules with the command
Testing Your Firewall
Now that you have your firewall running you probably want to test it to see how good it is. There are loads of firewall testers out there on the internet and they all do pretty much the same thing - send a bunch of packets to your machine and see what comes back. You should find that most of the scanners will report that either your machine is completely stealthed or not even there. A good tool for checking you firewall is nmap but this is only possible if you have shell access to another linux / unix machine.
We now need to set up ip forwarding so that machines inside our network can see the outside world. If you are not going to re-boot your server you need to make two small changes. If you are going to re-boot you only need to make one. Since a re-boot is not necessary lets not bother :o). The 2.4 kernel comes with the routing code built in and so it only needs to be switched on. This is achieved by echoing a 1 in to a particular file which is a flag to the kernel to tell it to start routing. The file you need to adjust is "/proc/sys/net/ipv4/ip_forward". The command below will tell you if routing is already turned on. As you can see ours returned 0 (zero) meaning it isn't.
cat /proc/sys/net/ipv4/ip_forward 0
To switch it on you echo as follows. Then test again with cat
echo 1 > /proc/sys/net/ipv4/ip_forward cat /proc/sys/net/ipv4/ip_forward 1
To ensure the setting is also set after a reboot adjust "/etc/network/options" so that the "ip_forward" flag is set to yes
The rules generated by the script mentioned above are very harsh (they stop apt from working!) and not completely necessary. I don't know if I set them up incorrectly or whether they are just wrong but either way I was unable to connect to any DNS servers that is despite setting the outbound DNS addresses mapping to 0.0.0.0/32 which should allow everything!
The primary change I have made is to replace the complex script which generates rules with a much simpler script that has each rule stated explicitly with a comment describing it. This is a slightly long winded way of doing it but it does result in a very easy to read script. The easier the script is to read the less likely you are to make mistakes. It is worth pointing out that there are loads of packages out there that automate some or all of the process of writting table rules but it isn't that hard to just write it by hand.
The first section of the rules deals with packet mangleing with all the chains set to an accept policy. To set a default policy for a chain use a command like this
iptables -t <table_name> --policy <chain_name> <value>
Where <table_name> is the name of the table (which defaults to filter if not specified; other options are mangle and nat), <chain_name> is the name of the chain (each table has a set of default chains; for instance filter has INPUT, OUTPUT and FORWARD) and <value> is what to do with the packet (this is generally one of either ACCEPT or DROP but can be a rangle of values). Its well worth setting the default policy for all the chains you make and a good idea is to set the default policy for the filter chains to be DROP.
You are to some extent on your own when it comes to making up firewall rules since every situation is different. I generally allow anything out but am very strict with things coming in. Filtering out going packets would help to stop the spread of worms but the down side is that you have to change the firewall everytime you want to visit an odd port. Its something that is more suited to a company situation than a home situation. I recommend reading (at least bits of) the Linux Network Administrators Guide and the whole man page for iptables.
The other thing to set up now is the natting (NAT stands for Network Address Translation and is how machines inside the network on private IP addresses get out). This is done using, rather unsupprisingly, the nat table. Simply set all the default policies to ACCEPT and then add a POSTROUTING rule to set up source natting. An example can be seen below (obviously replace xxx.xxx.xxx.xxx with your external IP address).
#========================== #======== NATTING ========= #========================== #======== DEFAULTS ======== iptables -t nat --policy PREROUTING ACCEPT iptables -t nat --policy POSTROUTING ACCEPT iptables -t nat --policy OUTPUT ACCEPT #====== POSTROUTING ======= #add a single rule to the post routing chain to allow natting iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source xxx.xxx.xxx.xxx
A small script such as that seen below is quite useful while you are setting up your firewall since it takes the work our of replacing files and restarting the firewall. This script copies a rules file from a given location such as your account and places it in the required location. In order to stop you accidently making modifications it is made read only and owned by root. It is important that only root can run this script though since it may be the case that the original file can be modified by anyone (although that is strongly discouraged. The pause is just to let things settle down before applying the new rules.
#!/bin/bash rm /etc/iptables/rules.sh cp <location_of_rules_file> /etc/iptables/ chown root:root /etc/iptables/rules.sh chmod 500 /etc/iptables/rules.sh /etc/iptables/iptables.sh stop sleep 5 /etc/iptables/iptables.sh start