Firewall uptime and security with iptables

Set up and maintain a Linux firewall with this effective application

Iptables is an application allowing the administration of the tables in the Linux kernel firewall. You don't need prior knowledge about the kernel, or the actual tables in it, for firewall modifications and common system administration tasks.

In some Linux distributions, iptables comes enabled by default. It is common for inexperienced users to recommend completely disabling iptables to avoid networking issues. This article will help you get started quickly and manipulate iptables to your needs.

Sometimes iptables is used to refer to the Linux kernel-level component. In this article, anything related to iptables will specifically refer to the application that controls the protocols in a Linux distribution like ipv4, ipv6, and the ARP tables.

Similar to other Linux applications, you can configure iptables in the command-line interface or in a plain text file, allowing editing with any text editor. Although it is easy to modify, it might feel awkward from the average firewall appliance where most of the interaction with settings and configurations is done in a graphical interface. There are applications using iptables to manage a firewall through graphical interfaces, but this article will cover interacting with iptables in its native environment: the Linux terminal.

Having a comfort level using a Linux terminal (also referred to as a console or terminal emulator) will help developers take advantage of the examples and configurations that follow. The command-line interface is the primary way to interact with iptables, and a Linux terminal is the application allowing access to this interface.

The rules that are applied are mostly very readable and easily ported to other servers. This feature saves significant time when dealing with unresponsive hardware.

Application requirements

Although iptables is the main subject of this article is, and it is probably already installed in your environment, we will also use nmap, which is another powerful application.

Verify that nmap is installed before continuing. You can install this effective network scanner in a Debian/Ubuntu Linux distribution.

Listing 1. Installing nmap on Debian/Ubuntu
sudo apt-get install nmap

Get started

Because we are going to make modifications at the kernel level, make sure you have root privileges.

Listing 2 shows the rules currently being applied to the server. Listing 2 will be repeated during the article to verify what rules are currently in use and to verify successful changes.

Listing 2. Currently applied rules
root@desktop:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

In Listing 2, we instruct iptables to list all rules currently applied to the firewall. This is accomplished by the -L flag.

The output also mentions Chain. Think of iptable chains as sections in the firewall allowing a certain type of traffic. For example, to block all traffic from the private network to the internet, that rule would be set in the OUTPUT section. Similarly, any rule affecting incoming traffic would be listed in the INPUT chain.

The three chains are each applied to one type of activity in the firewall. At this point, there is nothing set yet. This means there are no restrictions and all network traffic is allowed to come and go.

  • Chain INPUT
  • Chain FORWARD, and
  • Chain OUTPUT

Before continuing, it is necessary to verify what ports are open on the server for comparison after it is locked down. As mentioned before, nmap is a powerful command line tool that provides network security information. Listing 3 shows the output of nmap in a remote server on the network.

Listing 3. Network scanning with nmap
~ $ nmap

Starting Nmap 5.35DC1 ( ) at 2010-11-21 20:44 EST
Nmap scan report for
Host is up (0.012s latency).
Not shown: 991 closed ports
22/tcp   open  ssh
25/tcp   open  smtp
53/tcp   open  domain
80/tcp   open  http
631/tcp  open  ipp
3306/tcp open  mysql
4001/tcp open  unknown
5900/tcp open  vnc
8080/tcp open  http-proxy

Nmap done: 1 IP address (1 host up) scanned in 6.57 seconds

Those are a lot of open ports! In just a few steps, you will learn how the above changes after iptables is configured.

Firewall rules can be either applied and appended, or edited manually in a plain text file, and sourced. I prefer using a text file to apply changes. Most of the time syntax errors are easier to catch when written in a text file. Another problem arises with editing rules by appending rules directly, that is, these rules will not be saved when a server reboots. Before editing the file, let's tell iptables to export the current rules so that file becomes our initial template. See Listing 4.

Listing 4. Saving rules to a file
root@desktop:~# iptables-save > /etc/iptables.rules
root@desktop:~# cat /etc/iptables.rules 
# Generated by iptables-save v1.4.4 on Sun Nov 21 14:48:48 2010
:INPUT ACCEPT [732:83443]
:OUTPUT ACCEPT [656:51642]
# Completed on Sun Nov 21 14:48:48 2010

I used the iptables-save command and redirected the output to a text file in the "/etc" directory. I have concatenated the file so you can see what the file looks on my machine.

One of the first requirements is to allow established connections to receive traffic. You need this when you want anything behind the firewall (in a private network) to be able to send and receive network data without restrictions. In Listing 5 we will issue a direct rule to iptables and verify the state of the firewall afterward.

Listing 5. Established sessions rule
root@desktop:~# iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
root@desktop:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            ctstate RELATED,ESTABLISHED 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

To have a better idea of what was issued, let's break the command apart and explain each one:

-A INPUT: Append this rule to the INPUT chain.

-m conntrack: Match the following connection tracking for the current packet/connection.

-ctstate ESTABLISHED, RELATED: Connection states that the rule should apply to. In this case, an ESTABLISHED connection means a connection that has seen packets in both directions and a RELATED type means that the packet is starting a new connection but it is associated with an existing connection.

-j ACCEPT: tells the firewall to accept the connections described before. Another valid setting for the -j flag would be DROP

I'm also connecting through the SSH protocol to that server, so before locking down the firewall, a rule in Listing 6 is going to allow all incoming SSH traffic. I specify the type of network protocol (tcp) and the port that is conveniently associated with the SSH service. You can specify the port number directly if needed.

Listing 6. Accepting inbound SSH connections
root@desktop:~# iptables -A INPUT -p tcp --dport ssh -j ACCEPT
root@desktop:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            ctstate RELATED,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh 

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Finally, let's set the firewall to block everything else. Take special care when issuing the following command. If it is placed before all the other rules, it will block any and all traffic to the server. Iptables reads rules in a procedural fashion (from top to bottom) and after a rule is matched, nothing else gets evaluated.

Listing 7. Blocking all incoming traffic
root@desktop:~#  iptables -A INPUT -j DROP
root@desktop:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            ctstate RELATED,ESTABLISHED 
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ssh 
DROP       all  --  anywhere             anywhere            

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Listing 7 shows that the rules are in the proper order, but to be able to make specific changes, let's save the rules to a file and concatenate it to check the contents as in Listing 8.

Listing 8. Verifying firewall configuration
root@desktop:~# iptables-save > /etc/iptables.rules 
root@desktop:~# cat /etc/iptables.rules 
# Generated by iptables-save v1.4.4 on Sun Nov 21 15:10:42 2010
:INPUT ACCEPT [1234:120406]
:OUTPUT ACCEPT [1522:124750]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT 
# Completed on Sun Nov 21 15:10:42 2010

The iptables-=save command pushed our changes to a plain text file. It does look a bit different from just listing the rules in the command line, but it is exactly the same thing. Just as before, we have three sections: INPUT, FORWARD and OUTPUT. The rules that we initially specified concern OUTPUT connections, so this is the section where the rules we added are placed.

At this point, the server is locked and the configuration has been saved to a file. But what will happen when we perform a network scan? Let's run nmap again against that server and check the results as shown in Listing 9.

Listing 9. Network scan with locked down server
~ $ nmap    

Starting Nmap 5.35DC1 ( ) at 2010-11-21 20:56 EST
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 3.04 seconds

~ $ nmap -Pn

Starting Nmap 5.35DC1 ( ) at 2010-11-21 20:56 EST
Nmap scan report for
Host is up (0.017s latency).
Not shown: 999 filtered ports
22/tcp open  ssh

Nmap done: 1 IP address (1 host up) scanned in 12.19 seconds

Note that a scan was attempted against the IP where the server is located, but nmap failed to list the open ports. This happens because the firewall is set in such a way that it is blocking everything except for the SSH port we have open. Since nmap uses a specific network protocol to verify if the host is up, it returned empty handed. The second try was successful and is telling us that only SSH is open and nothing else. With just three rules, we managed to get an effective lock down of our server.

Saving and restoring rules

In the previous section, we saved the rules to a text file. However, that doesn't effectively tell the server that it needs to load the rules. Also, when the server reboots, it loses all the configuration done.

If you are adding rules on the command line, you should already be familiar with saving those changes to a text file. See Listing 10 for saving the firewall rules.

Listing 10. Saving the firewall rules
iptables-save > /etc/iptables.rules

Depending on the operating system in use, there are several ways to get those rules to load on start up. An easy approach is to go to the one interface that is public facing and tell it to load those rules before bringing the interface on line. See Listing 11.

Listing 11. Public network interface loading rules
auto eth0
iface eth0 inet static
  pre-up iptables-restore < /etc/iptables.rules

Here we have the eth0 interface and are declaring a rule to load the rules before bringing the interface up. As you may have guessed, you can use these commands to manually update the firewall rules from and to the file.

Disaster recovery

Not long ago, I was in a situation where I was responsible for a firewall appliance. Although I was making sure periodic backups of the rules and configurations were made, I failed to realize that those backups were in a proprietary format and only readable by the appliance model I had. That isn't a problem, of course, as long as you have two appliances of the same brand, model, and firmware version, but, as is common in small businesses, the budget didn't allowed for anything else.

One day, that appliance decided not to run anymore and I had to implement something fast that could be as reliable (or better). I learned the hard way that having human-readable configurations and the ability to come back up quickly are very important assets.

With some luck, I found an old server in good condition with a couple of network interfaces and was able to replace the dead appliance.

Until now, we have gone through scenarios of obtaining a copy of the rules that could be easily applied to any server in case of failure. Now let's enable the firewall to be the main gateway for a small home or business network.

Iptables as a main gateway

So far everything we've covered is great if you are running iptables on a personal computer, but it doesn't make much sense if a whole office needs to share an internet connection. With a few configuration settings, we can set that up properly.

We are going to assume that the server has two physical network interfaces: eth0 (public) and eth1 (private). I need to NAT them together so network traffic flows seamlessly from one interface to the other. The private network subnet is, so let's see how a NAT rule with forwarding would look in Listing 12.

Listing 12. NAT and forwarding rules
iptables -A FORWARD -s -i eth0 -o eth1 -m\
conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A POSTROUTING -t nat -j MASQUERADE

Listing 13 shows how to modify some settings in proc to enable forwarding in the server.

Listing 13. Enabling forwarding in the server
sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"

Note that proc changes are volatile, so any changes made there are lost after a reboot. There are several ways to make sure that the modifications will stick after a reboot. In Debian/Ubuntu distributions, add the lines to get executed in /etc/rc.local.

Finally, as shown in Listing 14, there is one more setting change that modifies kernel parameters at runtime (sysctl). These configurations are usually already in the sysctl.conf, but are commented out. Uncomment them (or add them if they are not included with your distribution).

Listing 14. Sysctl/kernel forwarding

ARP cache threshold

Running a Linux server as a gateway will cause certain issues with DNS. The kernel is designed to keep a mapping of IP addresses, but it comes with a maximum level of entries that are not suitable for heavy traffic. When this level is reached, no DNS queries get back to the host who asks. While such a threshold is rarely reached with a few clients, more than thirty clients going through this firewall will cause a problem.

The environment may need some adjusting, but the values shown in Listing 15 should provide room before seeing such issues.

Listing 15. Increasing the ARP cache size
echo 1024 > /proc/sys/net/ipv4/neigh/default/gc_thresh1
echo 2048 > /proc/sys/net/ipv4/neigh/default/gc_thresh2
echo 4096 > /proc/sys/net/ipv4/neigh/default/gc_thresh3

Be on the lookout for messages similar to those in Listing 16, which will provide a warning if it is necessary to increase the numbers just provided.

Listing 16. System log ARP cache overflow warnings
Nov  22 11:36:16 firewall kernel: [92374.325689] Neighbour table overflow.
Nov  22 11:36:20 firewall kernel: [92379.089870] printk: 37 messages suppressed.
Nov  22 11:36:20 firewall kernel: [92379.089876] Neighbour table overflow.
Nov  22 11:36:26 firewall kernel: [92384.333161] printk: 51 messages suppressed.
Nov  22 11:36:26 firewall kernel: [92384.333166] Neighbour table overflow.
Nov  22 11:36:30 firewall kernel: [92389.084373] printk: 200 messages suppressed.


We have gone through some simple steps to get iptables to run properly and to safely lock down a Linux server. The rules applied should provide a good sense of what is going on in a server using iptables as a firewall. I encourage you to give iptables a try, especially if you depend on an appliance and want more control and easily replicated human-readable configurations.

While the rules used we've used here are simple, the full flexibility and complexity of iptables is beyond the scope of this article. There are many complex rules that you can combine to create a safe and controllable firewall environment.

An example of an interesting advanced feature in iptables is load balancing. Most of the time, when exploring high availability web services, you are seeking load balancing solutions. With iptables, this can be set and configured with the random or nth flags.

You can also do time-based rules. In a small office environment, it might be useful to restrict certain services from Monday through Friday, but let the firewall behave differently on Saturday and Sunday. The flags that might work in such a case are: --timestart, --timestop and days.

A problem I experienced was not having two firewalls at the same time with some kind of fail over. Creating such a thing is no easy feat, and can be approached in several ways. The easiest solution would be to have the router do the job and load balance two identical Firewall servers. I recommend looking into such an option if the network environment is a critical asset like an office or small business.

Iptables saved me once, and I hope it does the same for you!

Downloadable resources

Related topics

Zone=Open source, Linux, Security
ArticleTitle=Firewall uptime and security with iptables