Basic iptables tutorial

In this article, I will provide a brief tutorial for using iptables.  This article applies specifically to ImageStream routers, but more generally, it applies to ALL Linux based devices that use iptables for the filtering of traffic.  In another article, I will address firewalling in Mikrotik, which is, also, an iptables based firewall.  Some parts of this article will apply to Mikrotik, so it may be worth reading even if you are a pure Mikrotik shop.
The iptables filter chains are called based upon only one or two details in the IP header of a packet.  A routing decision is made by the kernel based on the SOURCE address (where a packet is coming from) and DESTINATION address (where a packet is going to).  The good news is that there are only 3 combinations we have to worry about.
INPUT - This chain is called for packets which are destined for the router. In other words, if the destination address belongs to the router itself, that packet is processed against the INPUT chain.
OUTPUT - This chain is called for packets which originate from the router. Things like the router sending it's syslog to a remote syslog server, replies to ping or echo requests (when the router sends a ping out) will be processed against this chain.
FORWARD - This chain is called for packets that enter the router and will be sent along to other devices. In other words, traffic that passes through the router will be processed against this chain.
These 3 chains are referred to as "built in" chains, since they are the 3 chains that are "included" as part of iptables.  Strictly speaking, there are 2 additional chains called "PREROUTING" and "POSTROUTING", but these are not filter chains, so we won't deal with them here.  So, what does all this have to do with building a firewall?  Think of it this way. . . If I want to control traffic that is passing through my router between the Internet and my customers, then I will have to use the FORWARD chain in order to filter/manage that traffic.  If I want to limit who is able to connect to my router, I have to use the INPUT chain.  If I want to manage traffic such as syslog or other router generated traffic, then I will be using the OUTPUT chain.  It is fairly uncommon to see a large ruleset in the OUTPUT chain, as most of the traffic that will match in the OUTPUT chain is controllable either via a management setting (configured syslog server for example) or by controlling the INPUT (no need to limit echo reply if we simply control where we allow echo requests to come from).  It is VERY IMPORTANT to not think of these 3 chains as having anything to do with the direction of traffic as it relates to your network.  A very common mistake is to put a rule in the INPUT chain, thinking that will prevent traffic from the internet from scanning your customer's computers. For the above 3 "built-in" chains, the default policy is ACCEPT.  This means that if you have no rules in a given chain, then packets that would be processed against that chain will "automatically" be accepted.  You can change this policy easily, by using a command similar to the following:
iptables -P INPUT DROP OR iptables --policy INPUT DROP
NOTE: Mikrotik does not provide a method to change the chain policy.  You can change the behaviour of a chain by adding a rule at the end of a chain that will DROP all previously unmatched traffic.  This will SIMULATE the act of changing the policy, but is not exactly the same thing. Both of the preceding commands do exactly the same thing.  Both commands change the INPUT chain's policy to "DROP", which means that traffic that is not otherwise accepted in the firewall's INPUT chain, will be silently discarded (DROP).  The idea of policies is fairly simple idea, but you must clearly define the purpose of a firewall in order to choose the correct policy for a chain.  We will discuss the idea of policy statements in a future article, but it should be sufficient to understand that a firewall is more than a series of "rules" that filter this traffic or allow that traffic. Next, we'll look at the structure of an iptables command and some of the basic options.  I won't list all the options here, but we will discuss some of the more commonly used options.  You can view the iptables manual page at http://linux.die.net/man/8/iptables or by typing "man iptables" at a Linux command  prompt.  The basic format for an iptables command is as follows:
iptables [-t table] -COMMAND [arguments and options]
The "iptables" portion is simply the name of the iptables program.  In a shell script, you may need to specify the command and path, such as "/sbin/iptables", as shown in the example script earlier.  The next section "[-t table]" is optional if you will be working with the filter table.  I'll discuss these tables a bit later.  The next part of of the command line is the actual command or function you want the iptables program to perform, along with some optional arguments and options that are part of the command.  We'll look at the parts one at a time. First, is the optional "table" argument.  There are several tables that are commonly used, though our discussion here will remain centered on the filter table.
filter table - This is the default table.  If you don't supply a "-t" option on the command line, the command is performed on this table.  It is the filter table that includes the built in chains called "INPUT", "FORWARD" and "OUTPUT" as described above. nat table - This table is consulted only when a packet that creates a new connection is encountered.  There are three built-in chains called "PREROUTING", "OUTPUT" and "POSTROUTING".  If you want to NAT traffic (source or destination NAT), this is the table you'd use.  An example command would be:

iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

mangle table - This table is used for specialized packet alteration. There are five built-in chains called "PREROUTING", "OUTPUT", "INPUT", "FORWARD" and "POSTROUTING"  We won't discuss the mangle table in much detail in this article, but it is useful for setting DSCP values on packets.  Another common use for the mangle table is for marking packets for QOS.
The next portion of an iptables command is the actual command.  Most iptables commands have both a long and short version.  The long version of the commands below are enclosed in parentheses.  Some of the most common of these commands are:
-A  (--append) or -D (--delete) - Append/delete a rule in the indicated chain or in a specific location in a chain.  This command requires at least 2 arguments.  Required arguments are the chain and "rule specification".  Here are a couple of examples:

iptables -A INPUT -p tcp --dport 23 -j DROP

This command adds a rule at the end of the INPUT chain that will drop all traffic destined for the router (remember what the INPUT chain is for) and is a tcp packet with destination port 23 (telnet).

iptables -D INPUT 4

This command would delete the 4th rule in the INPUT chain.  Rules are numbered beginning at 1 (not 0).

-I (--insert) - Insert a rule in the indicated chain at position "X".  This command requires 2 arguments in addition to the rule specification.  The first argument is the chain and the second argument is a number indicating the position you want this rule placed.

iptables --insert INPUT 2 -p tcp --dport 22 -j DROP

This command inserts a rule in the second position in the chain INPUT that will drop tcp traffic destined for port 22 (ssh).  The rule would be placed between the previous rules in position 1 and 2 (the old rule number 2 would become number 3).

-R (--replace) - Replaces a rule in the indicated chain.  Again, 2 arguments are the chain and the position you want to replace. This command is not likely to be used in a script. -L (--list) - List the rules in the indicated chain.  If you don't indicate a chain, then all chains are listed. -F (--flush) - Flush all rules in the indicated chain.  If no chain is indicated, the all chains in the table are cleared.  This is the functional equivalent to deleting all rules one at a time. -P (--policy) - Set the default policy for the indicated chain.  This command requires 2 arguments.  The first argument is the chain and the second is the TARGET.  The most common target specified will be DROP, while the default policy target for the built-in chains is ACCEPT.
Some of the commands require arguments that will match specific traffic.  These are the commands that actually do the work of filtering traffic.  These commands include -A, -R and -I.  These rules have the following parts:
iptables -A INPUT -s 192.168.0.0/24 -p tcp --dport 22 -j ACCEPT

The iptables command (append).

The chain to operate on.

The MATCH parameters.  This indicates the specific traffic that we want to match.

The ACTION to take for the traffic that matches this rule.  In the documentation for iptables, you will see this referred to as the TARGET.

As you can see from the above example, this rule would match any packet that has a source address of 192.168.0.0/24 (anything in the range) AND is a TCP packet AND has the destination port of 22.  For all traffic that fits this description, we will ACCEPT this packet and stop further processing of rules in this chain (INPUT for this example). Let's look at some of the matching parameters.  Again, there are long and short version of each of these.
-p (--protocol) -This parameter matches the protocol of the packet.  It can be one of tcp, udp, icmp, or all, or any protocol name listed in /etc/protocols or you can simply use the protocol number.  A complete list of protocol numbers can be found at http://www.iana.org/assignments/protocol-numbers.  A "!" argument before the protocol inverts the test.  Be very careful using the inverse logic.  It is easy to build a rule that matches the wrong traffic or does not match your intended traffic.
This example accepts any TCP packet
iptables -A INPUT -p tcp -j ACCEPT
This example accepts OSPF (protocol number 89)
iptables -A INPUT -p 89 -j ACCEPT
This example drops any traffic that is NOT UDP
iptables -A INPUT -p !udp -j DROP
--sport (--source-port) or --dport (--destination-port) - If your rule includes "-p tcp" or "-p udp", you can use these additional match parameters.  This can either be a service name or a port number. In other words, you can use "22" or "ssh".  You can match a range of ports by using the format port:port.
The following rules are exactly equivalent:
iptables -A INPUT -p tcp --dport ssh -j ACCEPT
iptables -A INPUT --protocol tcp --destination-port 22 -j ACCEPT
-s (--source) or -d (--destination) - This is parameter allows you to specify the source or destination IP address or subnet.  The address can be specified as a network name, a hostname (please note that specifying any name to be resolved with a remote query such as DNS is a really bad idea), a network IP address (with /mask), or a plain IP address. The mask can be specified as a dotted decimal netmask or by CIDR notation. \
-j (--jump) -This specifies the target of the rule; i.e., what to do if the packet matches it. The target can be the name of a user-created chain (this is a bit beyond the scope of this article), one of the special builtin targets which decide the fate of the packet immediately (such as "ACCEPT" or "DROP), or an extension (again, this is a bit beyond the scope of this article). If this option is omitted in a rule , then matching the rule will have no effect on the packet's fate, but the counters on the rule will be incremented.  (At the end of this article, I will show some examples of rules that will show you the packet counters.)
-i (--in-interface) or -o (--out-interface) -These parameters allow you to specify the name of an interface.  This allows you to create a match parameter that considers where a packet enters the router or where it will leave the router.
The above parameters can be used individually or in (almost) any combination.  It is important to note, however, that in order for a packet to match a rule, it must match EXACTLY and COMPLETELY the set of parameters you specify.  Consider the following rule:
iptables -A INPUT -p tcp --dport ssh -s 192.168.0.1 -j ACCEPT
With this rule, if the router is processing a TCP packet with destination port 22 (ssh) and source IP of 192.168.0.2, it will NOT match this rule.   This is because it does not match exactly.  If we leave off the "-s 192.168.0.1" portion of the rule, then the above packet would match. Now that we are a bit more familiar with the iptables command line, let's do a quick check of our understanding.  One solution to the scenario below is posted further down.  Don't look until you've had a chance to try it yourself.
Write an iptables command (or commands) that will permit a PC at 192.168.0.1 to telnet (TCP port 23) to a Linux box that is behind our router at IP 192.168.10.1.  That PC should be the ONLY device that is allowed to telnet to the Linux box.  You are writing this rule on the router.
**********Don't look below here until you are ready to see my implementation example. *********** This is just one possible implementation.  One thing about the iptables firewall platform is that it is very flexible.  I'll write my implementation in 2 rules:
iptables -A FORWARD -p tcp --dport 23 -s 192.168.0.1 -d 192.168.10.1 -j ACCEPT iptables -A FORWARD -p tcp --dport 23 -d 192.168.10.1 -j DROP
Did you get your implementation correct?  I hope so.  Either way, this example brings us to the final point I want to bring out in this article.  That is the idea that the order of your rules is very important.  When a packet is processed against the FORWARD chain, the packet is compared to the first rule and, if it matches (remember it has to match exactly and completely), then the action or target (the "-j" parameter) will be taken for that packet.  Some targets, when called, determine the "final fate" of a packet.  For example, if we use target ACCEPT, then there is no need to continue comparing this packet against other rules, as we have already said it is to be accepted.  Therefore, in the example above, the second rule would never be seen by the traffic which our policy stated is wanted, since it would be accepted by the first rule.  That's why those 2 rules are able to fully implement the policy we stated. The targets ACCEPT and DROP both determine the "final fate" of a packet.  If a packet is processed through the chain and does not match ANY rules, then the default policy target of the chain will determine the final fate of a packet. The following command will show you a list of your current iptables rules, along with the default policies for the built-in chains:
iptables -L
Adding the "v" parameter includes packet and byte counters:
iptables -vL OR iptables -Lv
If you add the name of a chain, you will see output only for the specified chain:
iptables -vL INPUT
I hope you find this article helpful.  I will be writing more articles about iptables in the near future, so please leave comments letting me know about your opinions.

Leave a Reply

You must be logged in to post a comment.