Saturday, July 2, 2011

Configuring a Linux Firewall using Iptables

Overview
This page will describe how I set up the IPTable Firewall Scripts for Linux 2.4 or later. This is not a How-To, it will not attempt to teach you anything about IPTables, these are just scripts you can use that I know to work, and work well. These scripts are what I usually use when setting up firewall computers.

The Scripts
I use 3 different scripts to initiate/deactivate the firewall services for Linux.
A pre.firewall script that will deny everything that comes in on the Internet. I initiate this before any network interfaces come up so when the network comes up it is protected in case, for any reason, the main firewall script fails to initialize.
A rc.firewall script as the main script to initiate all the firewall and masquerading services needed to run on the network. Basically what this script will do is allow anyone on the internal network to access all the services of the internet, but anyone from the outside cannot access the internal network, unless someone on the internal network initiates the communication.
Finally a script to flush all the IPTables at shutdown, or whenever you make changes to the main script.
In order for IPTables to work properly, you must have all the required Kernel modules available, they are listed in the main rc.iptables script. Most Linux Distributions will already provide these within their default kernels.

The pre.firewalls Script

#################################################################
#!/bin/sh                                                       #
#                                                               #
# start firewall support before ethernet card initialize        #
#################################################################

echo "Starting Pre-Firewalling..."

iptables -F
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

#################################################################


As you can see, there really isn't much to this script. All it basically does is Drops all traffic going in or coming out of the Linux box. Some people would consider this extremely paranoid behavior, but this will secure the network in case the rc.firewall script does not initialize.

To use this script, what I do is to copy it to the /etc/rc.d/init.d directory, make it executable (chmod +x pre.firewalls) then link it to whatever runlevel you want to run it under. The following command explains the symbolic link.

ln -s /etc/rc.d/init.d/pre.firewalls /etc/rc.d/rc3.d/S01preiptables

The flsh.iptables Script

#################################################################
#!/bin/sh                                                       #
#                                                               #
#              Script to flush the firewall tables              #
#################################################################
echo "Flushing Firewall and Deleting Chains"

iptables -F icmp_packets
iptables -F tcp_packets
iptables -F udpincoming_packets
iptables -F allowed
iptables -F

iptables -X icmp_packets
iptables -X tcp_packets
iptables -X udpincoming_packets
iptables -X allowed

iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

#################################################################


All this script does is to get rid of all the custom tables you 
create with my rc.firewall script, as well as making the default action to Drop all traffic on the Linux box. You should use this script when you shut down the computer. You should also use this script whenever you make any changes to the rc.firewall script so that you start with a clean slate. The following is a command to allow this script to run every time you shutdown your computer. You should also make a symbolic link to /usr/bin or anywhere else in your path to allow for easy flushing of the firewall.

ln -s /etc/rc.d/init.d/flsh.iptables /etc/rc.d/rc0.d/S01flshiptables

ln -s /etc/rc.d/init.d/flsh.iptables /usr/bin/flsh.iptables

The rc.firewall Script
#################################################################
#!/bin/sh
###################################
#                                     
# IP Firewall script with NAT for       
# Dual-Homed Linux Servers                
#################################################################

# Configuration Options

EXTERNAL_INTERFACE="eth0"
LOOPBACK_INTERFACE="lo"
LAN_INTERFACE_1="eth1"
IPTABLES_CMD="/sbin/iptables"

# Load needed Modules
/sbin/modprobe ip_tables
/sbin/modprobe ip_conntrack
/sbin/modprobe iptable_filter
/sbin/modprobe iptable_mangle
/sbin/modprobe iptable_nat
/sbin/modprobe ipt_LOG
/sbin/modprobe ipt_limit
/sbin/modprobe ipt_state
/sbin/modprobe ipt_REJECT
#/sbin/modprobe ipt_MASQUERADE
/sbin/modprobe ip_conntrack_ftp
/sbin/modprobe ip_conntrack_irc
/sbin/modprobe ip_nat_ftp
/sbin/modprobe ip_nat_irc
# /sbin/modprobe ipt_owner

# Get the IP Addresses for the network cards
IPADDR=`/sbin/ifconfig $EXTERNAL_INTERFACE | grep -i "addr:" | cut -f2 -d: | cut -f1 -d " "`
LAN_IPADDR=`/sbin/ifconfig $LAN_INTERFACE_1 | grep -i "addr:" | cut -f2 -d: | cut -f1 -d " "`
LOCALHOST_IP="127.0.0.1/32"
LAN_BCAST_ADDRESS=`/sbin/ifconfig $LAN_INTERFACE_1 | grep -i "Bcast:" | cut -f3 -d: | cut -f1 -d " "`

##########

echo "Starting Firewalling... "
echo "1" > /proc/sys/net/ipv4/ip_forward
# clear existing Tables/Chains
$IPTABLES_CMD -F
$IPTABLES_CMD -X

########## Set default policies
$IPTABLES_CMD -P INPUT DROP
$IPTABLES_CMD -P OUTPUT DROP
$IPTABLES_CMD -P FORWARD DROP
$IPTABLES_CMD -A INPUT -i $LOOPBACK_INTERFACE -j ACCEPT
$IPTABLES_CMD -A OUTPUT -o $LOOPBACK_INTERFACE -j ACCEPT

########## Prerouting chain - Check for obviously spoofed IP's don't use during testing between private networks
##########    add problem Internet IP Addresses here to drop (attempted breakins, etc.)
# $IPTABLES_CMD -t nat -A PREROUTING -i $EXTERNAL_INTERFACE -s 192.168.0.0/24 -j DROP
# $IPTABLES_CMD -t nat -A PREROUTING -i $EXTERNAL_INTERFACE -s 10.0.0.0/8 -j DROP
# $IPTABLES_CMD -t nat -A PREROUTING -i $EXTERNAL_INTERFACE -s 172.16.0.0/12 -j DROP

########## Port Forwarding in Prerouting Chain
# Example of Port Forwarding, first allow the specific FORWARD connection, then reroute it
# $IPTABLES_CMD -A FORWARD -p TCP -i $EXTERNAL_INTERFACE --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
# $IPTABLES_CMD -A PREROUTING -p TCP -t nat -d $IPADDR --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j DNAT --to 10.0.0.2:80

########## Drop certain bad packets
$IPTABLES_CMD -N bad_tcp_packets
$IPTABLES_CMD -A bad_tcp_packets -p tcp --tcp-flags SYN,ACK Syn,ACK -m state --state NEW -j REJECT --reject-with tcp-reset
$IPTABLES_CMD -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "NEW not syn:"
$IPTABLES_CMD -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j DROP
$IPTABLES_CMD -A INPUT -p tcp -j bad_tcp_packets

########## Ensure LAN ADDR aren't blocked
$IPTABLES_CMD -A INPUT -p ALL -i $LAN_INTERFACE_1 -d $LAN_BCAST_ADDRESS -j ACCEPT
$IPTABLES_CMD -A INPUT -p ALL -d $LOCALHOST_IP -j ACCEPT
$IPTABLES_CMD -A INPUT -p ALL -d $LAN_IPADDR -j ACCEPT
$IPTABLES_CMD -A INPUT -p ALL -d $IPADDR -m state --state ESTABLISHED,RELATED -j ACCEPT

########## Create chains for each packet type
##########     and filter the packets onto the correct chains.
$IPTABLES_CMD -N icmp_packets
$IPTABLES_CMD -N tcp_packets
$IPTABLES_CMD -N udpincoming_packets
$IPTABLES_CMD -A INPUT -p ICMP -i $EXTERNAL_INTERFACE -j icmp_packets
$IPTABLES_CMD -A INPUT -p TCP -i $EXTERNAL_INTERFACE -j tcp_packets
$IPTABLES_CMD -A INPUT -p UDP -i $EXTERNAL_INTERFACE -j udpincoming_packets

########## The Allowed Chain for TCP connections
$IPTABLES_CMD -N allowed
$IPTABLES_CMD -A allowed -p TCP --syn -j ACCEPT
$IPTABLES_CMD -A allowed -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES_CMD -A allowed -p TCP -j DROP

########## Open ICMP rules (Internet Control Message Protocol)

$IPTABLES_CMD -A icmp_packets -p ICMP -s 0/0 --icmp-type 0 -j ACCEPT
$IPTABLES_CMD -A icmp_packets -p ICMP -s 0/0 --icmp-type 3 -j ACCEPT
$IPTABLES_CMD -A icmp_packets -p ICMP -s 0/0 --icmp-type 5 -j ACCEPT
$IPTABLES_CMD -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -j ACCEPT
$IPTABLES_CMD -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT

########## Open TCP rules (Transmission Control Protocol)
### FTP port
 $IPTABLES_CMD -A tcp_packets -p TCP -i $EXTERNAL_INTERFACE -s 0/0 --dport 21 -j allowed
### SSH port
$IPTABLES_CMD -A tcp_packets -p TCP -i $EXTERNAL_INTERFACE -s 0/0 --dport 22 -j allowed
### SMTP Mail Server port
# $IPTABLES_CMD -A tcp_packets -p TCP -i $EXTERNAL_INTERFACE -s 0/0 --dport 25 -j allowed
### DNS port
$IPTABLES_CMD -A tcp_packets -p tcp -i $EXTERNAL_INTERFACE -s 0/0 --dport 53 -j allowed
### HTTP port
# $IPTABLES_CMD -A tcp_packets -p tcp -i $EXTERNAL_INTERFACE -s 0/0 --dport 80 -j allowed
### POP3 port
# $IPTABLES_CMD -A tcp_packets -p TCP -i $EXTERNAL_INTERFACE -s 0/0 --dport 110 -j allowed
### IRC port
# $IPTABLES_CMD -A tcp_packets -p TCP -i $EXTERNAL_INTERFACE -s 0/0 --dport 113 -j allowed
### IMAP port
# $IPTABLES_CMD -A tcp_packets -p TCP -i $EXTERNAL_INTERFACE -s 0/0 --dport 143 -j allowed

########## Open UDP ports (User Datagram Protocol)
### DNS
$IPTABLES_CMD -A udpincoming_packets -p UDP -i $EXTERNAL_INTERFACE -s 0/0 --source-port 53 -j ACCEPT
### NTP
$IPTABLES_CMD -A udpincoming_packets -p UDP -i $EXTERNAL_INTERFACE -s 0/0 --source-port 123 -j ACCEPT
### IMAP
$IPTABLES_CMD -A udpincoming_packets -p UDP -i $EXTERNAL_INTERFACE -s 0/0 --source-port 143 -j ACCEPT

#### Enable to log INPUT errors That didn't match anything above
$IPTABLES_CMD -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT INPUT packet died: "

########## FORWARD RULES
$IPTABLES_CMD -A FORWARD -p tcp -j bad_tcp_packets
$IPTABLES_CMD -A FORWARD -i $LAN_INTERFACE_1 -j ACCEPT
$IPTABLES_CMD -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES_CMD -A FORWARD -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT FORWARD packet died: "

########## OUTPUT chain # Establish the basic Output chain
$IPTABLES_CMD -A OUTPUT -p tcp -j bad_tcp_packets
$IPTABLES_CMD -A OUTPUT -p ALL -s $LOCALHOST_IP -j ACCEPT
$IPTABLES_CMD -A OUTPUT -p ALL -s $LAN_IPADDR -j ACCEPT
$IPTABLES_CMD -A OUTPUT -p ALL -s $IPADDR -j ACCEPT
$IPTABLES_CMD -A OUTPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT OUTPUT packet died: "

########## Enable SNAT / Masquerading
# If you want to use Masquerading instead of SNAT
# $IPTABLES_CMD -t nat -A POSTROUTING -o $EXTERNAL_INTERFACE -j MASQUERADE
$IPTABLES_CMD -t nat -A POSTROUTING -o $EXTERNAL_INTERFACE -j SNAT --to-source $IPADDR

To make this automatically run at startup you could make a symbolic link from /etc/rc.d/init.d/rc.iptables to /etc/rc.d/rc3.d/S15iptables. This should work for any Internet connection, static or DHCP. Just ensure you specify the correct NICs for each connection in the script.
As you can see in the script, I have allowed certain services to access to the firewall computer, like the http or ssh servers. You can add your own services that you want to allow access to, just experiment.

No comments:

Post a Comment