Skip to content

IPtables

Iptables places rules into predefined chains (INPUT, OUTPUT and FORWARD) that are checked against any network traffic (IP packets) relevant to those chains and a decision is made about what to do with each packet based upon the outcome of those rules, i.e. accepting or dropping the packet. These actions are referred to as targets, of which the two most common predefined targets are DROP to drop a packet or ACCEPT to accept a packe

These are 3 predefined chains in the filter table to which we can add rules for processing IP packets passing through those chains. These chains are:

1
2
3
4
  INPUT - All packets destined for the host computer.
  OUTPUT - All packets originating from the host computer.
  FORWARD - All packets neither destined for nor originating from the host computer, but passing through (routed by) the host computer. 
            This chain is used if you are using your computer as a router.

Rules are added in a list to each chain. A packet is checked against each rule in turn, starting at the top, and if it matches that rule, then an action is taken such as accepting (ACCEPT) or dropping (DROP) the packet. Once a rule has been matched and an action taken, then the packet is processed according to the outcome of that rule and isn't processed by further rules in the chain. If a packet passes down through all the rules in the chain and reaches the bottom without being matched against any rule, then the default action for that chain is taken. This is referred to as the default policy and may be set to either ACCEPT or DROP the packet.

The concept of default policies within chains raises two fundamental possibilities that we must first consider before we decide how we are going to organize our firewall.

1. We can set a default policy to DROP all packets and then add rules to specifically allow (ACCEPT) packets that may be from trusted IP addresses, or for certain ports on which we have services running such as bittorrent, FTP server, Web Server, Samba file server etc.

or alternatively,

2. We can set a default policy to ACCEPT all packets and then add rules to specifically block (DROP) packets that may be from specific nuisance IP addresses or ranges, or for certain ports on which we have private services or no services running.

Generally, option 1 above is used for the INPUT chain where we want to control what is allowed to access our machine and option 2 would be used for the OUTPUT chain where we generally trust the traffic that is leaving (originating from) our machine.

An iptables syntax quick reference**

Taking a look at what you have

iptables -L [chain] - Lists your current iptables configuration

iptables -L -t nat - for listing all the nat rules. they are not displayed by default.

Making modifications

iptables -A [chain] - Append a rule to a desired chain in the current configuration

iptables -D [chain] - Delete a rule from a desired chain in the current configuration

iptables -R [chain] - Replace an existing rule from a desired chain in the current configuration

iptables - I [chain] - (that's a capital I as in Insert) Insert a new rule into a desired chain of the current configuration

iptables -N [chain] - Create a new chain

iptables -X [chain] - Delete a chain

Getting rid of all rules and starting over

iptable -X - Delete all chains

iptables -F - Flush the table of all contents

Importing & Exporting

iptables-save > filename - exports the current iptables configuration to a flat file.

iptables-restore < filename - imports an iptables configuration from a flat file and overwrites the current configuration.

Writing a Simple Rule Set

IMPORTANT: At this point we are going to clear the default rule set. If you are connecting remotely to a server via SSH for this tutorial then there is a very real possibility that you could lock yourself out of your machine. You must set the default input policy to accept before flushing the current rules, and then add a rule at the start to explicitly allow yourself access to prevent against locking yourself out.

We will use an example based approach to examine the various iptables commands. In this first example, we will create a very simple set of rules to set up a Stateful Packet Inspection (SPI) firewall that will allow all outgoing connections but block all unwanted incoming connections:

1
2
3
4
5
6
7
8
9
# iptables -P INPUT ACCEPT
# iptables -F
# iptables -A INPUT -i lo -j ACCEPT
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# iptables -P INPUT DROP
# iptables -P FORWARD DROP
# iptables -P OUTPUT ACCEPT
# iptables -L -v

which should give the following output:

1
2
3
4
5
6
7
8
9
Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  lo     any     anywhere             anywhere
    0     0 ACCEPT     all  --  any    any     anywhere             anywhere            state RELATED,ESTABLISHED
    0     0 ACCEPT     tcp  --  any    any     anywhere             anywhere            tcp dpt:ssh
Chain FORWARD (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Now lets look at each of the 8 commands above in turn and understand exactly what we've just done:

iptables -P INPUT ACCEPT If connecting remotely we must first temporarily set the default policy on the INPUT chain to ACCEPT otherwise once we flush the current rules we will be locked out of our server.

iptables -F We used the -F switch to flush all existing rules so we start with a clean state from which to add new rules.

iptables -A INPUT -i lo -j ACCEPT Now it's time to start adding some rules. We use the -A switch to append (or add) a rule to a specific chain, the INPUT chain in this instance. Then we use the -i switch (for interface) to specify packets matching or destined for the lo (localhost, 127.0.0.1) interface and finally -j (jump) to the target action for packets matching the rule - in this case ACCEPT. So this rule will allow all incoming packets destined for the localhost interface to be accepted. This is generally required as many software applications expect to be able to communicate with the localhost adaptor.

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT This is the rule that does most of the work, and again we are adding (-A) it to the INPUT chain. Here we're using the -m switch to load a module (state). The state module is able to examine the state of a packet and determine if it is NEW, ESTABLISHED or RELATED. NEW refers to incoming packets that are new incoming connections that weren't initiated by the host system. ESTABLISHED and RELATED refers to incoming packets that are part of an already established connection or related to and already established connection.

iptables -A INPUT -p tcp --dport 22 -j ACCEPT Here we add a rule allowing SSH connections over tcp port 22. This is to prevent accidental lockouts when working on remote systems over an SSH connection. We will explain this rule in more detail later.

iptables -P INPUT DROP The -P switch sets the default policy on the specified chain. So now we can set the default policy on the INPUT chain to DROP. This means that if an incoming packet does not match one of the following rules it will be dropped. If we were connecting remotely via SSH and had not added the rule above, we would have just locked ourself out of the system at this point.

iptables -P FORWARD DROP Similarly, here we've set the default policy on the FORWARD chain to DROP as we're not using our computer as a router so there should not be any packets passing through our computer.

iptables -P OUTPUT ACCEPT and finally, we've set the default policy on the OUTPUT chain to ACCEPT as we want to allow all outgoing traffic (as we trust our users).

iptables -L -v Finally, we can list (-L) the rules we've just added to check they've been loaded correctly.

Finally, the last thing we need to do is save our rules so that next time we reboot our computer our rules are automatically reloaded:

1
 # /sbin/service iptables save

This executes the iptables init script, which runs /sbin/iptables-save and writes the current iptables configuration to /etc/sysconfig/iptables. Upon reboot, the iptables init script reapplies the rules saved in /etc/sysconfig/iptables by using the /sbin/iptables-restore command.

Common IPtables examples:

1. Delete all existing rules

1
2
3
4
    iptables -t nat -F
    iptables -t mangle -F
    iptables -F
    iptables -X

2. Set default chain policies

1
2
3
 iptables -P INPUT DROP
 iptables -P FORWARD DROP
 iptables -P OUTPUT DROP

3. Block a specific ip-address

1
2
 #BLOCK_THIS_IP="x.x.x.x"
 iptables -A INPUT -s "$BLOCK_THIS_IP" -j DROP

4. Allow ALL incoming SSH

1
2
 iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

5. Allow incoming SSH only from a sepcific network

1
2
 iptables -A INPUT -i eth0 -p tcp -s 192.168.200.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

6. Allow incoming HTTP

1
2
3
4
5
6
 iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT

 # Allow incoming HTTPS
 iptables -A INPUT -i eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

7. MultiPorts (Allow incoming SSH, HTTP, and HTTPS)

1
2
 iptables -A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp -m multiport --sports 22,80,443 -m state --state ESTABLISHED -j ACCEPT

8. Allow outgoing SSH

1
2
 iptables -A OUTPUT -o eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

9. Allow outgoing SSH only to a specific network

1
2
 iptables -A OUTPUT -o eth0 -p tcp -d 192.168.101.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT

10. Allow outgoing HTTPS

1
2
 iptables -A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A INPUT -i eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT

11. Load balance incoming HTTPS traffic

1
2
3
 iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 0 -j DNAT --to-destination 192.168.1.101:443
 iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 1 -j DNAT --to-destination 192.168.1.102:443
 iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 2 -j DNAT --to-destination 192.168.1.103:443

12. Ping from inside to outside

1
2
 iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
 iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT

13. Ping from outside to inside

1
2
 iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
 iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT

14. Allow loopback access

1
2
 iptables -A INPUT -i lo -j ACCEPT
 iptables -A OUTPUT -o lo -j ACCEPT

15. Allow packets from internal network to reach external network.

1
2
3
 # if eth1 is connected to external network (internet)
 # if eth0 is connected to internal network (192.168.1.x)
 iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

16. Allow outbound DNS

1
2
 iptables -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT
 iptables -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT

17. Allow NIS Connections

1
2
3
4
5
6
7
 rpcinfo -p | grep ypbind ; This port is 853 and 850
 iptables -A INPUT -p tcp --dport 111 -j ACCEPT
 iptables -A INPUT -p udp --dport 111 -j ACCEPT
 iptables -A INPUT -p tcp --dport 853 -j ACCEPT
 iptables -A INPUT -p udp --dport 853 -j ACCEPT
 iptables -A INPUT -p tcp --dport 850 -j ACCEPT
 iptables -A INPUT -p udp --dport 850 -j ACCEPT

18. Allow rsync from a specific network

1
2
 iptables -A INPUT -i eth0 -p tcp -s 192.168.101.0/24 --dport 873 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 873 -m state --state ESTABLISHED -j ACCEPT

19. Allow MySQL connection only from a specific network

1
2
 iptables -A INPUT -i eth0 -p tcp -s 192.168.200.0/24 --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT

20. Allow Sendmail or Postfix

1
2
 iptables -A INPUT -i eth0 -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT

21. Allow IMAP and IMAPS

1
2
3
4
5
 iptables -A INPUT -i eth0 -p tcp --dport 143 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 143 -m state --state ESTABLISHED -j ACCEPT

 iptables -A INPUT -i eth0 -p tcp --dport 993 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 993 -m state --state ESTABLISHED -j ACCEPT

22. Allow POP3 and POP3S

1
2
3
4
5
 iptables -A INPUT -i eth0 -p tcp --dport 110 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 110 -m state --state ESTABLISHED -j ACCEPT

 iptables -A INPUT -i eth0 -p tcp --dport 995 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 995 -m state --state ESTABLISHED -j ACCEPT

23. Prevent DoS attack

1
 iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT

24. Port forwarding 422 to 22

1
2
3
 iptables -t nat -A PREROUTING -p tcp -d 192.168.102.37 --dport 422 -j DNAT --to 192.168.102.37:22
 iptables -A INPUT -i eth0 -p tcp --dport 422 -m state --state NEW,ESTABLISHED -j ACCEPT
 iptables -A OUTPUT -o eth0 -p tcp --sport 422 -m state --state ESTABLISHED -j ACCEPT

25. Log dropped packets

1
2
3
4
 iptables -N LOGGING
 iptables -A INPUT -j LOGGING
 iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: " --log-level 7
 iptables -A LOGGING -j DROP

Sample /etc/sysconfig/iptables file for nating (port forwarding) port 80 to 7101 and 443 to 7102

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 *nat
 :PREROUTING ACCEPT [0:0]
 :POSTROUTING ACCEPT [0:0]
 :OUTPUT ACCEPT [0:0] 
 -A OUTPUT -d 10.192.14.181 -p tcp --dport 80 -j REDIRECT --to-ports 7101
 -A OUTPUT -d 10.192.14.181 -p tcp --dport 443 -j REDIRECT --to-ports 7102
 -A OUTPUT -d localhost -p tcp --dport 80 -j REDIRECT --to-ports 7101
 -A OUTPUT -d localhost -p tcp --dport 443 -j REDIRECT --to-ports 7102
 -A PREROUTING -d 10.192.14.181 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 7101
 -A PREROUTING -d 10.192.14.181 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 7102
 COMMIT

Saving Iptables Firewall Rules Permanently

This article explains several ways in which iptables rules can be stored permanently on Linux.

iptables-save

The actual iptables rules are created and customized on the command line with the command iptables for IPv4 and ip6tables for IPv6.

These can be saved in a file with the command iptables-save for IPv4.

1
2
Debian/Ubuntu: iptables-save > /etc/iptables/rules.v4
RHEL/CentOS: iptables-save > /etc/sysconfig/iptables

These files can be loaded again with the command iptables-restore for IPv4.

1
2
Debian/Ubuntu: iptables-restore < /etc/iptables/rules.v4
RHEL/CentOS: iptables-restore < /etc/sysconfig/iptables

If you would also like to use IPv6 rules, these can be stored in a separate file.

1
2
Debian/Ubuntu: ip6tables-save > /etc/iptables/rules.v6
RHEL/CentOS: ip6tables-save > /etc/sysconfig/ip6tables

The automatic loading of the configured iptables rules can be done by using the following methods:

iptables-persistent for Debian/Ubuntu

Since [Ubuntu 10.04 LTS][1] (Lucid) and [Debian 6.0][2] (Squeeze) there is a package with the name "iptables-persistent" which takes over the automatic loading of the saved iptables rules. To do this, the rules must be saved in the file /etc/iptables/rules.v4 for IPv4 and /etc/iptables/rules.v6 for IPv6.

For use, the package must simply be installed.

1
apt-get install iptables-persistent

If the installation fails, please check whether systemd has already had failures before the installation of iptables-persisent. Those systemd errors can cause the iptables-persistent installation to fail.[[1]][3]

Older iptables-persistent versions (e.g. like those in Debian Squeeze) still do not support IPv6 rules. There is only one file with the name /etc/iptables/rules for IPv4. Check the Init-Script for which files are loaded in your iptables-persistent version.

Note

Please check that your rules are loaded as desired following the first reboot after configuration.

iptables Service for RedHat Enterprise Linux (RHEL) and CentOS

RHEL/CentOS also offer simple methods to permanently save iptables rules for IPv4 and IPv6. There is a service called "iptables". This must be enabled.

1
2
3
# chkconfig --list | grep iptables
  iptables          0:off   1:off   2:on    3:on    4:on    5:on    6:off
# chkconfig iptables on

The rules are saved in the file /etc/sysconfig/iptables for IPv4 and in the file /etc/sysconfig/ip6tables for IPv6. You may also use the init script in order to save the current rules.

1
# service iptables save

Note

Please check that your rules are loaded as desired following the first reboot after configuration.