iptables is a powerful firewall administration tool used in Linux-based operating systems. It allows administrators to set up and manage rules for packet filtering and network address translation (NAT) within the Linux kernel. With iptables, you can control incoming and outgoing network traffic, making it a crucial component for securing and managing network communications.
The primary purpose of iptables is to provide a way to define rules that determine how network packets should be handled. These rules can allow, deny, or modify packets based on various criteria, such as source and destination IP addresses, ports, protocols, connection states, and more. By configuring these rules, administrators can control the flow of network traffic and enforce security policies.
The main functionalities of iptables are:
1. Packet Filtering: It allows you to specify which packets are allowed to pass through the system and which ones should be dropped or rejected. This is the basic function of a firewall - to filter traffic based on predefined rules.
2. Network Address Translation (NAT): iptables can perform Network Address Translation, allowing you to modify the source or destination IP address and/or port of packets as they traverse through the system. NAT is often used to map internal private IP addresses to a single public IP address when accessing the internet.
3. Stateful Connection Tracking: iptables can track the state of network connections, which means it can recognize established connections and allow related packets to pass through. This helps in managing incoming and outgoing traffic for established connections and prevents unwanted external access.
4. Packet Manipulation: iptables enables you to alter packet headers or payloads, enabling more advanced network configurations or setups.
5. Logging: iptables can be set up to log network activity, providing valuable information for troubleshooting and auditing network traffic.
6. Traffic Shaping and Quality of Service (QoS): iptables can be used for traffic shaping and implementing Quality of Service rules to prioritize certain types of network traffic over others.
It's important to be cautious when configuring iptables rules, as misconfigurations can lead to unintended consequences and potential network disruptions. Always test new rules carefully and consider implementing a robust backup and rollback strategy.
Iptables rules are ephemeral, which means they need to be manually saved for them to persist after a reboot.
On Ubuntu, one way to save iptables rules is to use the iptables-persistent package. Install it with apt like this:
sudo apt install iptables-persistent
If you update your firewall rules and want to save the changes, run this command:
sudo netfilter-persistent save
To list out all of the active iptables rules by specification, run the iptables command with the -S option:
sudo iptables -S
Output -P INPUT DROP -P FORWARD DROP -P OUTPUT ACCEPT -N ICMP -N TCP -N UDP -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable -A TCP -p tcp -m tcp --dport 22 -j ACCEPT ...
If you want to limit the output to a specific chain (INPUT, OUTPUT, TCP, etc.), you can specify the chain name directly after the -S option. For example, to show all of the rule specifications in the TCP chain, you would run this command:
sudo iptables -S TCP
Output -N TCP -A TCP -p tcp -m tcp --dport 22 -j ACCEPT
When listing iptables rules, it is also possible to show the number of packets, and the aggregate size of the packets in bytes, that matched each particular rule. This is often useful when trying to get a rough idea of which rules are matching against packets. To do so, use the -L and -v options together.
sudo iptables -L INPUT -v
Output Chain INPUT (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 284K 42M ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED 0 0 ACCEPT all -- lo any anywhere anywhere 0 0 DROP all -- any any anywhere anywhere ctstate INVALID 396 63275 UDP udp -- any any anywhere anywhere ctstate NEW 17067 1005K TCP tcp -- any any anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN ctstate NEW 2410 154K ICMP icmp -- any any anywhere anywhere ctstate NEW 396 63275 REJECT udp -- any any anywhere anywhere reject-with icmp-port-unreachable 2916 179K REJECT all -- any any anywhere anywhere reject-with icmp-proto-unreachable 0 0 ACCEPT tcp -- any any anywhere anywhere
To clear the counters for all chains and rules, use the -Z option by itself:
sudo iptables -Z
To clear the counters for all rules in a specific chain, use the -Z option and specify the chain. For example, to clear the INPUT chain counters run this command:
sudo iptables -Z INPUT
If you want to clear the counters for a specific rule, specify the chain name and the rule number. For example, to zero the counters for the first rule in the INPUT chain, run this:
sudo iptables -Z INPUT 1
To determine a rule’s line number, list the rules in the table format and add the --line-numbers option:
sudo iptables -L --line-numbers
Output Chain INPUT (policy DROP) num target prot opt source destination 1 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED 2 ACCEPT all -- anywhere anywhere 3 DROP all -- anywhere anywhere ctstate INVALID 4 UDP udp -- anywhere anywhere ctstate NEW 5 TCP tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN ctstate NEW 6 ICMP icmp -- anywhere anywhere ctstate NEW 7 REJECT udp -- anywhere anywhere reject-with icmp-port-unreachable 8 REJECT tcp -- anywhere anywhere reject-with tcp-reset 9 REJECT all -- anywhere anywhere reject-with icmp-proto-unreachable 10 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ctstate NEW,ESTABLISHED ...
Once you know which rule you want to delete, note the chain and line number of the rule. Then run the iptables -D command followed by the chain and rule number.
sudo iptables -D INPUT 3
To flush a specific chain, which will delete all of the rules in the chain, you may use the -F, or the equivalent --flush, option and the name of the chain to flush.
For example, to delete all of the rules in the INPUT chain, run this command:
sudo iptables -F INPUT
To flush all chains, which will delete all of the firewall rules, you may use the -F, or the equivalent --flush, option by itself:
sudo iptables -F
This section will show you how to flush all of your firewall rules, tables, and chains, and allow all network traffic. Warning: This will effectively disable your firewall. You should only follow this section if you want to start over the configuration of your firewall.
First, set the default policies for each of the built-in chains to ACCEPT. The main reason to do this is to ensure that you won’t be locked out from your server via SSH:
sudo iptables -P INPUT ACCEPT sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT
Then flush the nat and mangle tables, flush all chains (-F), and delete all non-default chains (-X):
sudo iptables -t nat -F sudo iptables -t mangle -F sudo iptables -F sudo iptables -X
Your firewall will now allow all network traffic. If you list your rules now, you will will see there are none, and only the three default chains (INPUT, FORWARD, and OUTPUT) remain.
The loopback interface, also referred to as lo, is what a computer uses to forward network connections to itself. For example, if you run ping localhost or ping 127.0.0.1, your server will ping itself using the loopback. The loopback interface is also used if you configure your application server to connect to a database server with a localhost address. As such, you will want to be sure that your firewall is allowing these connections.
To accept all traffic on your loopback interface, run these commands:
sudo iptables -A INPUT -i lo -j ACCEPT sudo iptables -A OUTPUT -o lo -j ACCEPT
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 for outgoing connections initiated by the server itself. This command will allow that:
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
You 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
Assuming eth0 is your external network, and eth1 is your internal network, this will allow your internal to access the external:
sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
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. Do so with this command:
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
To block network connections that originate from a specific IP address, 203.0.113.51 for example, run this command:
sudo iptables -A INPUT -s 203.0.113.51 -j DROP
In this example, -s 203.0.113.51 specifies a source IP address of “203.0.113.51”. The source IP address can be specified in any firewall rule, including an allow rule.
If you want to reject the connection instead, which will respond to the connection request with a “connection refused” error, replace “DROP” with “REJECT” like this:
sudo iptables -A INPUT -s 203.0.113.51 -j REJECT
To block connections from a specific IP address, e.g. 203.0.113.51, to a specific network interface, e.g. eth0, use this command:
iptables -A INPUT -i eth0 -s 203.0.113.51 -j DROP
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT
To allow incoming SSH connections from a specific IP address or subnet, specify the source. For example, if you want to allow the entire 203.0.113.0/24 subnet, run these commands:
sudo iptables -A INPUT -p tcp -s 203.0.113.0/24 --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT
If your firewall OUTPUT policy is not set to ACCEPT, and you want to allow outgoing SSH connections—your server initiating an SSH connection to another server—you can run these commands:
sudo iptables -A OUTPUT -p tcp --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A INPUT -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED -j ACCEPT
Rsync, which runs on port 873, can be used to transfer files from one computer to another.
To allow incoming rsync connections from a specific IP address or subnet, specify the source IP address and the destination port. For example, if you want to allow the entire 203.0.113.0/24 subnet to be able to rsync to your server, run these commands:
sudo iptables -A INPUT -p tcp -s 203.0.113.0/24 --dport 873 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 873 -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate ESTABLISHED -j ACCEPT
To allow incoming MySQL connections from a specific IP address or subnet, specify the source. For example, if you want to allow the entire 203.0.113.0/24 subnet, run these commands:
sudo iptables -A INPUT -p tcp -s 203.0.113.0/24 --dport 3306 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 3306 -m conntrack --ctstate ESTABLISHED -j ACCEPT
To allow MySQL connections to a specific network interface—say you have a private network interface eth1, for example—use these commands:
sudo iptables -A INPUT -i eth1 -p tcp --dport 3306 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -o eth1 -p tcp --sport 3306 -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 25 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 25 -m conntrack --ctstate ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 143 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT sudo iptables -A OUTPUT -p tcp --sport 143 -m conntrack --ctstate ESTABLISHED -j ACCEPT