All information pulled out from this link for personal notes and study.
How iptables work
The iptables work mainly in Internet layer and Transport layer. However, iptables can also work in Application layer, but it is not intended to do so.
Tables
Allows packet processing in specific ways. There are four types of tables:
- The filter table: Default and most popular table. It is used to decide whether a packet should be allowed or denied to reach its destination.
- The mangle table: Allows you to change packet headers.
- The nat table: Allows you to route packets to different hosts on a NAT by changing source and destination address of a packet.
- The raw table: Allows you to work with packets before the kernel starts tracking its state.
- The security table: Used by SELinux to implement SELinux policies.
Chains
Each table contains few chains which are attached to them. They allow you to inspect and filter traffic at various points. This is the list of chains iptables use:
- PREROUTING chain: Applies rules for packets that just arrived on the network interface. Supports nat, mangle, and raw tables.
- INPUT chain: Applies rules for packets just before they are given to a local process. Supports mangle and filter tables.
- OUTPUT chain: Applies rules for packets right after they are produced by a process. Supports raw, mangle, nat, and filter tables.
- FORWARD chain: Applies rules for packets that are routed through the current host. Supports mangle and filter tables.
- POSTROUTING chain: Applies rules for packets as they leave the network interface. Supports nat and mangle tables.

Targets
They decide whether packet is allowed or rejected. Commonly used terminating targets are:
- ACCEPT: iptables accepts the packet
- DROP: iptables drops the packet. For client, he cannot tell if this host exists.
- REJECT: iptables rejects the packet. For TCP, it sends “connection reset” packet, and for UDP or ICMP, it sends “destination host unreachable”
Setting default policies
Default policy governs how iptables handles packets that pass all rules. Imagine a system is candy factory and all bad candies are on a production line. If set to DROP, workers will pick up only good candies, and bad ones are going to a trash bin. Similarly, with policy set to DROP, a packet comes to a system and is waiting for firewall rules. Packet that matches a rule gets picked up from production line and the rest of them are dropped. Here is how to set this:
# iptables --policy INPUT DROP
# iptables --policy OUTPUT DROP
# iptables --policy FORWARD DROP
Or, we can set iptables to ACCEPT all packets that passed rules. For example, ACCEPT all packets except those with specified IP address. If one is found, rule will pick it up and it won’t find its way to the last rule, which ACCEPTs them. Lets use our candy factory analogy again. This time, all candies on production line are good. However, if bad candy is passing by, a worker will pick it up and throw out of the production. Good candies will make to the packaging and will be distributed. Here is how to set ACCEPT default policy:
# iptables --policy INPUT ACCEPT
# iptables --policy OUTPUT ACCEPT
# iptables --policy FORWARD ACCEPT
If set to REJECT, packets that find their way to the end of a list will be rejected. However, this rule sends back error message to a client. In this way, client will know firewall blocked his packet. In contrary, when set to DROP, firewall does not send any feedback to the client. It simply drops the packet and moves on.
Allowing or blocking connections
Important flags:
-t | Specify the table where rule will apply to |
-A | Apped this rule (INPUT) to the list of existing rules in INPUT chain |
-s | Set source IP that you want to block |
-j | iptables will reject traffic with REJECT target (sends packet back to the client) If you want iptables to not respond, use DROP target. |
-d | Block output traffic to this IP address |
-L | List all rules within the chain |
-n | Don’t resolve names |
-F | Flush all rules within the chain |
-R | Replace single rule (modify it) |
Blocking IP address
If you want to block an incoming IP address, you would block all incoming packets coming from that IP address. To add this rule to the INPUT chain of the filter table, use this:
# iptables -t filter -A INPUT -s 195.94.101.10 -j REJECT
Block range of IP addresses with CIDR notation, for example:
# iptables -t filter -A INPUT -s 195.94.101.10/24 -j REJECT
Or, if you want to block output traffic to that IP address, use OUTPUT chain, and –d to specify destination:
# iptables -t filter -A OUTPUT -d 195.94.101.10/24 -j DROP
Listing rules
If you want to see all rules (-L), from filter table (-t filter), and numbered (–line-number), and disable DNS lookup (-n) use the following command:
# iptables -L -n -t filter
Deleting rules
To remove a rule, replace -A with -D:
# iptables -t filter -D INPUT -s 195.94.101.10 -j REJECT
or delete rule by its rule number:
# iptables -t filter -D INPUT 3
When you remove a rule from a chain, in this case INPUT chain, first delete ones with highest numbers (those at the end of list). For example:
# iptables -t filter -D INPUT 20
# iptables -t filter -D INPUT 9
# iptables -t filter -D INPUT 6
To remove all rules from a particular chain, use this:
# iptables -t filter -F INPUT
Inserting and replacing rules
Since the chain apply rules one by one (from first rule to the last), we must make sure they are properly positioned. So,the rule that is blocking all traffic from /24 subnet, cannot be before rule that whitelists single IP from that subnet. It must be the other way around. First, you whitelist an IP address, and then block the entire subnet:
Protocols and modules
To block all incoming TCP traffic you would use -p tcp flag, like so:
# iptables -t filter -A INPUT -p tcp -j DROP
To block all incoming traffic to port 22 (SSH) from IP range 195.94.101.10/24, you would type this:
# iptables -t filter -A INPUT -p tcp -m tcp --dport 22 -s 195.94.101.10/24 -j DROP
Let’s digest this formula from above:
-t filter | Apply the following for filter table |
-A INPUT | Now, append this rule to INPUT chain |
-p tcp | Specify port type (TCP in this case) |
-m tcp | Load TCP module (multiport for multiple ports) |
–dport | And all incoming packets going to port 22 (–dports for multiple ports) |
-s 195.94.101.10/24 | And source IP / range 195.94.101.10/24 |
-j DROP | DROP them |
TCP Connection Tracking Module
iptables have a module that can control packet behavior from the state of a connection. Here are the states:
NEW | This state represents first packet of a connection (HTTP request for example) |
ESTABLISHED | This state is used for packets that are part of an existing connection. For a connections to be in this state, it must receive a reply from the other host |
RELATED | This state is used for packets that are related to another ESTABLISHED connection. For a packet that is part of an existing connection, but it requests new connection. |
INVALID | This state means the packet doesn’t have proper state. |
DNAT | This state is used to show packets whose destination address was changed by rules in nat table |
SNAT | This state is used to show packets whose source address was changed by rules in nat table. |
# iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
If we set a INPUT chain policy to accept, like this (which is default rule):
[root@arch ~]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Then, all traffic that comes to our system will be accepted. However, we can also use DROP to ban all incoming connections to our system, like so:
# iptables -P INPUT DROP
If doing this, we should ban all incoming traffic, from any IP, from any port. However, this will also restrict us to use all services, and also to use Internet.
Saving changes
Changes we make to iptables rules will be removed next time iptables service gets restarted. To save changes, run /sbin/iptables-save command
Remove rules
To remove all configured rules, and go back to default ones, use -F (flush):
# iptables -F