Linux IP tables for Dummies

iptable
All Blog

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.

[[email protected] ~]# 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

Leave a Reply

Your email address will not be published. Required fields are marked *