Foreword

Firewalling in Linux is a pretty diverse topic. As far as I have experienced, there are almost as many firewall solutions as there are different distributions of Linux. When I setup firewalls across various Linux servers and distributions, I usually default to using simple iptables rules. For me, iptables is the most portable, accepted firewall that can be used for Linux. It allows for very complex configurations as well as very simple, yet effective ones. I have used UFW, FirewallD and others many times in the past. I have seen the use case for all of them and understand why people might choose to use one or the other, but in my experience, most of them are really just different frontends for iptables. There is nothing inherently wrong about this, but if you find yourself using a variety of Linux distributions like me, you will find that quite a few of these frontends aren't available or aren't packaged across the Linux ecosystem. Because of this, using iptables as your firewalling solution is both acceptable and recommendable.

iptables rules are flashed into it at runtime. Because iptables rules are flashed into active memory, instead of being read from a configuration file like most other firewalls, you might have to write some SystemD unit files or init scripts around flashing those rules into memory. This is a downside to iptables for some users. iptables has a pretty simple command line syntax that focuses around chains. Chains are very similar in concept to FirewallD's nic-based zones except that iptables chains are logical constructs that do not feel like they are tied so close to physical hardware like FirewallD's zones. It is possible to define your own chains with their own logic making iptables a highly advanced and customizable firewall solution for Linux.

Some Examples

The chain that I will speak to in this post is the INPUT chain because it is the chain I use the most and is the one that most are introduced to. First however, we need to see the rules currently flashed into iptables.

iptables -S shows the default chains INPUT, FORWARD, and OUTPUT. This command will also show the rules of each chain in the default chain list as well as some extra goodies such as additional chains that the user or a program might have added.

iptables default chains output

Adding rules is just as easy as listing them. If you wished to add a rule that would accept packets to port 22 (SSH) the rule would look like

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

There is a lot going on here, so lets digest it;

  • -A INPUT This just tells iptables to append the rule we are creating to the INPUT chain. If you wished to add a rule to the OUTPUT chain, you would replace INPUT with OUTPUT.
  • -p tcp This allows matching the rule to TCP packets. Important as SSH is a TCP protocol. To match all protocols, you would use all instead of tcp
  • --dport 22 is actually an argument to the tcp module. While the tcp module was not specified on the command line originally, it is added automatically my iptables when specifying the protocol type. This argument allows matching a packet to its destination port. In this case we are matching to port 22 (SSH)
  • -j ACCEPT This is the action clause. After matching all of the preceding identifiers, what does iptables do with the packet? That question is satisfied by this action clause where iptables is directed to, in this case, ACCEPT the packet. To do the opposite, replace ACCEPT with DROP.

Adding rules really isn't that bad hunh? It only gets simpler from here! Now that I have elaborated how to match packets and what to do with them, what about the packets that don't match these rules? For that, iptables has the -P flag to set the policy for a given chain. In the gif output above, we see that the policy for the INPUT, OUTPUT, and FORWARD chains is ACCEPT. This means that rules that don't match the rules in these default chains get accepted anyway. To change this we use the -P flag.

iptables -P INPUT DROP

This example is pretty straight forward so we don't have too much to digest but essentially we are saying that the default action to take on packets not matching a rule in the INPUT chains is to drop them. By taking this action, the packets never get forwarded to their destination in the system.

Closing

You made it! Thanks for reading this far and I hope I've highlighted some of my opinions about iptables and gave some exposure into iptables for those that are not familiar with it. If you would like to talk more, ping me on twitter!