Linux IP tables for Beginners
This blog introduces some simple firewall rules and how to configure rules with iptables.
iptables is an application that allows a user to configure the firewall functionality also it is into the Linux kernel.
Types of tables in iptables
By default, there are three tables in the kernel that contain sets of rules.
The filter table is used for packet filtering.
[email protected]~# iptables -t filter -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
The nat table is used for address translation.
[email protected]~# iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
The mangle table can be used for special-purpose processing of packets.
A series of rules in each table are called a chain. We will discuss chains and the nat table later in this chapter.
Start and stop iptables
The following screenshot shows how to stop and start iptables on Red Hat/Fedora/CentOS and compatible distributions.
[[email protected] ~]# service iptables stop [[email protected] ~]# service iptables start iptables: Applying firewall rules [ ok ]
Debian and *ubuntu distributions do not have this script but allow for an uninstall.
[email protected]~# aptitude purge iptables
The filter table
About packet filtering
Packet filtering is a bit lengthy process as comparison to packet forwarding. The packet forwarding uses only a routing table to make decisions, where the packet filtering also uses a list of rules. The kernel will inspect packets and decide based on these rules what to do with each packet.
Filter table
The filter table in iptables holds three sets of rules. The INPUT chain is used for any packet coming into the system. The OUTPUT chain is for any packet leaving the system. And the FORWARD chain is for packets that are routed through the system.
The screenshot below shows how to list the filter table and all its rules.
[[email protected] ~]# iptables -t filter -nL 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
As you can see, all three chains in the filter table are set to ACCEPT everything. ACCEPT implies default behavior in iptables.
Setting up default ruleset
The default for the default rule is indeed to ACCEPT everything. This is not the most secure firewall.
A more secure setup would be to DROP everything. A package that is dropped will not continue in any chain, and no warning or error will be sent anywhere.
The below commands lock down a computer. Do not execute these commands inside a remote ssh shell.
[email protected]~# iptables -P INPUT DROP [email protected]~# iptables -P OUTPUT DROP [email protected]~# iptables -P FORWARD DROP [email protected]~# iptables -L Chain INPUT (policy DROP) target prot opt source destination Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy DROP) target prot opt source destination
Changing policy rules in iptables
To start, let’s first set the default policy for all three chains to drop everything.
Note:- that you might lose your connection when typing it over ssh ;-).
[[email protected] ~]# iptables -P INPUT DROP [[email protected] ~]# iptables -P FORWARD DROP [[email protected] ~]# iptables -P OUTPUT DROP
Now, we allow the server to use its own loopback device (this allows the server to access its services running on localhost). We first append a rule to the INPUT chain to allow (ACCEPT) traffic from the lo (loopback) interface, then we do the same to allow packets to leave the system through the loopback interface.
[[email protected] ~]# iptables -A INPUT -i lo -j ACCEPT [[email protected] ~]# iptables -A OUTPUT -o lo -j ACCEPT
Looking at the filter table again (omitting -t filter because it is the default table).
[[email protected] ~]# iptables -nL Chain INPUT (policy DROP) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy DROP) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
Allowing ssh over eth0
This example shows how to add two rules to allow ssh access to your system from outside.
[[email protected] ~]# iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT [[email protected] ~]# iptables -A OUTPUT -o eth0 -p tcp --sport 22 -j ACCEPT
The filter table will look something like this screenshot (note that -v is added for more verbose output).
[[email protected] ~]# iptables -nvL Chain INPUT (policy DROP 7 packets, 609 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy DROP 3 packets, 228 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * lo 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT tcp -- * eth0 0.0.0.0/0 0.0.0.0/0 tcp spt:22
Allowing access from a subnet
This example shows how to allow access from any computer in the 10.1.1.0/24 network, but only through eth1. There is no port (application) limitation here.
[[email protected] ~]# iptables -A INPUT -i eth1 -s 10.1.1.0/24 -p tcp -j ACCEPT [[email protected] ~]# iptables -A OUTPUT -o eth1 -d 10.1.1.0/24 -p tcp -j ACCEPT
Together with the previous examples, the policy is expanding.
[[email protected] ~]# iptables -nvL Chain INPUT (policy DROP 7 packets, 609 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 0 0 ACCEPT tcp -- eth1 * 10.1.1.0/24 0.0.0.0/0 Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy DROP 3 packets, 228 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * lo 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT tcp -- * eth0 0.0.0.0/0 0.0.0.0/0 tcp spt:22 0 0 ACCEPT tcp -- * eth1 0.0.0.0/0 10.1.1.0/24
Automatic implement the rules
Use iptables save to automatically implement these rules when the firewall is (re)started.
[[email protected] ~]# /etc/init.d/iptables save Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
scripting example
You can write a simple script for these rules. Below is an example script that implements the firewall rules that you saw before in this chapter.
#!/bin/bash # first cleanup everything iptables -t filter -F iptables -t filter -X iptables -t nat -F iptables -t nat -X # default drop iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT DROP # allow loopback device iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # allow ssh over eth0 from outside to system iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 22 -j ACCEPT # allow any traffic from 10.1.1.0/24 to system iptables -A INPUT -i eth1 -s 10.1.1.0/24 -p tcp -j ACCEPT iptables -A OUTPUT -o eth1 -d 10.1.1.0/24 -p tcp -j ACCEPT
Allowing ICMP(ping)
When you enable iptables, you will get an ‘Operation not permitted’ message when trying to ping other hosts.
[[email protected] ~# ping 192.168.1.130 PING 192.168.1.130 (192.168.1.130) 56(84) bytes of data. ping: sendmsg: Operation not permitted ping: sendmsg: Operation not permitted
The screenshot below shows you how to set up iptables to allow ping from or to your machine.
[[email protected] ~]# iptables -A INPUT -p icmp --icmp-type any -j ACCEPT [[email protected] ~]# iptables -A OUTPUT -p icmp --icmp-type any -j ACCEPT
The previous two lines do not allow other computers to route ping messages through your router, because it only handles INPUT and OUTPUT. For routing of ping, you will need to enable it on the FORWARD chain. The following command enables routing of icmp messages between networks.
[root@RHEL6 ~]# iptables -A FORWARD -p icmp --icmp-type any -j ACCEPT
Practice: packet filtering
1. Make sure you can ssh to your router-system when iptables is active.
2. Make sure you can ping to your router-system when iptables is active.
3. Define one of your networks as ‘internal’ and the other as ‘external’. Configure the router to allow visits to a website (HTTP) to go from the internal network to the external network (but not in the other direction).
4. Make sure the internal network can ssh to the external, but not the other way around.
Solution: packet filtering
A possible solution, where leftnet is the internal and rightnet is the external network.
#!/bin/bash # first cleanup everything iptables -t filter -F iptables -t filter -X iptables -t nat -F iptables -t nat -X # default drop iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT DROP # allow loopback device iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # question 1: allow ssh over eth0 iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 22 -j ACCEPT # question 2: Allow icmp(ping) anywhere iptables -A INPUT -p icmp --icmp-type any -j ACCEPT iptables -A FORWARD -p icmp --icmp-type any -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type any -j ACCEPT # question 3: allow http from internal(leftnet) to external(rightnet) iptables -A FORWARD -i eth1 -o eth2 -p tcp --dport 80 -j ACCEPT iptables -A FORWARD -i eth2 -o eth1 -p tcp --sport 80 -j ACCEPT # question 4: allow ssh from internal(leftnet) to external(rightnet) iptables -A FORWARD -i eth1 -o eth2 -p tcp --dport 22 -j ACCEPT iptables -A FORWARD -i eth2 -o eth1 -p tcp --sport 22 -j ACCEPT # allow http from external(rightnet) to internal(leftnet) # iptables -A FORWARD -i eth2 -o eth1 -p tcp --dport 80 -j ACCEPT # iptables -A FORWARD -i eth1 -o eth2 -p tcp --sport 80 -j ACCEPT # allow rpcinfo over eth0 from outside to system # iptables -A INPUT -i eth2 -p tcp --dport 111 -j ACCEPT # iptables -A OUTPUT -o eth2 -p tcp --sport 111 -j ACCEPT
Network address translation
A NAT device is a router that is also changing the source and/or target IP-address in packets. It is typically used to connect multiple computers in a private address range with the (public) internet. A NAT can hide private addresses from the internet.
NAT was developed to mitigate the use of real IP addresses, to allow private address ranges to reach the internet and back and to not disclose details about internal networks to the outside.
The NAT table in iptables adds two new chains. PREROUTING allows altering of packets before they reach the INPUT chain. POSTROUTING allows altering packets after they exit the OUTPUT chain.
Use iptables -t nat -nvL to look at the NAT table. The screenshot below shows an empty NAT table.
[[email protected] ~]# iptables -t nat -nL Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
SNAT (Source NAT)
The goal of SNAT is to change the source address inside a packet before it leaves the system (e.g. to the internet). The destination will return the packet to the NAT-device. This means our NAT-device will need to keep a table in memory of all the packets it changed, so it can deliver the packet to the original source (e.g. in the private network).
Because SNAT is about packets leaving the system, it uses the POSTROUTING chain.
Here is an example SNAT rule. The rule says that packets coming from 10.1.1.0/24 network and exiting via eth1 will get the source IP-address set to 11.12.13.14. (Note that this is a one-line command!)
iptables -t nat -A POSTROUTING -o eth1 -s 10.1.1.0/24 -j SNAT \ --to-source 11.12.13.14
Of course, there must exist a proper iptables filter setup to allow the packet to traverse from one network to the other.
SNAT example setup
This example script uses a typical nat setup. The internal (eth0) network has access via SNAT to external (eth1) webservers (port 80).
#!/bin/bash # # iptables script for simple classic nat websurfing # eth0 is internal network, eth1 is internet # echo 0 > /proc/sys/net/ipv4/ip_forward iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD DROP iptables -A FORWARD -i eth0 -o eth1 -s 10.1.1.0/24 -p tcp \ --dport 80 -j ACCEPT iptables -A FORWARD -i eth1 -o eth0 -d 10.1.1.0/24 -p tcp \ --sport 80 -j ACCEPT iptables -t nat -A POSTROUTING -o eth1 -s 10.1.1.0/24 -j SNAT \ --to-source 11.12.13.14 echo 1 > /proc/sys/net/ipv4/ip_forward
IP masquerading
IP masquerading is very similar to SNAT but is meant for dynamic interfaces. Typical examples are broadband ‘router/modems’ connected to the internet and receiving a different IP-address from the isp, each time they are cold-booted.
The only change needed to convert the SNAT script to a masquerading is one line.
iptables -t nat -A POSTROUTING -o eth1 -s 10.1.1.0/24 -j MASQUERADE
DNAT (Destination NAT)
DNAT is typically used to allow packets from the internet to be redirected to an internal server (in your DMZ) and in a private address range that is inaccessible directly from the internet.
This example script allows internet users to reach your internal (192.168.1.130) server via ssh (port 22).
#!/bin/bash # # iptables script for DNAT # eth0 is internal network, eth1 is internet # echo 0 > /proc/sys/net/ipv4/ip_forward iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD DROP iptables -A FORWARD -i eth0 -o eth1 -s 10.1.1.0/24 -j ACCEPT iptables -A FORWARD -i eth1 -o eth0 -p tcp --dport 22 -j ACCEPT iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 22 \ -j DNAT --to-destination 10.1.1.130 echo 1 > /proc/sys/net/ipv4/ip_forward
Recent Comments