This How-To provides the details for securing a Linux gateway box with the IPTABLES firewall. This guide can be used for Kernels ranging from 2.4-2.6. Special rules for running Squid in transparent mode and providing Network Address Translation (NAT) are also covered in this guide.

The tool IPTABLES talks to the kernel and tells it what packets to filter.

The IPTABLES application operates at a high level by filtering TCP and UDP protocols before the data is passed onto the user applications that can be corrupted.

The IPTABLES tool inserts and deletes rules from the kernel’s packet filtering table.

What this means is that the rules you create in your Linux machine using IPTABLES are lost upon reboot.

The best way to use IPTABLES rules are to store them up in a simple shell script and use your Linux OS to load that script on boot up.

IPTABLES uses the concept of tables. It has 3 tables known as Filter, NAT and Mangle tables. Most of the rules in this guide uses the Filter table to maintain it’s rules though we will also introduce the basic rules for NAT table. The NAT table is needed to Network Address Translation which can be used for internet connection sharing, etc.

The Filter table in turn has 3 chains called INPUT, OUTPUT and FORWARD.

Their simple definition are as follows:

INPUT Chain: If a packet comes to your Linux machine either from your local network or from the Internet itself, that packet passes through the INPUT chain.

OUTPUT Chain: Any packet originating from a program such as Squid, Apache, Bind, etc on your Linux machine itself has to pass through the OUTPUT chain.

FORWARD Chain: If IP forwarding is enabled on your Linux machine, this Linux machine can act as a router or gateway between 2 or more networks. When we say 2 networks, it can mean that the 1st network is your LAN and 2nd network can be the Internet. In order for your machines on your LAN to travel to the 2nd network and vice versa, the packet has to pass through the FORWARD chain.

Note: This guide follows the guidelines and ideas given by Oskar Andreasson. I would like to thank him for his wonderful and amazing IPTABLES guide which can be found at:

http://iptables-tutorial.frozentux.net/iptables-tutorial.html

I request everybody new to IPTABLES to read this guide. Oskar Andreasson should be given an award for his works!

Keeping that in mind, let us create a simple but effective IPTABLES firewall rules in a file called rc.firewall. The firewall can be used for Linux boxes with at least 2 network interfaces. Our firewall will have 3 network interfaces.

This firewall is just a guide and introduction to IPTABLES. Please use it at your own risks. I will not be responsible for any side-effects!

(1.) Go to a general location such as /etc

cd /etc

(2.) Use the Vi editor and create a file called rc.firewall

vi rc.firewall

(2.) Copy and paste the following in your rc.firewall script

#!/bin/sh

# Firewall for Linux Box created by Tek Limbu
### tekbdrlimbu@hotmail.com ###
###Date: 07-Oct-2007

LOGGING=1

LO_IF=”lo”
LO_IF_IP=”127.0.0.1″

#Define your eth0, eth1 and eth2 interfaces
#Eth0 = Internet Network
#Eth1 = Local Area Network
#Eth2 = Wireless Network

OUT_IF=eth0
INT_IF1=eth1
INT_IF2=eth2

#Extract your interfaces’ IP
OUT_IF_IP=”`/sbin/ifconfig $OUT_IF | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $1}’`”
INT_IF_IP1=”`/sbin/ifconfig $INT_IF1 | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $1}’`”
INT_IF_IP2=”`/sbin/ifconfig $INT_IF2 | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $1}’`”
OUT_IF_MASK=”`/sbin/ifconfig $OUT_IF | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $3}’`”
INT_IF_MASK1=”`/sbin/ifconfig $INT_IF1 | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $3}’`”
INT_IF_MASK2=”`/sbin/ifconfig $INT_IF2 | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $3}’`”

#Extract your interfaces netmask

OUT_IF_NET=$OUT_IF_IP/$OUT_IF_MASK
INT_IF_NET1=$INT_IF_IP1/$INT_IF_MASK1
INT_IF_NET2=$INT_IF_IP2/$INT_IF_MASK2

#Extract your Broadcast mask

OUT_IF_BROADCAST=”`/sbin/ifconfig $OUT_IF | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $2}’`”
INT_IF_BROADCAST1=”`/sbin/ifconfig $INT_IF1 | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $2}’`”
INT_IF_BROADCAST2=”`/sbin/ifconfig $INT_IF2 | grep ‘inet[^6]’ | sed ’s/[a-zA-Z:]//g’ | awk ‘{print $2}’`”

#Define your local and server network and ports
#You may need to change the IPs to your own IP addresses

PROXY=”192.168.0.1″
PROXY_NET=”192.168.0.0/29″
LOCAL_NET=”192.168.0.0/24″
EXTERNAL_NET=”172.16.0.0/24″
SYSTEM_NET=”10.0.0.0/24″
MY_IP=”192.168.0.100″
SSH=”12345″
NTP_SERVER=”10.0.0.5″
IPTABLES=”/sbin/iptables”

echo “Starting Firewalling ……..”

# Flush everything
$IPTABLES -F

# Set default policies to DROP

$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT DROP
$IPTABLES -P FORWARD DROP

echo starting firewall
# Set necessary values for /proc
echo “1″ >/proc/sys/net/ipv4/ip_forward

if [ -e /proc/sys/net/ipv4/tcp_syncookies ]
then
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
fi
echo 1 > /proc/sys/net/ipv4/tcp_syncookies

# dont respond to broadcasts (dont get smurfed)
echo “1″ > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

#Load Necessary Modules at runtime
/sbin/depmod -a

# Flush everything

# flush all the rules in the filter and nat tables.

$IPTABLES -F
$IPTABLES -t nat -F
$IPTABLES -t mangle -F

# erase all chains that’s not default in filter and nat table.

$IPTABLES -X
$IPTABLES -t nat -X
$IPTABLES -t mangle -X

#Define your own chains

$IPTABLES -N bad_tcp_packets
$IPTABLES -N allowed
$IPTABLES -N tcp_packets
$IPTABLES -N udp_packets
$IPTABLES -N icmp_packets

# bad_tcp_packets chain

$IPTABLES -A bad_tcp_packets -p tcp –tcp-flags SYN,ACK SYN,ACK \
-m state –state NEW -j REJECT –reject-with tcp-reset
$IPTABLES -A bad_tcp_packets -p tcp ! –syn -m state –state NEW -j LOG \
–log-prefix “New not syn:”
$IPTABLES -A bad_tcp_packets -p tcp ! –syn -m state –state NEW -j DROP
$IPTABLES -A bad_tcp_packets -p tcp -m state –state INVALID -j LOG –log-prefix “Invalid packet:”
$IPTABLES -A bad_tcp_packets -p tcp -m state –state INVALID -j DROP

$IPTABLES -A allowed -p TCP –syn -j ACCEPT
$IPTABLES -A allowed -p TCP -m state –state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A allowed -p TCP -j DROP

# TCP rules

###Web Server
$IPTABLES -A tcp_packets -p TCP -s $LOCAL_NET –dport 80 -j allowed

##Only if you want the World to access your Web server
$IPTABLES -A tcp_packets -p TCP -s 0.0.0.0/0.0.0.0 –dport 80 -j allowed

$IPTABLES -A tcp_packets -p TCP -s $EXTERNAL_NET –dport 80 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $SYSTEM_NET –dport 80 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $OUT_IF_NET –dport 80 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET1 –dport 80 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET2 –dport 80 -j allowed

###Mail SMTP Server
$IPTABLES -A tcp_packets -p TCP -s $LOCAL_NET –dport 25 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $SYSTEM_NET –dport 25 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $EXTERNAL_NET –dport 25 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $OUT_IF_NET –dport 25 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET1 –dport 25 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET2 –dport 25 -j allowed

#Only needed if your Mail Server has a vaild MX and Reverse DNS entries
$IPTABLES -A tcp_packets -p TCP -s 0.0.0.0/0.0.0.0 –dport 25 -j allowed

###Courier-Pass
$IPTABLES -A tcp_packets -p TCP -s localhost –dport 106 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $LOCAL_NET –dport 106 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $EXTERNAL_NET –dport 106 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $SYSTEM_NET –dport 106 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $OUT_IF_NET –dport 106 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET1 –dport 106 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET2 –dport 106 -j allowed

###IMAP
$IPTABLES -A tcp_packets -p TCP -s localhost –dport 143 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $LOCAL_NET –dport 143 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $EXTERNAL_NET –dport 143 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $SYSTEM_NET –dport 143 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $OUT_IF_NET –dport 143 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET1 –dport 143 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET2 –dport 143 -j allowed

###Allow SSH to this machine

$IPTABLES -A tcp_packets -p TCP -s $LOCAL_NET –dport $SSH -j allowed
$IPTABLES -A tcp_packets -p TCP -s $EXTERNAL_NET –dport $SSH -j allowed
$IPTABLES -A tcp_packets -p TCP -s $SYSTEM_NET –dport $SSH -j allowed
$IPTABLES -A tcp_packets -p TCP -s $MY_IP –dport $SSH -j allowed
$IPTABLES -A tcp_packets -p TCP -s $PROXY_NET –dport $SSH -j allowed

###Allow TCP connections to Squid. Only needed if you are running a Squid cache.
$IPTABLES -A tcp_packets -p TCP -s $LOCAL_NET –dport 3128 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $EXTERNAL_NET –dport 3128 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $SYSTEM_NET –dport 3128 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $OUT_IF_NET –dport 3128 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET1 –dport 3128 -j allowed
$IPTABLES -A tcp_packets -p TCP -s $INT_IF_NET2 –dport 3128 -j allowed

#Allow DNS queries. Only needed if you are running a local DNS server.

$IPTABLES -A udp_packets -p UDP -s $LOCAL_NET –destination-port 53 -j ACCEPT
$IPTABLES -A udp_packets -p UDP -s $EXTERNAL_NET –destination-port 53 -j ACCEPT
$IPTABLES -A udp_packets -p UDP -s $SYSTEM_NET –destination-port 53 -j ACCEPT
$IPTABLES -A udp_packets -p UDP -s $OUT_IF_NET –destination-port 53 -j ACCEPT
$IPTABLES -A udp_packets -p UDP -s $INT_IF_NET1 –destination-port 53 -j ACCEPT
$IPTABLES -A udp_packets -p UDP -s $INT_IF_NET2 –destination-port 53 -j ACCEPT

#Allow NTP update
$IPTABLES -A udp_packets -p UDP -s $NTP_SERVER –destination-port 123 -j ACCEPT

#ICP Queries from Proxy Network. Needed only if you have proxy peers.
$IPTABLES -A udp_packets -p UDP -s $PROXY_NET –destination-port 3130 -j ACCEPT

#Drop Microsoft Networks’ Broadcasts
$IPTABLES -A udp_packets -p UDP -i $OUT_IF -d $OUT_IF_BROADCAST –destination-port 135:139 -j DROP
$IPTABLES -A udp_packets -p UDP -s $INT_IF_NET1 -d $INT_IF_BROADCAST1 –destination-port 135:139 -j DROP
$IPTABLES -A udp_packets -p UDP -s $INT_IF_NET2 -d $INT_IF_BROADCAST2 –destination-port 135:139 -j DROP

#Drop DHCP requests from the Outside of our network
$IPTABLES -A udp_packets -p UDP -i $OUT_IF -d $OUT_IF_BROADCAST –destination-port 67:68 -j DROP
$IPTABLES -A udp_packets -p UDP -s $INT_IF_NET1 -d $INT_IF_BROADCAST1 –destination-port 135:139 -j DROP
$IPTABLES -A udp_packets -p UDP -s $INT_IF_NET2 -d $INT_IF_BROADCAST2 –destination-port 135:139 -j DROP

# ICMP rules

$IPTABLES -A icmp_packets -p ICMP -s $LOCAL_NET –icmp-type 0 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $LOCAL_NET –icmp-type 3 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $LOCAL_NET –icmp-type 5 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $LOCAL_NET –icmp-type 8 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $LOCAL_NET –icmp-type 11 -j ACCEPT

$IPTABLES -A icmp_packets -p ICMP -s $EXTERNAL_NET –icmp-type 0 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $EXTERNAL_NET –icmp-type 3 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $EXTERNAL_NET –icmp-type 5 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $EXTERNAL_NET –icmp-type 8 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $EXTERNAL_NET –icmp-type 11 -j ACCEPT

$IPTABLES -A icmp_packets -p ICMP -s $SYSTEM_NET –icmp-type 0 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $SYSTEM_NET –icmp-type 3 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $SYSTEM_NET –icmp-type 5 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $SYSTEM_NET –icmp-type 8 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $SYSTEM_NET –icmp-type 11 -j ACCEPT

$IPTABLES -A icmp_packets -p ICMP -s $PROXY_NET –icmp-type 0 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $PROXY_NET –icmp-type 3 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $PROXY_NET –icmp-type 5 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $PROXY_NET –icmp-type 8 -j ACCEPT
$IPTABLES -A icmp_packets -p ICMP -s $PROXY_NET –icmp-type 11 -j ACCEPT

## INPUT chain

#Drop Bad Packets
$IPTABLES -A INPUT -p tcp -j bad_tcp_packets

$IPTABLES -A INPUT -p ALL -i $INT_IF1 -s $INT_IF_NET1 -j ACCEPT
$IPTABLES -A INPUT -p ALL -i $INT_IF1 -s $OUT_IF_NET -j ACCEPT
$IPTABLES -A INPUT -p ALL -i $OUT_IF -s $OUT_IF_NET -j ACCEPT
$IPTABLES -A INPUT -p ALL -i $INT_IF2 -s $INT_IF_NET2 -j ACCEPT
$IPTABLES -A INPUT -p ALL -i $INT_IF2 -s $OUT_IF_NET -j ACCEPT

$IPTABLES -A INPUT -p ALL -i $LO_IF -s $LO_IF_IP -j ACCEPT
$IPTABLES -A INPUT -p ALL -i $LO_IF -s $INT_IF_IP1 -j ACCEPT
$IPTABLES -A INPUT -p ALL -i $LO_IF -s $INT_IF_IP2 -j ACCEPT
$IPTABLES -A INPUT -p ALL -i $LO_IF -s $OUT_IF_IP -j ACCEPT

$IPTABLES -A INPUT -p ALL -d $OUT_IF_IP -m state –state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A INPUT -p ALL -d $INT_IF_IP1 -m state –state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A INPUT -p ALL -d $INT_IF_IP2 -m state –state ESTABLISHED,RELATED -j ACCEPT

#Forword all TCP packets to tcp_packets chain
$IPTABLES -A INPUT -p TCP -i $OUT_IF -j tcp_packets
$IPTABLES -A INPUT -p TCP -s $OUT_IF_NET -j tcp_packets
$IPTABLES -A INPUT -p TCP -s $INT_IF_NET1 -j tcp_packets
$IPTABLES -A INPUT -p TCP -s $INT_IF_NET2 -j tcp_packets

#Forward all UDP packets to udp_packets chain
$IPTABLES -A INPUT -p UDP -i $OUT_IF -j udp_packets
$IPTABLES -A INPUT -p UDP -s $OUT_IF_NET -j udp_packets
$IPTABLES -A INPUT -p UDP -s $INT_IF_NET1 -j udp_packets
$IPTABLES -A INPUT -p UDP -s $INT_IF_NET2 -j udp_packets

#Forward all ICMP packets to icmp_packets chain
$IPTABLES -A INPUT -p ICMP -i $OUT_IF -j icmp_packets
$IPTABLES -A INPUT -p ICMP -s $INT_IF_NET1 -j icmp_packets
$IPTABLES -A INPUT -p ICMP -s $INT_IF_NET2 -j icmp_packets

#Drop Multicasts from Microsoft Networks
$IPTABLES -A INPUT -i $OUT_IF -d 224.0.0.0/8 -j DROP
$IPTABLES -A INPUT -i $INT_IF1 -d 224.0.0.0/8 -j DROP
$IPTABLES -A INPUT -i $INT_IF2 -d 224.0.0.0/8 -j DROP
#$IPTABLES -A INPUT -i $OUT_IF1 -d 224.0.0.0/8 -j DROP
#$IPTABLES -A INPUT -i $OUT_IF2 -d 224.0.0.0/8 -j DROP

#Log weird packets that don’t match the above.
$IPTABLES -A INPUT -m limit –limit 3/minute –limit-burst 3 -j LOG \
–log-level DEBUG –log-prefix “IPT INPUT packet died: “

# FORWARD chain

# Bad TCP packets we don’t want
$IPTABLES -A FORWARD -p tcp -j bad_tcp_packets

# Accept the packets we actually want to forward

$IPTABLES -A FORWARD -i $INT_IF1 -j ACCEPT
$IPTABLES -A FORWARD -i $INT_IF2 -j ACCEPT
$IPTABLES -A FORWARD -i $OUT_IF -j ACCEPT

$IPTABLES -A FORWARD -m state –state ESTABLISHED,RELATED -j ACCEPT

# Log weird packets that don’t match the above.
$IPTABLES -A FORWARD -m limit –limit 3/minute –limit-burst 3 -j LOG \
–log-level DEBUG –log-prefix “IPT FORWARD packet died: “

#OUTPUT chain

#Bad TCP packets we don’t want.
$IPTABLES -A OUTPUT -p tcp -j bad_tcp_packets

# Special OUTPUT rules to decide which IP’s to allow.

$IPTABLES -A OUTPUT -p ALL -s $LO_IF_IP -j ACCEPT
$IPTABLES -A OUTPUT -p ALL -s $INT_IF_IP1 -j ACCEPT
$IPTABLES -A OUTPUT -p ALL -s $INT_IF_IP2 -j ACCEPT
$IPTABLES -A OUTPUT -p ALL -s $OUT_IF_IP -j ACCEPT

# Log weird packets that don’t match the above.
$IPTABLES -A OUTPUT -m limit –limit 3/minute –limit-burst 3 -j LOG \
–log-level DEBUG –log-prefix “IPT OUTPUT packet died: “

# NAT table

# Enable simple IP Forwarding and Network Address Translation for interfaces eth1 and #eth2

$IPTABLES -t nat -A POSTROUTING -o $OUT_IF -s $INT_IF_NET1 -j SNAT –to-source $OUT_IF_IP
$IPTABLES -t nat -A POSTROUTING -o $OUT_IF -s $INT_IF_NET2 -j SNAT –to-source $OUT_IF_IP

#For Squid Transproxy
$IPTABLES -t nat -A PREROUTING -i $INT_IF1 -p tcp –dport 80 -j REDIRECT –to-ports 3128
$IPTABLES -t nat -A PREROUTING -i $INT_IF2 -p tcp –dport 80 -j REDIRECT –to-ports 3128

echo “Firewalling Established ! ……”

Leave a Reply