Basic concepts

iptables is a user-space application program that allows a system administrator to configure the tables provided by the Linux kernel firewall (implemented as different Netfilter modules) and the chains and rules it stores. Different kernel modules and programs are currently used for different protocols; iptables applies to IPv4, ip6tables to IPv6, arptables to ARP, and ebtables to Ethernet frames.

The code for filtering IPv4 packets is already built into the kernel and is organized into a collection of tables.
The tables are made up of a set of predefined chains, and the chains contain rules which are traversed in order.
Each rule consists of a predicate of potential matches and a corresponding action (called a target) which is executed if the predicate is true.
iptables is the user utility which allows you to work with these chains/rules.

Tables

iptables contains five tables:
1. raw is used only for configuring packets so that they are exempt from connection tracking.
2. filter is the default table, and is where all the actions typically associated with a firewall take place.
3. nat is used for network address translation (e.g. port forwarding).
4. mangle is used for specialized packet alterations.
5. security is used for Mandatory Access Control networking rules (e.g. SELinux – see this article for more details).
In most common use cases you will only use two of these: filter and nat. The following chart depicts a simplified network packet flow through iptables:

|                                  XXXXXXXXXXXXXXXXXX
|                                  XXX   Network  XXX
|                                  XXXXXXXXXXXXXXXXXX
|                                          +
|                                          |
|                                          v
|    +-------------+              +------------------+
|    |table: filter| <---+        | table: nat       |
|    |chain: INPUT |     |        | chain: PREROUTING|
|    +-----+-------+     |        +--------+---------+
|          |             |                 |
|          v             |                 v
|    [local process]     |           ****************          +--------------+
|          |             +---------+ Routing decision +------> |table: filter |
|          v                         ****************          |chain: FORWARD|
|   ****************                                           +------+-------+
|   Routing decision                                                  |
|   ****************                                                  |
|          |                                                          |
|          v                        ****************                  |
|   +-------------+       +------>  Routing decision  <---------------+
|   |table: nat   |       |         ****************
|   |chain: OUTPUT|       |               +
|   +-----+-------+       |               |
|         |               |               v
|         v               |      +-------------------+
|   +--------------+      |      | table: nat        |
|   |table: filter | +----+      | chain: POSTROUTING|
|   |chain: OUTPUT |             +--------+----------+
|   +--------------+                      |
|                                         v
|                                  XXXXXXXXXXXXXXXXXX
|                                  XXX  Network   XXX
|                                  XXXXXXXXXXXXXXXXXX

Chains

Tables consist of chains, which are lists of rules which are followed in order. The default table, filter, contains three built-in chains: INPUT, OUTPUT and FORWARD which are activated at different points of the packet filtering process. The nat table includes PREROUTING, POSTROUTING, and OUTPUT chains.

By default, none of the chains contain any rules. It is up to you to append rules to the chains that you want to use. Chains do have a default policy, which is generally set to ACCEPT, but can be reset to DROP, if you want to be sure that nothing slips through your ruleset. The default policy always applies at the end of a chain only. Hence, the packet has to pass through all existing rules in the chain before the default policy is applied.

Rules

Packet filtering is based on rules, which are specified by multiple matches (conditions the packet must satisfy so that the rule can be applied), and one target (action taken when the packet matches all conditions). The typical things a rule might match on are what interface the packet came in on (e.g eth0 or eth1), what type of packet it is (ICMP, TCP, or UDP), or the destination port of the packet.

Targets are specified using the -j or --jump option. Targets can be either user-defined chains (i.e. if these conditions are matched, jump to the following user-defined chain and continue processing there), one of the special built-in targets, or a target extension. Built-in targets are ACCEPT, DROP, QUEUE and RETURN, target extensions are, for example, REJECT and LOG.

Traversing Chains

A network packet received on any interface traverses the traffic control chains of tables in the order shown in the flow chart:

.

The first routing decision involves deciding if the final destination of the packet is the local machine (in which case the packet traverses through the INPUT chains) or elsewhere (in which case the packet traverses through the FORWARD chains). Subsequent routing decisions involve deciding what interface to assign to an outgoing packet. At each chain in the path, every rule in that chain is evaluated in order and whenever a rule matches, the corresponding target/jump action is executed. The 3 most commonly used targets are ACCEPT, DROP, and jump to a user-defined chain. While built-in chains can have default policies, user-defined chains can not. If every rule in a chain that you jumped fails to provide a complete match, the packet is dropped back into the calling chain as illustrated here:

iptables_Routing

If at any time a complete match is achieved for a rule with a DROP target, the packet is dropped and no further processing is done. If a packet is ACCEPTed within a chain, it will be ACCEPTed in all superset chains also and it will not traverse any of the superset chains any further. However, be aware that the packet will continue to traverse all other chains in other tables in the normal fashion.

Configuration and usage

Showing the current rules

iptables -nvL [chain]
iptables -nvL --line-numbers [chain]
iptables -S [chain]
iptables-save

Resetting rules

iptables -F [chain]
iptables -X [chain]
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

-F - like DELETE FROM table_name; in SQL
-X - like DROP TABLE table_name; in SQL
-P, --policy chain target - Only built-in (non-user-defined) chains can have policies, and neither built-in nor user-defined chains can be policy targets.

  • chain policy - the default target
    If the end of a built-in chain is reached or a rule in a built-in chain with target RETURN is matched, the target specified by the chain policy determines the fate of the packet.(see Chains for more information)

Editing rules

-A, --append chain rule-specification
-D, --delete chain rule-specification
-D, --delete chain rulenum
-I, --insert chain [rulenum] rule-specification
-R, --replace chain rulenum rule-specification

rule-specification = [matches...] [target]
match = -m matchname [per-match-options]
target = -j targetname [per-target-options]
  • some useful options
[!] -p, --protocol protocol
[!] -s, --source address[/mask][,...]
[!] -d, --destination address[/mask][,...]
-j, --jump target
[!] --source-port,--sport port[:port]
[!] --destination-port,--dport port[:port]
[!] --source-ports,--sports port[,port|,port:port]...
[!] --destination-ports,--dports port[,port|,port:port]...
[!] --ports port[,port|,port:port]...

Example 1 - append, insert, replace

  1. Reject packets from anywhere to tcp port 17500
iptables -A INPUT -p tcp --dport 17500 -j REJECT --reject-with icmp-port-unreachable
  1. Only allow 10.0.0.85
    use -R to replace our old rule:
iptables -R INPUT 1 -p tcp --dport 17500 ! -s 10.0.0.85 -j REJECT --reject-with icmp-port-unreachable
  1. More scalable
iptables -I INPUT -p tcp --dport 17500 -s 10.0.0.85 -j ACCEPT -m comment --comment "Friendly Dropbox"
iptables -R INPUT 2 -p tcp --dport 17500 -j REJECT --reject-with icmp-port-unreachable
1        0     0 ACCEPT     tcp  --  *      *       10.0.0.85            0.0.0.0/0            tcp dpt:17500 /* Friendly Dropbox */
2        0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:17500 reject-with icmp-port-unreachable

Example 2 - randomly dropping 10% of incoming packets

iptables -A INPUT -p tcp -s 10.105.44.6 -j DROP --match statistic --mode random --probability 0.1

See iptables-extensions for more information.

References

iptables(ArchWiki)
iptables(Wikipedia)