Linux IPTables - 2020
IPTables is a rule based firewall and it is pre-installed on most of Linux operating system. By default it runs without any rules as we can see from the following output:
Let's check the status of IPTables by listing (-L) the rules with additional verbose (-v) and numeric (-n) flags:
$ sudo iptables -L -v -n Chain INPUT (policy ACCEPT 59 packets, 3940 bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 35 packets, 4100 bytes) pkts bytes target prot opt in out source destination
As we can see, all three chains are set to default ACCEPT policy. There are currently no rules for any of the chains.
In the output, Chain is nothing but a set of rules. Each rule defines what to do with the packet if it matches with that packet. When the packet is matched, it is given a target.
Chains are:
- INPUT: default chain originating to system.
- OUTPUT: default chain generating from system.
- FORWARD: default chain packets are send through another interface.
A target can be another chain to match with or one of the following special values:
- ACCEPT: means the packet will be allowed to pass through.
- DROP: means that packet will not be allowed to pass through.
- RETURN: means to skip the current chain and go back to the next rule from the chain it was called in.
IPTables main files are:
- /etc/init.d/iptables: init script to start|stop|restart and save rulesets.
- /etc/sysconfig/iptables: where Rulesets are saved.
- /sbin/iptables: binary.
We can define a rule simply appending it to the list (chain). Here's the IPTables command formatted with regular options. We don't have to specify all of them.
$ sudo iptables -A -i <interface> -p <protocol(tcp/udp)> \ -s <source> --dport <port no.> -j <target>
Here -A stands for append. The chain refers to the chain we want to append our rules. The interface is the network interface on which we want to filter the traffic. The protocol refers to the networking protocol of packets we want to filter. We can also specify the port on which we want to filter the traffic.
$ sudo iptables -A INPUT -i lo -j ACCEPT
Here -A option is used to append the rule to the INPUT chain, ACCEPT (-j target) all connections lo (loopback) interface (-i input name).
Output:
$ sudo iptables -L -v -n Chain INPUT (policy ACCEPT 183 packets, 11717 bytes) pkts bytes target prot opt in out source destination 4 360 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 116 packets, 21607 bytes) pkts bytes target prot opt in out source destination
All out bound traffic from the lo:
$ sudo iptables -A OUTPUT -o lo -j ACCEPT
We want our HTTP (port 80), https (port 443), ssh (port 22) connections from outside continue to work. Enter the following commands to enable them. Note that we have specified protocol with -p option and the corresponding port for each protocol with –dport (destination port) option:
$ sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT $ sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT $ sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
Output:
$ sudo iptables -L -v -n Chain INPUT (policy ACCEPT 1 packets, 48 bytes) pkts bytes target prot opt in out source destination 24 2176 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 87 6276 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 13 packets, 1588 bytes) pkts bytes target prot opt in out source destination
If we want to accept or reject packets based on the source IP address or the range of IP addresses we can specify it with -s (source) option.
For example to accept packets from address 3.89.183.225:
$ sudo iptables -A INPUT -s 3.89.183.225 -j ACCEPT
We can drop packets from an IP address with option DROP:
$ sudo iptables -A INPUT -s 4.100.183.123 -j DROP
If we want to drop packets from a range of IP addresses we have to use the iprange module with -m (match) option and specify the IP address range with –src-range:
$ sudo iptables -A INPUT -m iprange --src-range 192.168.1.100-192.168.1.101 -j DROP
Output:
$ sudo iptables -L -v -n Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 44 3976 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 152 11699 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 0 0 ACCEPT all -- * * 3.89.183.225 0.0.0.0/0 0 0 DROP all -- * * 4.100.183.123 0.0.0.0/0 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 source IP range 192.168.1.100-192.168.1.101 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 7 packets, 736 bytes) pkts bytes target prot opt in out source destination
It is important to DROP all other traffic after defining the rules as it prevents unauthorized access to a server from other open ports:
Output:
$ sudo iptables -L -v -n Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 52 4696 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 173 13019 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 0 0 ACCEPT all -- * * 3.89.183.225 0.0.0.0/0 0 0 DROP all -- * * 4.100.183.123 0.0.0.0/0 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 source IP range 192.168.1.100-192.168.1.101 1 40 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 8 packets, 856 bytes) pkts bytes target prot opt in out source destination
We can see the command drops all incoming traffic other than the ports mentioned in the above commands.
Before delete any rule, let's list all the rules with numbers with the help of argument --line-numbers:
$ sudo iptables -n -L -v --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 60 5376 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 2 221 16095 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 3 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 5 0 0 ACCEPT all -- * * 3.89.183.225 0.0.0.0/0 6 0 0 DROP all -- * * 4.100.183.123 0.0.0.0/0 7 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 source IP range 192.168.1.100-192.168.1.101 8 44 2490 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 58 packets, 8300 bytes) num pkts bytes target prot opt in out source destination
Let's say if we want to delete rule no 5 and 6 from INPUT chain. Use the following command with -D:
$ sudo iptables -D INPUT 6 $ sudo iptables -D INPUT 5
Output:
$ sudo iptables -n -L -v --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 84 7416 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 2 266 19031 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 3 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 5 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 source IP range 192.168.1.100-192.168.1.101 6 145 12759 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 32 packets, 2908 bytes) num pkts bytes target prot opt in out source destination
We've using the -A option to append the new rule to the end of a chain. If we want to put it somewhere else in the chain, we can use the -I option which allows us to specify the position of the new rule.
To insert a rule to INPUT chain in between 5 and 6 ruleset, we can use -I (insert):
$ sudo iptables -I INPUT 6 -s 10.0.10.233 -j DROP
Output:
$ sudo iptables -n -L -v --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 114 9878 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 2 412 28915 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 3 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 5 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 source IP range 192.168.1.100-192.168.1.101 6 0 0 DROP all -- * * 10.0.10.233 0.0.0.0/0 7 312 28304 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 44 packets, 4062 bytes) num pkts bytes target prot opt in out source destination
The following flush command will remove all the rules from tables. Take rulesets backup before executing above command:
$ sudo iptables -F
Output:
$ sudo iptables -n -L -v Chain INPUT (policy ACCEPT 20 packets, 1909 bytes) num pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 18 packets, 1876 bytes) num pkts bytes target prot opt in out source destination
Let's start from this:
$ sudo iptables -L -v Chain INPUT (policy ACCEPT 29 packets, 2558 bytes) pkts bytes target prot opt in out source destination 12 1080 ACCEPT all -- lo any anywhere anywhere Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 23 packets, 3261 bytes) pkts bytes target prot opt in out source destination 4 360 ACCEPT all -- any lo anywhere anywhere
As network traffic generally needs to be two-way—incoming and outgoing—to work properly, it is typical to create a firewall rule that allows established and related incoming traffic, so that the server will allow return traffic to outgoing connections initiated by the server itself. The following command will allow that:
$ sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
What we really needed here is a way to tell IPTables to not touch packets that are part of an existing connection. Fortunately, IPTables is a stateful firewall, and it provides a connection tracking module named conntrack for this purpose. Connections tracked by this module will be in one of the following states:
- NEW: This state represents the very first packet of a connection.
- ESTABLISHED: This state is used for packets that are part of an existing connection. For a connection to be in this state, it should have received a reply from the other host.
- RELATED: This state is used for connections that are related to another ESTABLISHED connection. An example of this is a FTP data connection — they're related to the already established control connection.
- INVALID: Packets can be marked INVALID if they are not associated with an existing connection and aren't appropriate for opening a new connection, if they cannot be identified, or if they aren't routable among other reasons.
- UNTRACKED: Packets can be marked as UNTRACKED if they've been targeted in a raw table chain to bypass tracking.
- SNAT: A virtual state set when the source address has been altered by NAT operations. This is used by the connection tracking system so that it knows to change the source addresses back in reply packets.
- DNAT: A virtual state set when the destination address has been altered by NAT operations. This is used by the connection tracking system so that it knows to change the destination address back when routing reply packets.
Let's see what's been added to the table:
$ sudo iptables -L -v Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 20 1800 ACCEPT all -- lo any anywhere anywhere 11 784 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 6 packets, 832 bytes) pkts bytes target prot opt in out source destination 12 1080 ACCEPT all -- any lo anywhere anywhere
The --ctstate switch sets the states. On some older kernels, this module is named state and the switch is named --state instead of --ctstate.
Note that we usually put the new rule at the very top. (If this isn't the first rule, we may want to use -I to place it at the top.)
Let's put it at the top as a practice what we've learned so far. We can insert the same rule using -I and DROP INPUT 3:
$ sudo iptables -I INPUT 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT $ sudo iptables -D INPUT 3 $ sudo iptables -L -v --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 137 10414 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED 2 36 3240 ACCEPT all -- lo any anywhere anywhere Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 9 packets, 1140 bytes) num pkts bytes target prot opt in out source destination 1 36 3256 ACCEPT all -- any lo anywhere anywhere
We may want to allow outgoing traffic of all established connections, which are typically the response to legitimate incoming connections. This command will allow that:
$ sudo iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT $ sudo iptables -L -v --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 254 19883 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED 2 39 3498 ACCEPT all -- lo any anywhere anywhere Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 44 3976 ACCEPT all -- any lo anywhere anywhere 2 4 664 ACCEPT all -- any any anywhere anywhere ctstate ESTABLISHED
Some network traffic packets get marked as INVALID. Sometimes it can be useful to log this type of packet but often it is fine to drop them:
$ sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP $ sudo iptables -L -v --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 337 27057 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED 2 42 3756 ACCEPT all -- lo any anywhere anywhere 3 0 0 DROP all -- any any anywhere anywhere ctstate INVALID Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 52 4696 ACCEPT all -- any lo anywhere anywhere 2 86 14284 ACCEPT all -- any any anywhere anywhere ctstate ESTABLISHED
If we want to reject the connection instead, which will respond to the connection request with a "connection refused" error:
$ sudo iptables -A INPUT -s 54.214.74.210 -j REJECT $ sudo iptables -L -v --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 337 27057 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED 2 42 3756 ACCEPT all -- lo any anywhere anywhere 3 0 0 DROP all -- any any anywhere anywhere ctstate INVALID 4 0 0 REJECT all -- any any ec2-54-214-74-210.us-west-2.compute.amazonaws.com anywhere reject-with icmp-port-unreachable Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 52 4696 ACCEPT all -- any lo anywhere anywhere 2 86 14284 ACCEPT all -- any any anywhere anywhere ctstate ESTABLISHED
There are five predefined chains:
- PREROUTING: Packets will enter this chain before a routing decision is made.
- INPUT: Packet is going to be locally delivered. It does not have anything to do with processes having an opened socket; local delivery is controlled by the "local-delivery" routing table: ip route show table local.
- FORWARD: All packets that have been routed and were not for local delivery will traverse this chain.
- OUTPUT: Packets sent from the machine itself will be visiting this chain.
- POSTROUTING: Routing decision has been made. Packets enter this chain just before handing them off to the hardware
Let's take a look at the different tables that iptables provides. These represent distinct sets of rules, organized by area of concern, for evaluating packets.
Filter Table
The filter table is one of the most widely used tables in iptables. The filter table is used to make decisions about whether to let a packet continue to its intended destination or to deny its request. In firewall parlance, this is known as "filtering" packets. This table provides the bulk of functionality that people think of when discussing firewalls.
NAT Table
The nat table is used to implement network address translation rules. As packets enter the network stack, rules in this table will determine whether and how to modify the packet's source or destination addresses in order to impact the way that the packet and any response traffic are routed. This is often used to route packets to networks when direct access is not possible.
Mangle Table
The mangle table is used to alter the IP headers of the packet in various ways. For instance, you can adjust the TTL (Time to Live) value of a packet, either lengthening or shortening the number of valid network hops the packet can sustain. Other IP headers can be altered in similar ways.
This table can also place an internal kernel "mark" on the packet for further processing in other tables and by other networking tools. This mark does not touch the actual packet, but adds the mark to the kernel's representation of the packet.
Raw Table
The iptables firewall is stateful, meaning that packets are evaluated in regards to their relation to previous packets. The connection tracking features built on top of the netfilter framework allow iptables to view packets as part of an ongoing connection or session instead of as a stream of discrete, unrelated packets. The connection tracking logic is usually applied very soon after the packet hits the network interface.
The raw table has a very narrowly defined function. Its only purpose is to provide a mechanism for marking packets in order to opt-out of connection tracking.
Security Table
The security table is used to set internal SELinux security context marks on packets, which will affect how SELinux or other systems that can interpret SELinux security contexts handle the packets. These marks can be applied on a per-packet or per-connection basis.
Picture source: iptables: Packet Processing
Linux - system, cmds & shell
- Linux Tips - links, vmstats, rsync
- Linux Tips 2 - ctrl a, curl r, tail -f, umask
- Linux - bash I
- Linux - bash II
- Linux - Uncompressing 7z file
- Linux - sed I (substitution: sed 's///', sed -i)
- Linux - sed II (file spacing, numbering, text conversion and substitution)
- Linux - sed III (selective printing of certain lines, selective definition of certain lines)
- Linux - 7 File types : Regular, Directory, Block file, Character device file, Pipe file, Symbolic link file, and Socket file
- Linux shell programming - introduction
- Linux shell programming - variables and functions (readonly, unset, and functions)
- Linux shell programming - special shell variables
- Linux shell programming : arrays - three different ways of declaring arrays & looping with $*/$@
- Linux shell programming : operations on array
- Linux shell programming : variables & commands substitution
- Linux shell programming : metacharacters & quotes
- Linux shell programming : input/output redirection & here document
- Linux shell programming : loop control - for, while, break, and break n
- Linux shell programming : string
- Linux shell programming : for-loop
- Linux shell programming : if/elif/else/fi
- Linux shell programming : Test
- Managing User Account - useradd, usermod, and userdel
- Linux Secure Shell (SSH) I : key generation, private key and public key
- Linux Secure Shell (SSH) II : ssh-agent & scp
- Linux Secure Shell (SSH) III : SSH Tunnel as Proxy - Dynamic Port Forwarding (SOCKS Proxy)
- Linux Secure Shell (SSH) IV : Local port forwarding (outgoing ssh tunnel)
- Linux Secure Shell (SSH) V : Reverse SSH Tunnel (remote port forwarding / incoming ssh tunnel) /)
- Linux Processes and Signals
- Linux Drivers 1
- tcpdump
- Linux Debugging using gdb
- Embedded Systems Programming I - Introduction
- Embedded Systems Programming II - gcc ARM Toolchain and Simple Code on Ubuntu/Fedora
- LXC (Linux Container) Install and Run
- Linux IPTables
- Hadoop - 1. Setting up on Ubuntu for Single-Node Cluster
- Hadoop - 2. Runing on Ubuntu for Single-Node Cluster
- ownCloud 7 install
- Ubuntu 14.04 guest on Mac OSX host using VirtualBox I
- Ubuntu 14.04 guest on Mac OSX host using VirtualBox II
- Windows 8 guest on Mac OSX host using VirtualBox I
- Ubuntu Package Management System (apt-get vs dpkg)
- RPM Packaging
- How to Make a Self-Signed SSL Certificate
- Linux Q & A
- DevOps / Sys Admin questions
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization