Chapter 3. Setting up a firewall

As of this moment, we respond to any and all requests that are being directed at the machine. True - not much of anything is active at this point, as we have yet to actually install much of anything, and the administrative interface has been disabled for all external addresses.

Now is the time to install a basic firewall, and for that purpose we have something called Netfilter. This is a packet filtering firewall, and can introduce som basic security to our host.

This section will give a small example of a script to setup the basic firewall, but will not extensively describe how this works.

3.1. Installing Netfilter

As luck would have it - or foresight - iptables has already been installed at this point, so no actual installation is needed at this point.

3.2. Configuring a basic firewall

What we want to achieve in the first basic installation of the firewall is the following:

The following is an example of a basic firewall script:


#!/bin/bash
#
# Declare path
#
PATH=/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin
export PATH

#
# Load modules used by iptables
#
modprobe ip_tables
modprobe ip_nat_ftp
modprobe ip_conntrack_ftp


#
# Where de we find the iptables program
#
IPT=/sbin/iptables

#
# First we define the internal and external interfaces
#
INTERNALIF="eth0"
INTERNALIP="192.168.228.14"
INTERNALNET="192.168.228.0/24"
EXTERNALIF="eth0:1"
EXTERNALIP="192.168.100.14"
LOCALIF="lo"

#
# Define if what we have is virtual interface or a real interface.
# Virtual interfaces need to to block on IP instead of IF. This is
# because iptables doesn't really like virtual interfaces. 
#
# It's really a good idea to change this when going into production,
# so that it's the interface that's blocked, and not just the IP. This
# does of course require You to have 2 interfaces in Your host.
#
EXTERNAL=${EXTERNALIP}
INTERNAL=${INTERNALIF}

#
# The switch that's used by iptables.
#  -d : destination (used when using IP)
#  -i : interface (used when using a real interface)
#
# If You change EXTERNAL or INTERNAL, remember to change this also.
#
EXTSWITCH="-d"
INTSWITCH="-i"

#
# Service definitions
#
# service : name         = port (protocol)
# ----------------------------------------
# ping    : icmp-request 
#           icmp-reply
# ftp     : ftp          = 21 (tcp)
# ssh     : ssh          = 22 (tcp/udp)
# mail    : smtp         = 25 (tcp)
# web     : http         = 80 (tcp)
#

#
# What do we want to allow
#
ICMPOK="
	icmp:echo-request
	icmp:echo-reply
"
EXTPORTSOK="
	tcp:ssh
	tcp:ftp
"
#
# What don't we want the outside world to see (pretty much everything)
# This is used if You have a service that announces itself to god and
# everyone e.g. a printer server.
#
EXTPORTSDROP="
"

#
# Flush current iptables definitions
#
for TABLE in filter nat mangle; do
  $IPT -t $TABLE -F
  $IPT -t $TABLE -X
done
$IPT -P INPUT DROP
$IPT -P OUTPUT ACCEPT
$IPT -P FORWARD DROP

#
# Allow everything on the local interface
#
$IPT -t filter -A INPUT -i ${LOCALIF} -j ACCEPT

#
# filter INPUT for external interface
#
$IPT -t filter -A INPUT ${EXTSWITCH} ${EXTERNAL} -m state \
	--state ESTABLISHED,RELATED -j ACCEPT

#
# Start with the icmp protocols (special handling)
#
$IPT -t filter -A INPUT -p icmp -m state --state INVALID -j DROP
for ICMP in ${ICMPOK}; do
	PROTOCOL="${ICMP%%:*}"
	ICMPPORT="${ICMP##*:}"
	printf "Proto : %4.4s - Port : %-20s" "${PROTOCOL}" "${ICMPPORT}"
	$IPT -t filter \
	     -A INPUT \
	     ${EXTSWITCH} ${EXTERNAL} \
	     -p ${PROTOCOL} \
	     --icmp-type ${ICMPPORT} \
	     -j ACCEPT
	printf " : ACCEPT\n"
done

#
# Then udp and tcp protocols.
#
for INPUT in ${EXTPORTSOK}; do
	PROTOCOL=${INPUT%%:*}
	PORT=${INPUT##*:}
	printf "Proto : %4.4s - Port : %-20s" "${PROTOCOL}" "${PORT}"
	$IPT -t filter \
	     -A INPUT \
	     ${EXTSWITCH} ${EXTERNAL} \
	     -p ${PROTOCOL} \
	     --dport ${PORT} \
	     -m state --state NEW \
	     -j ACCEPT
	printf " : ACCEPT\n"
done
for INPUT in ${EXTPORTSDROP}; do
	PROTOCOL=${INPUT%%:*}
	PORT=${INPUT##*:}
	printf "Proto : %4.4s - Port : %-20s" "${PROTOCOL}" "${PORT}"
	$IPT -t filter \
	     -A INPUT \
	     ${EXTSWITCH} ${EXTERNAL} \
	     -p ${PROTOCOL} \
	     --dport ${PORT} \
	     -j DROP
	printf " : DROP\n"
done

#
# Drop new connections on external interface, log invalid packets and drop them.
#
$IPT -t filter -A INPUT ${EXTSWITCH} ${EXTERNAL} -m state --state NEW -j DROP
$IPT -t filter -A INPUT ${EXTSWITCH} ${EXTERNAL} -m state --state INVALID -j LOG
$IPT -t filter -A INPUT ${EXTSWITCH} ${EXTERNAL} -m state --state INVALID -j DROP

#
# filter INPUT for internal interface
#
$IPT -t filter -A INPUT ${INTSWITCH} ${INTERNAL} -j ACCEPT

#
# filter FORWARD
#
$IPT -t filter -A FORWARD ${EXTSWITCH} ${EXTERNAL} -m state --state NEW -j DROP
$IPT -t filter -A FORWARD ${EXTSWITCH} ${EXTERNAL} -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -t filter -A FORWARD ${EXTSWITCH} ${EXTERNAL} -m state --state INVALID -j LOG
$IPT -t filter -A FORWARD ${EXTSWITCH} ${EXTERNAL} -m state --state INVALID -j DROP
$IPT -t filter -A FORWARD ${INTSWITCH} ${INTERNAL} -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -t filter -A FORWARD ${INTSWITCH} ${INTERNAL} -m state --state INVALID -j LOG
$IPT -t filter -A FORWARD ${INTSWITCH} ${INTERNAL} -m state --state INVALID -j DROP

#
# Masquerading the internal net
#
$IPT -t nat -A POSTROUTING -o ${EXTERNAL} -s ${INTERNALNET} -d 0/0 -j MASQUERADE
#
# Enable IP forwarding
#
echo 1 > /proc/sys/net/ipv4/ip_forward

The script can also be found here

In later parts of this document, the script will be modified to accept/deny connections.

3.3. Starting the firewall at boot

The creator of the Debian /etc/init.d/iptables would really like to discourage use of his script. He recommends rolling Your own, or do anything but use his scripts...

For more on that, read /etc/default/iptables

For those of us who choose to ignore this sage advise, here is what we do...

Run the iptables.sh script. This will create Some rules for Your firewall (packet filter).


ember:~# iptables.sh
Proto : icmp - Port : echo-request         : ACCEPT
Proto : icmp - Port : echo-reply           : ACCEPT
Proto : icmp - Port : ssh                  : ACCEPT
Proto : icmp - Port : ftp                  : ACCEPT
ember:~#

These rules now needs to be saved:


ember:~# /etc/init.d/iptables save active
Saving iptables ruleset: save "active" with counters.
ember:~# /etc/init.d/iptables clear
Clearing iptables ruleset: default ACCEPT policy
ember:~# /etc/init.d/iptables save inactive
Saving iptables ruleset: save "active" with counters.
ember:~# 

And finally we need to execute the iptables init.d script at boot time, since this is not done per default:


ember:~# cd /etc/rc2.d
ember:~# ln -s ../init.d/iptables S15iptables

The last bit can also be accomplished by using the webmin interface for "SysV Init Configuration" in the "System" tab.

3.4. Enabling IP forwarding

As this is also a NAT firewall (Masquerading), we need to enable the IP forward option in /etc/network/options. Set the option to "yes", and we should be set.


ip_forward=yes
spoofprotect=yes
syncookies=no