The following firewall scripts will help you secure your web and db servers placed on the internet. The scenario is such that the MySQL db server is desired to receive db connections / traffic only from the web server. The following is the list of services running on each server:

Web Server (200.10.20.31): FTP, SSH, HTTP, HTTPS, SMTP, POP3, IMAP, POP3S, IMAPS, MySQL (for some local services[qmail/vpopmail])

DB Server (200.10.20.32): SSH, HTTP, HTTPS, MySQL (only to receive traffic from Web Server)

The following scripts are currently implemented on live servers so they are 100% tested. Still, USE THEM AT YOUR OWN RISK.

Below are two scripts (create as /etc/firewall.sh) , one for Web Server and one for DB server. And below them, a startup (init.d) script common for both.

WebServer :-

vi /etc/firewall.sh

#!/bin/bash

###########################################################################################
# Author: Muhammad Kamran Azeem (kamran _at_ wbitt _dot_ com)
# Created: 20080410
# Revision History: 20080706, 20080412
# Proposed implementation: On StandAlone web servers
# Current Implementation: StandAlone web server
###########################################################################################
#
Various tools:
# nmap -sU publichost # scans UDP ports
#
# The following reports total number of connections
# netstat -anp |grep ‘tcp\\|udp’ | awk ‘{print $5}’ | cut -d: -f1 | sort | uniq -c | sort -n
#
# Once system is secured, test your firewall with nmap or hping2 command:
# nmap -v -f FIREWALL-IP
# nmap -v -sX FIREWALL-IP
# nmap -v -sN FIREWALL-IP
# nmap -v -sS FIREWALL-IP
# hping2 -X FIREWALL-IP
# ping -f FIREWALL_IP
# ping -s 65507 192.168.0.230
#############################################################################################

# User configurable parameters - START - #############################################
#
# The Public interface of this server towards Internet:-
PUBLICIF=eth0
#
# The Public IP of this server (on $PUBLICIF) visible/accessable from the Internet:-
PUBLICIP=200.10.20.31

# The full path to the iptables program:-
IPTABLES=/sbin/iptables
#
# User configurable parameters - END - ###############################################

############ Load Modules - Start ##################################################
#
# Load FTP connection tracking module. Without it, FTP to this server will NOT work.
# Because we have DROPed all INPUT packets at the end of this firewall.
modprobe ip_conntrack_ftp
modprobe ip_conntrack
#
############# Load Modules - End ###################################################

###################### Kernel Parameters - Start ########################
#
# Various Kernel paramters which you can (also) setup in /etc/sysctl.conf
#
# This following enables source address verification,
# , which is inbuilt into Linux kernel itself.
# net.ipv4.conf.all.rp_filter = 1
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter

###################### Kernel Parameters - End ########################

$IPTABLES -F
$IPTABLES -t nat -F

# ports list:
# 22/tcp - SSH
# 25/tcp - SMTP
# 53/tcp - DNS
# 53/udp - DNS
# 80/tcp - HTTP
# 443/tcp - HTTPS
# 110/tcp - POP3
# 995/tcp - POP3S
# 143/tcp - IMAP
# 993/tcp - IMAPS
# 123/tcp - NTP
# 123/udp - NTP
# 199/tcp - SNMP
# 161/UDP - SNMP
# 3306/tcp - MySQL
# 8443/tcp - Plesk

# Setup default INPUT policy as DROP. This is dangerous incase of flushing the rules.
# Instead, look at the end of this file for other method.
# $IPTABLES -P INPUT DROP # <—- Don’t use this method.

# allow packets coming from the machine
$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A OUTPUT -o lo -j ACCEPT

# allow outgoing traffic
$IPTABLES -A OUTPUT -o $PUBLICIF -j ACCEPT

# Allow the following traffic only:-
$IPTABLES -A INPUT -i $PUBLICIF -p tcp -m multiport –dport 21,22,25,53,80,443,110,995,143,993 -j ACCEPT
$IPTABLES -A INPUT -i $PUBLICIF -p udp -m multiport –dport 53 -j ACCEPT

# Block spoofing

# $IPTABLES -A INPUT -s 127.0.0.0/8 -i ! lo -j DROP

# More sophisticated / wide ranged method is below:-

# Add your IP range/IPs here,
# Yes, I am sure that the last address has 16 bit subnet for a VALID reason
SPOOFLIST=”0.0.0.0/8 127.0.0.0/8 10.0.0.0/8 172.16.0.0/16 192.168.0.0/16 224.0.0.0/3”
for ip in $SPOOFLIST
do
$IPTABLES -A INPUT -i $PUBLICIF -s $ip -j DROP
done

# Stop bad packets
$IPTABLES -A INPUT -m state –state INVALID -j DROP

# Stop NMAP FIN/URG/PSH
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL FIN,URG,PSH -j DROP

# Stop Xmas Tree type scanning
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL ALL -j DROP
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

# Stop null scanning
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL NONE -j DROP

# Stop SYN/RST
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags SYN,RST SYN,RST -j DROP

# Stop SYN/FIN
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags SYN,FIN SYN,FIN -j DROP

# If the incoming SYN packets are not NEW, we need to DROP them:-
$IPTABLES -A INPUT -p tcp ! –syn -m state –state NEW -j DROP

# Stop ping flood attack

# DROP ICMP packets size larger than 56(84) bytes

iptables -A INPUT -p icmp –icmp-type echo-request -m length –length 85: -j REJECT –reject-with icmp-host-prohibited

# **The above works ! See two outputs below:
# [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 56
# PING yourdomain.com (1.2.3.4) 56(84) bytes of data.
# 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=1 ttl=42 time=1140 ms
# 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=2 ttl=42 time=799 ms
# …
# Just by increasing one byte in the packet size has resulted in packet DROPs. Alhumdulillah.
# [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 57
# PING yourdomain.com (1.2.3.4) 57(85) bytes of data.
# From www.yourdomain.com (1.2.3.4) icmp_seq=1 Destination Host Prohibited
# From www.yourdomain.com (1.2.3.4) icmp_seq=2 Destination Host Prohibited
# …

# Allow maximum two incoming ICMP packets per second
iptables -A INPUT -p icmp –icmp-type echo-request -m limit –limit 1/s -j ACCEPT

# Hopefuly spamassassin, NTP, Razor, DNS, DCCIFD, etc will keep working properly,
# because of the following two rules.
$IPTABLES -A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

# Setup the default INPUT policy as DROP. Note that -P for POLICY is NOT used below.
# Instead, since all desired traffic is allowed before these lines,
# we will just drop all of the other packets coming on $PUBLICIF

$IPTABLES -A INPUT -i eth0 -j DROP

exit 0

DB Server :-

vi /etc/firewall.sh

#!/bin/bash

#########################################################################
# Author: Muhammad Kamran Azeem (kamran _at_ wbitt _dot_ com)
# Created: 20080410
# Revision History: 20080706, 20080513
# Implemented on this server: 20080513
# Proposed implementation: On db servers
# Current implementation: Customized for this DB server
#########################################################################
#
Various tools:
# nmap -sU PUBLIChost # scans UDP ports
#
# The following reports total number of connections
# netstat -anp |grep ‘tcp\\|udp’ | awk ‘{print $5}’ | cut -d: -f1 | sort | uniq -c | sort -n

# Once system is secured, test your firewall with nmap or hping2 command:
# nmap -v -f FIREWALL-IP
# nmap -v -sX FIREWALL-IP
# nmap -v -sN FIREWALL-IP
# nmap -v -sS FIREWALL-IP
# hping2 -X FIREWALL-IP
# ping -f FIREWALL_IP
# ping -s 65507 FIREWALL_IP
##############################################################################################

# User configurable parameters - START - #############################################
#
# The Public interface of this server towards Internet:-
PUBLICIF=eth0
#
# The Public IP of this server (on $PUBLICIF) visible/accessable from the Internet. (Use ifconfig to find out):-
PUBLICIP=200.10.20.32

#
# The IP of WebServer accessing this machine/DB server
WEBSERVERIP=200.10.20.31

#
# The full path to the iptables program:-
IPTABLES=/sbin/iptables
#
# User configurable parameters - END - ###############################################

############ Load Modules - Start ##################################################
#
# Load FTP connection tracking module. Witihout it, FTP to this server will NOT work.
# Because we have DROPed all INPUT packets at the end of this firewall.

modprobe ip_conntrack_ftp
modprobe ip_conntrack
#
############# Load Modules - End ###################################################

###################### Kernel Parameters - Start ########################
#
# Various Kernel paramters which you can (also) setup in /etc/sysctl.conf
#
# This following enables source address verification,
# , which is inbuilt into Linux kernel itself.
# net.ipv4.conf.all.rp_filter = 1
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter

###################### Kernel Parameters - End ########################

$IPTABLES -F
$IPTABLES -t nat -F

# ports list:
# 22/tcp - SSH
# 25/tcp - SMTP
# 80/tcp - HTTP
# 443/tcp - HTTPS
# 110/tcp - POP3
# 995/tcp - POP3S
# 143/tcp - IMAP
# 993/tcp - IMAPS
# 123/tcp - NTP
# 123/udp - NTP
# 199/tcp - SNMP
# 161/UDP - SNMP
# 3306/tcp - MySQL

# Setup default INPUT policy as DROP. This is dangerous incase of flushing the rules.
# Instead, look at the end of this file for other method.
# $IPTABLES -P INPUT DROP # <—- Don’t use this method.

## allow packets coming from the machine
$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A OUTPUT -o lo -j ACCEPT

# allow outgoing traffic
$IPTABLES -A OUTPUT -o $PUBLICIF -j ACCEPT

# Allow the following traffic only:-
# The following are allowed to get traffic from all over the world:-
$IPTABLES -A INPUT -i $PUBLICIF -p tcp -m multiport –dport 21,22,80,443 -j ACCEPT

# And the following ports are only allowed to get traffic from $WEBSERVERIP
$IPTABLES -A INPUT -i $PUBLICIF -p tcp -s $WEBSERVERIP –dport 3306 -j ACCEPT

# Block spoofing

# $IPTABLES -A INPUT -s 127.0.0.0/8 -i ! lo -j DROP

# OR more sophisticated / wide ranged method is below:-

# Add your IP range/IPs here,
# Yes I am sure that the last address has 16 bit subnet for a VALID reason
SPOOFLIST=”0.0.0.0/8 127.0.0.0/8 10.0.0.0/8 172.16.0.0/16 192.168.0.0/16 224.0.0.0/3”
for ip in $SPOOFLIST
do
$IPTABLES -A INPUT -i $PUBLICIF -s $ip -j DROP
done

# Stop bad packets
$IPTABLES -A INPUT -m state –state INVALID -j DROP

# Stop NMAP FIN/URG/PSH
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL FIN,URG,PSH -j DROP

# Stop Xmas Tree type scanning
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL ALL -j DROP
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

# Stop null scanning
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags ALL NONE -j DROP

# Stop SYN/RST
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags SYN,RST SYN,RST -j DROP

# Stop SYN/FIN
$IPTABLES -A INPUT -i $PUBLICIF -p tcp –tcp-flags SYN,FIN SYN,FIN -j DROP

# If the incoming SYN packets are not NEW, we need to DROP them:-
$IPTABLES -A INPUT -p tcp ! –syn -m state –state NEW -j DROP

# Stop ping flood attack

# DROP ICMP packets size larger than 56(84) bytes :-
iptables -A INPUT -p icmp –icmp-type echo-request -m length –length 85: -j REJECT –reject-with icmp-host-prohibited

# The above works ! See two outputs below:
# [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 56
# PING yourdomain.com (1.2.3.4) 56(84) bytes of data.
# 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=1 ttl=42 time=1140 ms
# 64 bytes from www.yourdomain.com (1.2.3.4): icmp_seq=2 ttl=42 time=799 ms
# …
# Just by increasing one byte in the packet size has resulted in packet DROPs. Alhumdulillah.
# [kamran@kworkhorse ~]$ ping www.yourdomain.com -s 57
# PING yourdomain.com (1.2.3.4) 57(85) bytes of data.
# From www.yourdomain.com (1.2.3.4) icmp_seq=1 Destination Host Prohibited
# From www.yourdomain.com (1.2.3.4) icmp_seq=2 Destination Host Prohibited
# …

# Allow maximum two incoming ICMP packets per second
iptables -A INPUT -p icmp –icmp-type echo-request -m limit –limit 2/s -j ACCEPT

# Hopefuly spamassassin, NTP, Razor, DNS, DCCIFD, etc will keep working properly,
# because of the following two rules.
$IPTABLES -A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

# Setup the default INPUT policy as DROP. Note that -P for POLICY is NOT used below.
# Instead, since all desired traffic is allowed before these lines,
# we will just drop all of the other packets coming on $PUBLICIF

$IPTABLES -A INPUT -i eth0 -j DROP

exit 0

And now the startup (init.d) script to be used on both servers:-

Create as /etc/init.d/firewall

vi /etc/init.d/firewall
#!/bin/bash
# firewall Startup script for our personal firewall
#
# chkconfig: - 01 99
# description: Our own custom built firewall setup
# processname: firewall

# Source function library.
. /etc/rc.d/init.d/functions

prog=/etc/firewall.sh
lockfile=/var/lock/subsys/firewall
RETVAL=0

start() {
echo -n “Starting $prog: “
. /etc/firewall.sh
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch ${lockfile}
return $RETVAL
}

stop() {
echo -n $”Stopping $prog: “
/sbin/iptables -F
/sbin/iptables -t nat -F
/sbin/iptables -P INPUT ACCEPT
/sbin/iptables -A INPUT -i eth0 -p tcp –dport 22 -j ACCEPT
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f ${lockfile}
}

# See how we were called.
case “$1” in
start)
start
;;
stop)
stop
;;
status)
/sbin/iptables -L
;;
restart)
stop
start
;;
*)
echo $”Usage: $prog {start|stop|status|restart}”
RETVAL=3
esac

exit $RETVAL

Final steps:-

Make the three scripts executable by:

chmod +x /etc/firewall.sh /etc/init.d/firewall.sh

chkconfig –level 35 firewall on

That should be all.