Aerospace



Home

Company Information

Information Request

Linux How-to Guides

ADSP 21xx
Digital Signal Processing
Tutorials

SW Utilities

On-line Order Form

Aerospace Projects

Commercial Projects

Circuit Boards

Server Support


Bonk

Have you found this site useful? Did we save you time? Did we cure your head-ache? Is your hair growing back now?

Please make a donation to help with maintenance.


Firewall Howto

For Mandrake Linux 10.2, Limited Edition 2005

May 2005

Herman Oosthuysen

Copyright 2003, 2005, Aerospace Software Ltd., GPL.


General

A friend asked me: How do I enable a firewall?

Eeeep... I can write a book about that question, but I tried my best not to. This guide was my answer.


Shorewall

Mandrake comes with the Shorewall script and wizard, which is good, but I find it to be totally incomprehensible. It is just way too complicated, since it tries to cater for everything, but all it is, is an IPtables configuration script, so being bloody minded, I use my own...

If you are less adventurous than me, then you can use Webmin to manage Shorewall - I have used Webmin with Shorewall a few times and it works well. Another option is to use the Firestarter firewall. Note that when you install Shorewall, it defaults to inactive, while Firestarter defaults to active and everything blocked. Therefore, if you would install Firestarter from an RPM on a remote machine, then you will instantly lock yourself out!

See the end of this guide for a safety mechanism to use when experimenting on a remote machine.


Basics

To do a firewall, you need at least two NICs of course. Most configurations will use eth0 as the WAN port and eth1 as the LAN port. This example follows this convention. Read the attached rc.firewall script carefully and change a few things for your configuration - it should be reasonably obvious.

You may need to set the WAN MAC address to a specific value to keep your DSL supplier happy, in /etc/rc.d/rc.local. This forces the Linux server to use the MAC address of the network adaptor that was originally used to provision the DSL line:

  • ## Configure the ADSL ethernet port with a specific HW address
  • service network stop
  • ifconfig eth1 hw ether 00:20:78:d9:c3:c8
  • service network start

Multiple layers in the Onion

There are mainly two software packages involved with firewalling: IPtables and TCPwrappers. First of all deactivate TCPwrappers. In /etc/hosts.allow put the line:

  • ALL: ALL

for starters as the first rule to open tcpwrappers wide. You can close it up again later.

Here is my /etc/rc.d/rc.firewall script.

It is based on a Redhat script that I got on the web (thanks to whoever wrote the original). I had to hack it a bit to make it work better, but on the whole it is much the same.

The advantage of this over an abomination like Shorewall, is that it is a single file - plain and simple. Shorewall has its place in the universe, but golly Miss Molly, simple it ain't...

Start reading at the top and work your way to the bottom. Once you get out the other side, you'll have a fair understanding of iptables. Note that the order in which the rules are written matters. Once a matching rule is found, the packet is delivered and it exits.

Copy the text below into /etc/rc.d/rc.firewall and make it executable:

#!/bin/sh
#
# rc.firewall
#
# Aerospace:
FWVER=0.83

#          Original by Redhat - Modified by Aerospace Software Ltd.
#          http://www.AerospaceSoftware.com
#
#          An example of a stronger IPTABLES firewall with IP Masquerade 
#          support for 2.4.x kernels.  
#
# Log:
#
#   0.82  - Aerospace: Open things up for external email to mail.aeronetworks.ca
#   0.82  - Aerospace: Add Windows spamware blocking
#   0.81  - Aerospace: Add Windows worm rules
#   0.80  - Aerospace: Modify for Oosthuysen Omura
#   0.80  - Aerospace: Add protection for MS Windows Hosts and forward ports
#           Load iptable_mangle module for Port Forwarding.
#   0.79s - ruleset now uses modprobe instead of insmod
#   0.78s - REJECT is not a legal policy yet; back to DROP
#   0.77s - Changed the default block behavior to REJECT not DROP
#   0.76s - Added a comment about the OPTIONAL WWW ruleset and a comment
#           where to put optional PORTFW commands
#   0.75s - Added clarification that PPPoE users need to use
#           "ppp0" instead of "eth0" for their external interface
#   0.74s - Changed the EXTIP command to work on NON-English distros
#   0.73s - Added comments in the output section that DHCPd is optional
#           and changed the default settings to disabled
#   0.72s - Changed the filter from the INTNET to the INTIP to be
#           stateful; moved the command VARs to the top and made the
#           rest of the script to use them
#   0.70s - Added a disabled examples for allowing internal DHCP  
#           and external WWW access to the server
#   0.63s - Added support for the IRC module
#   0.62s - Initial version based upon the basic 2.4.x rc.firewall


echo -e "\nLoading rc.firewall - version $FWVER..\n"


# The location of various iptables and other shell programs
#
#   If your Linux distribution came with a copy of iptables, most
#   likely it is located in /sbin.  If you manually compiled 
#   iptables, the default location is in /usr/local/sbin
#
# ** Please use the "whereis iptables" command to figure out 
# ** where your copy is and change the path below to reflect 
# ** your setup
#
# Aerospace:
IPTABLES=/sbin/iptables
#IPTABLES=/usr/local/sbin/iptables
#
LSMOD=/sbin/lsmod
DEPMOD=/sbin/depmod
MODPROBE=/sbin/modprobe
GREP=/bin/grep
AWK=/bin/awk
SED=/bin/sed
IFCONFIG=/sbin/ifconfig


#Setting the EXTERNAL and INTERNAL interfaces for the network
#
#  Each IP Masquerade network needs to have at least one
#  external and one internal network.  The external network
#  is where the natting will occur and the internal network
#  should preferably be addressed with a RFC1918 private address
#  scheme.
#
#  For this example, "eth0" is external and "eth1" is internal"
#
#  NOTE:  If this doesnt EXACTLY fit your configuration, you must 
#         change the EXTIF or INTIF variables above. For example: 
#
#            If you are a PPPoE or analog modem user:
#
#               EXTIF="ppp0" 
#
# Aerospace:
EXTIF="eth0"
INTIF="eth1"
echo "  External Interface:  $EXTIF"
echo "  Internal Interface:  $INTIF"
echo "  ---"

# Specify your Static IP address here or let the script take care of it 
# for you.
#
#   If you prefer to use STATIC addresses in your firewalls, un-# out the
#   static example below and # out the dynamic line.  If you don't care,
#   just leave this section alone.
#
#   If you have a DYNAMIC IP address, the ruleset already takes care of
#   this for you.  Please note that the different single and double quote 
#   characters and the script MATTER.
#
#
#   DHCP users:
#   -----------
#   If you get your TCP/IP address via DHCP, **you will need ** to enable the 
#   #ed out command below underneath the PPP section AND replace the word 
#   "eth0" with the name of your EXTERNAL Internet connection (ppp0, ippp0, 
#   etc) on the lines for "ppp-ip" and "extip".  You should also note that the 
#   DHCP server can and will change IP addresses on you.  To deal with this, 
#   users should configure their DHCP client to re-run the rc.firewall ruleset 
#   everytime the DHCP lease is renewed.
#
#     NOTE #1:  Some DHCP clients like the original "pump" (the newer
#               versions have been fixed) did NOT have the ability to run 
#               scripts after a lease-renew.  Because of this, you need to 
#               replace it with something like "dhcpcd" or "dhclient".
#
#     NOTE #2:  The syntax for "dhcpcd" has changed in recent versions.
#
#               Older versions used syntax like:
#                         dhcpcd -c /etc/rc.d/rc.firewall eth0
#
#               Newer versions execute a file called /etc/dhcpc/dhcpcd-eth0.exe
#
#     NOTE #3:  For Pump users, put the following line in /etc/pump.conf:
#
#                   script /etc/rc.d/rc.firewall
#
#   PPP users:
#   ----------
#   If you aren't already aware, the /etc/ppp/ip-up script is always run when 
#   a PPP connection comes up.  Because of this, we can make the ruleset go and 
#   get the new PPP IP address and update the strong firewall ruleset.
#
#   If the /etc/ppp/ip-up file already exists, you should edit it and add a line
#   containing "/etc/rc.d/rc.firewall" near the end of the file.
#
#   If you don't already have a /etc/ppp/ip-up sccript, you need to create the 
#   following link to run the /etc/rc.d/rc.firewall script.
#
#       ln -s /etc/rc.d/rc.firewall /etc/ppp/ip-up
#
#   * You then want to enable the #ed out shell command below *
#
#
# Determine the external IP automatically:
# ----------------------------------------
#
#  The following line will determine your external IP address.  This
#  line is somewhat complex and confusing but it will also work for
#  all NON-English Linux distributions:
#
EXTIP="`$IFCONFIG $EXTIF | $AWK \
 /$EXTIF/'{next}//{split($0,a,":");split(a[2],a," ");print a[1];exit}'`"


# For users who wish to use STATIC IP addresses:
#
#  # out the EXTIP line above and un-# out the EXTIP line below
#
#EXTIP="your.static.PPP.address"
echo "  External IP: $EXTIP"
echo "  ---"


# Assign the internal TCP/IP network and IP address
# Aerospace:
INTNET="192.168.1.0/24"
INTIP="192.168.1.1/24"
echo "  Internal Network: $INTNET"
echo "  Internal IP:      $INTIP"
echo "  ---"




# Setting a few other local variables
#
UNIVERSE="0.0.0.0/0"

#======================================================================
#== No editing beyond this line is required for initial MASQ testing ==

# Need to verify that all modules have all required dependencies
#
echo "  - Verifying that all kernel modules are ok"
$DEPMOD -a

echo -en "    Loading kernel modules: "

# With the new IPTABLES code, the core MASQ functionality is now either
# modular or compiled into the kernel.  This HOWTO shows ALL IPTABLES
# options as MODULES.  If your kernel is compiled correctly, there is
# NO need to load the kernel modules manually.  
#
#  NOTE: The following items are listed ONLY for informational reasons.
#        There is no reason to manual load these modules unless your
#        kernel is either mis-configured or you intentionally disabled
#        the kernel module autoloader.
#

# Upon the commands of starting up IP Masq on the server, the
# following kernel modules will be automatically loaded:
#
# NOTE:  Only load the IP MASQ modules you need.  All current IP MASQ 
#        modules are shown below but are commented out from loading.
# ===============================================================

#Load the main body of the IPTABLES module - "ip_tables"
#  - Loaded automatically when the "iptables" command is invoked
#
#  - Loaded manually to clean up kernel auto-loading timing issues
#
echo -en "ip_tables, "
#
#Verify the module isn't loaded.  If it is, skip it
#
if [ -z "` $LSMOD | $GREP ip_tables | $AWK {'print $1'} `" ]; then
   $MODPROBE ip_tables
fi


#Load the IPTABLES filtering module - "iptable_filter" 
#
#  - Loaded automatically when filter policies are activated


#Load the stateful connection tracking framework - "ip_conntrack"
#
# The conntrack  module in itself does nothing without other specific 
# conntrack modules being loaded afterwards such as the "ip_conntrack_ftp"
# module
#
#  - This module is loaded automatically when MASQ functionality is 
#    enabled 
#
#  - Loaded manually to clean up kernel auto-loading timing issues
#
echo -en "ip_conntrack, "
#
#Verify the module isn't loaded.  If it is, skip it
#
if [ -z "` $LSMOD | $GREP ip_conntrack | $AWK {'print $1'} `" ]; then
   $MODPROBE ip_conntrack
fi


#Load the FTP tracking mechanism for full FTP tracking
#
# Enabled by default -- insert a "#" on the next line to deactivate
#
echo -e "ip_conntrack_ftp, "
#
#Verify the module isn't loaded.  If it is, skip it
#
if [ -z "` $LSMOD | $GREP ip_conntrack_ftp | $AWK {'print $1'} `" ]; then
   $MODPROBE ip_conntrack_ftp
fi


#Load the IRC tracking mechanism for full IRC tracking
#
# Enabled by default -- insert a "#" on the next line to deactivate
#
echo -en "                             ip_conntrack_irc, "
#
#Verify the module isn't loaded.  If it is, skip it
#
if [ -z "` $LSMOD | $GREP ip_conntrack_irc | $AWK {'print $1'} `" ]; then
   $MODPROBE ip_conntrack_irc
fi


#Load the general IPTABLES NAT code - "iptable_nat"
#  - Loaded automatically when MASQ functionality is turned on
# 
#  - Loaded manually to clean up kernel auto-loading timing issues
#
echo -en "iptable_nat, "
#
#Verify the module isn't loaded.  If it is, skip it
#
if [ -z "` $LSMOD | $GREP iptable_nat | $AWK {'print $1'} `" ]; then
   $MODPROBE iptable_nat
fi


#Loads the FTP NAT functionality into the core IPTABLES code
# Required to support non-PASV FTP.
#
# Enabled by default -- insert a "#" on the next line to deactivate
#
echo -e "ip_nat_ftp"
#
#Verify the module isn't loaded.  If it is, skip it
#
if [ -z "` $LSMOD | $GREP ip_nat_ftp | $AWK {'print $1'} `" ]; then
   $MODPROBE ip_nat_ftp
fi

echo "  ---"

# Just to be complete, here is a list of the remaining kernel modules 
# and their function.  Please note that several modules should be only
# loaded by the correct master kernel module for proper operation.
# --------------------------------------------------------------------
#
#    ipt_mark       - this target marks a given packet for future action.
#                     This automatically loads the ipt_MARK module
#
#    ipt_tcpmss     - this target allows to manipulate the TCP MSS
#                     option for braindead remote firewalls.
#                     This automatically loads the ipt_TCPMSS module
#
#    ipt_limit      - this target allows for packets to be limited to
#                     to many hits per sec/min/hr
#
#    ipt_multiport  - this match allows for targets within a range
#                     of port numbers vs. listing each port individually
#
#    ipt_state      - this match allows to catch packets with various
#                     IP and TCP flags set/unset
#
#    ipt_unclean    - this match allows to catch packets that have invalid
#                     IP/TCP flags set
#
#    iptable_filter - this module allows for packets to be DROPped, 
#                     REJECTed, or LOGged.  This module automatically 
#                     loads the following modules:
#
#                     ipt_LOG - this target allows for packets to be 
#                               logged
#
#                     ipt_REJECT - this target DROPs the packet and returns 
#                                  a configurable ICMP packet back to the 
#                                  sender.
# 
#    iptable_mangle - this target allows for packets to be manipulated
#                     for things like the TCPMSS option, etc.  ALSO USED
#                     FOR PORT FORWARDING!!!


#CRITICAL:  Enable IP forwarding since it is disabled by default since
#
#           Redhat Users:  you may try changing the options in
#                          /etc/sysconfig/network from:
#
#                       FORWARD_IPV4=false
#                             to
#                       FORWARD_IPV4=true
#
echo "  Enabling forwarding.."
echo "1" > /proc/sys/net/ipv4/ip_forward


# Dynamic IP users:
#
#   If you get your IP address dynamically from SLIP, PPP, or DHCP, 
#   enable the following option.  This enables dynamic-address hacking
#   which makes the life with Diald and similar programs much easier.
#
echo "  Enabling DynamicAddr.."
echo "1" > /proc/sys/net/ipv4/ip_dynaddr

echo "  ---"

#############################################################################
#
# Enable Stronger IP forwarding and Masquerading
#
#  NOTE:  In IPTABLES speak, IP Masquerading is a form of SourceNAT or SNAT.
#
#  NOTE #2:  The following is an example for an internal LAN address in the
#            192.168.1.x network with a 255.255.255.0 or a "24" bit subnet 
#            mask connecting to the Internet on external interface "eth0".  
#            This example will MASQ internal traffic out to the Internet 
#            but not allow non-initiated traffic into your internal network.
#
#            
#         ** Please change the above network numbers, subnet mask, and your 
#         *** Internet connection interface name to match your setup
#         

#Clearing any previous configuration
#
#  Unless specified, the defaults for INPUT, OUTPUT, and FORWARD to DROP
#
#    You CANNOT change this to REJECT as it isn't a vaild policy setting.
#    If you want REJECT, you must explictly REJECT at the end of a giving 
#    INPUT, OUTPUT, or FORWARD chain
#
echo "  Clearing any existing rules and setting default policy to DROP.."
# Aerospace:
$IPTABLES -F INPUT 
$IPTABLES -F OUTPUT 
$IPTABLES -F FORWARD 
$IPTABLES -F -t nat
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT DROP
$IPTABLES -P FORWARD DROP

#Not needed and it will only load the unneeded kernel module
# Aerospace: This is needed for PORT FORWARDING
$IPTABLES -F -t mangle

#
# Flush the user chain.. if it exists
if [ -n "`$IPTABLES -L | $GREP drop-and-log-it`" ]; then
   $IPTABLES -F drop-and-log-it
fi
#
# Delete all User-specified chains
$IPTABLES -X
#
# Reset all IPTABLES counters
$IPTABLES -Z


#Configuring specific CHAINS for later use in the ruleset
#
#  NOTE:  Some users prefer to have their firewall silently
#         "DROP" packets while others prefer to use "REJECT"
#         to send ICMP error messages back to the remote 
#         machine.  The default is "REJECT" but feel free to
#         change this below.
#
# NOTE: Without the --log-level set to "info", every single
#       firewall hit will goto ALL vtys.  This is a very big
#       pain.
#
echo "  Creating a DROP chain.."
$IPTABLES -N drop-and-log-it
$IPTABLES -A drop-and-log-it -j LOG --log-level info 
$IPTABLES -A drop-and-log-it -j DROP

echo -e "\n   - Loading INPUT rulesets"


#######################################################################
# INPUT: Incoming traffic from various interfaces.  All rulesets are 
#        already flushed and set to a default policy of DROP. 
#

# loopback interfaces are valid.
#
$IPTABLES -A INPUT -i lo -s $UNIVERSE -d $UNIVERSE -j ACCEPT


# local interface, local machines, going anywhere is valid
#
$IPTABLES -A INPUT -i $INTIF -s $INTNET -d $UNIVERSE -j ACCEPT


# remote interface, claiming to be local machines, IP spoofing, get lost
#
$IPTABLES -A INPUT -i $EXTIF -s $INTNET -d $UNIVERSE -j drop-and-log-it


# external interface, from any source, for ICMP traffic is valid
#
#  If you would like your machine to "ping" from the Internet, 
#  enable this next line
#
#$IPTABLES -A INPUT -i $EXTIF -p ICMP -s $UNIVERSE -d $EXTIP -j ACCEPT

# Protect against DOS attacks - rate limit various ICMP messages
$IPTABLES -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j
ACCEPT
$IPTABLES -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT
$IPTABLES -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s
-j ACCEPT

# remote interface, any source, going to permanent PPP address is valid
#
#$IPTABLES -A INPUT -i $EXTIF -s $UNIVERSE -d $EXTIP -j ACCEPT


# Allow any related traffic coming back to the MASQ server in
#
$IPTABLES -A INPUT -i $EXTIF -s $UNIVERSE -d $EXTIP -m state --state \
 ESTABLISHED,RELATED -j ACCEPT


# ----- Begin OPTIONAL INPUT Section -----
#

# DHCPd - Enable the following lines if you run an INTERNAL DHCPd server
#
# Aerospace:
$IPTABLES -A INPUT -i $INTIF -p tcp --sport 68 --dport 67 -j ACCEPT
$IPTABLES -A INPUT -i $INTIF -p udp --sport 68 --dport 67 -j ACCEPT

# HTTPd - Enable the following lines if you run an EXTERNAL WWW server
#
#    NOTE:  This is NOT needed for simply enabling PORTFW.  This is ONLY 
#           for users that plan on running Apache on the MASQ server itself
#
#echo -e "      - Allowing EXTERNAL access to the WWW server"
#$IPTABLES -A INPUT -i $EXTIF -m state --state NEW,ESTABLISHED,RELATED \
# -p tcp -s $UNIVERSE -d $EXTIP --dport 80 -j ACCEPT

echo "   Allow ssh on port 22 in"
$IPTABLES -A INPUT -i $EXTIF -p tcp --dport ssh -j ACCEPT 
$IPTABLES -A INPUT -i $EXTIF -p udp --dport ssh -j ACCEPT

#echo "   Allow imap on port 143 in"
#$IPTABLES -A INPUT -i $EXTIF -p tcp --dport 143 -j ACCEPT
#$IPTABLES -A INPUT -i $EXTIF -p udp --dport 143 -j ACCEPT

echo "   Drop X connections from external on port 6000"
$IPTABLES -A INPUT -i $EXTIF -p tcp --dport 6000 -j drop-and-log-it

echo "   Drop Portmap connections from external on port 111"
$IPTABLES -A INPUT -i $EXTIF -p tcp --dport 111 -j drop-and-log-it

echo "   Drop RPC connections from external on port 799"
$IPTABLES -A INPUT -i $EXTIF -p tcp --dport 799 -j drop-and-log-it

#
# ----- End OPTIONAL INPUT Section -----



# Catch all rule, all other incoming is denied and logged. 
#
$IPTABLES -A INPUT -s $UNIVERSE -d $UNIVERSE -j drop-and-log-it


echo -e "   - Loading OUTPUT rulesets"

#######################################################################
# OUTPUT: Outgoing traffic from various interfaces.  All rulesets are 
#         already flushed and set to a default policy of DROP. 
#

# loopback interface is valid.
#
$IPTABLES -A OUTPUT -o lo -s $UNIVERSE -d $UNIVERSE -j ACCEPT


# local interfaces, any source going to local net is valid
#
$IPTABLES -A OUTPUT -o $INTIF -s $EXTIP -d $INTNET -j ACCEPT


# local interface, any source going to local net is valid
#
$IPTABLES -A OUTPUT -o $INTIF -s $INTIP -d $INTNET -j ACCEPT


# outgoing to local net on remote interface, stuffed routing, deny
#
$IPTABLES -A OUTPUT -o $EXTIF -s $UNIVERSE -d $INTNET -j drop-and-log-it


# anything else outgoing on remote interface is valid
#
$IPTABLES -A OUTPUT -o $EXTIF -s $EXTIP -d $UNIVERSE -j ACCEPT


# ----- Begin OPTIONAL OUTPUT Section -----
#

# DHCPd - Enable the following lines if you run an INTERNAL DHCPd server
#         - Remove BOTH #s all the #s if you need this functionality.
#
# Aerospace:
$IPTABLES -A OUTPUT -o $INTIF -p tcp -s $INTIP --sport 67 \
 -d 255.255.255.255 --dport 68 -j ACCEPT
$IPTABLES -A OUTPUT -o $INTIF -p udp -s $INTIP --sport 67 \
 -d 255.255.255.255 --dport 68 -j ACCEPT

#
# ----- End OPTIONAL OUTPUT Section -----


# Catch all rule, all other outgoing is denied and logged. 
#
$IPTABLES -A OUTPUT -s $UNIVERSE -d $UNIVERSE -j drop-and-log-it


echo -e "   - Loading FORWARD rulesets"

#######################################################################
# FORWARD: Enable Forwarding and thus IPMASQ
#

# ----- Begin OPTIONAL FORWARD Section -----
#
echo "   DNAT Forward port 81 for Expeditors on Hera"
$IPTABLES -A FORWARD -s 0/0 -i $EXTIF -d 192.168.10.11 -o $INTIF -p tcp \
   --dport 81 -j ACCEPT
$IPTABLES -A FORWARD -d 0/0 -o $EXTIF -s 192.168.10.11 -i $INTIF -p tcp \
   -m state --state ESTABLISHED,RELATED -j ACCEPT

#
# Aerospace:
# Block outgoing NetBios (if you have windows machines running
# on the private subnet).  This will not affect any NetBios
# traffic that flows over the VPN tunnel, but it will stop
# local windows machines from broadcasting themselves to
# the internet.
# Also block Windows Messenger pop-up advertisements.
echo "   Drop windoze NetBIOS and Messenger packets, ports 135:139, 445"
$IPTABLES -A FORWARD -p tcp --dport 135:139 -j drop-and-log-it
$IPTABLES -A FORWARD -p udp --dport 135:139 -j drop-and-log-it
$IPTABLES -A FORWARD -p tcp --dport 445 -j drop-and-log-it
$IPTABLES -A FORWARD -p udp --dport 445 -j drop-and-log-it

echo "   Drop Windoze SQL Slammer virus packets, ports 1434"
$IPTABLES -A FORWARD -p tcp --dport 1434 -j drop-and-log-it
$IPTABLES -A FORWARD -p udp --dport 1434 -j drop-and-log-it

echo "   Block the WindowsXP RPC DCOM worm ports 4444, 593, 69"
$IPTABLES -A FORWARD -p tcp --dport 4444 -j drop-and-log-it
$IPTABLES -A FORWARD -p udp --dport 4444 -j drop-and-log-it
$IPTABLES -A FORWARD -p tcp --dport 593 -j drop-and-log-it
$IPTABLES -A FORWARD -p udp --dport 593 -j drop-and-log-it
$IPTABLES -A FORWARD -p tcp --dport 69 -j drop-and-log-it
$IPTABLES -A FORWARD -p udp --dport 69 -j drop-and-log-it

# I wish I knew what the hell this is:
echo "   Block an unknown piece of crapware that talks to Asia Pacific"
$IPTABLES -I INPUT -s 210.65.231.206 -j DROP
$IPTABLES -I OUTPUT -d 210.65.231.206 -j DROP

echo "   Block CUPS to the outside"
$IPTABLES -I INPUT -i $EXTIF -p tcp --dport 631 -j DROP
$IPTABLES -I OUTPUT -o $EXTIF -p tcp --dport 631 -j DROP
$IPTABLES -I INPUT -i $EXTIF -p udp --dport 631 -j DROP
$IPTABLES -I OUTPUT -o $EXTIF -p udp --dport 631 -j DROP

echo "   Block MySQL to the outside"
$IPTABLES -I INPUT -i $EXTIF -p tcp --dport 3306 -j DROP



#
# Aerospace:
# Squid Transparent Proxying:
# Requires a special build of squid for this to work.
# You need to exclude localhost as a source, or else
# squid will redirect to itself.  For localhost, I usually exclude by
# interface (loopback) rather than by address.
# Now, you don't have to set the proxying on each and every browser.
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port
$PORT 
# echo "    Redirect outbound HTTP traffic to Squid"
# $IPTABLES -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port
3128

echo "   Prevent external access to Squid"
$IPTABLES -I INPUT -i $EXTIF -p tcp --dport 3128 -j DROP
$IPTABLES -I INPUT -i $EXTIF -p udp --dport 3128 -j DROP

#
# ----- End OPTIONAL FORWARD Section -----


echo "     - FWD: Allow all connections OUT and only existing/related IN"
$IPTABLES -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED \
 -j ACCEPT
$IPTABLES -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT

# Catch all rule, all other forwarding is denied and logged. 
#
$IPTABLES -A FORWARD -j drop-and-log-it


echo "     - NAT: Enabling SNAT (MASQUERADE) functionality on $EXTIF"
#
#More liberal form
$IPTABLES -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE
#
#Stricter form
#$IPTABLES -t nat -A POSTROUTING -o $EXTIF -j SNAT --to $EXTIP


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


echo -e "\nDone.\n"

Things to specifically look at above, include the protection against DOS attacks, port forwarding and blocked ports. I added rate limiting to certain ICMP messages to prevent SYN, spoofed SYN and Ping of Death style attacks and there is one port forwarding rule in the FORWARD section, which you can modify to suit your application, or comment out entirely.

Take the above script, put it in /etc/rc.d and run it:

  • # chmod 700 /etc/rc.d/rc.firewall
  • # /etc/rc.d/rc.firewall

Note: The script enables packet forwarding.


Initial Tests

Connect to the wild wild world and use some pings to test the firewall. With Linux, you can specify which port to use to send the pings on. Test both ways, from LAN to WAN and WAN to LAN.

Now add some rules to hosts.allow, or just comment out the ALL: ALL:

# hosts.allow This file describes the names of the hosts which are
# allowed to use the local INET services, as decided
# by the '/usr/sbin/tcpd' server.
#ALL: ALL
ALL: 192.168.10.
popper: LOCAL 127.0.0.1 192.168.10.
sendmail: LOCAL 127.0.0.1 192.168.10.
sshd: ALL
postfix: LOCAL 127.0.0.1 192.168.10.
mysqld: LOCAL 127.0.0.1 192.168.10.

Keep hosts.deny as:

# hosts.deny 
# This file describes the names of the hosts which are
# *not* allowed to use the local INET services, as decided
# by the '/usr/sbin/tcpd' server.
ALL:ALL

Hook-up

I hook the rc.firewall script into /etc/init.d/network, so that when you execute the command service network restart, the firewall will also be restarted. Put the link in etc/init.d/networkat the end of start), immediately before stop) as shown below:

...snip...

# IPv6 hook (post IPv4 start)
 	if [ "$NETWORKING_IPV6" = "yes" ]; then
 		if [ -x /etc/sysconfig/network-scripts/init.ipv6-global ]; then
 			/etc/sysconfig/network-scripts/init.ipv6-global start post
 		fi
 	fi

# Herman
	sleep 10
	/etc/rc.d/rc.firewall
	
        touch /var/lock/subsys/network
        ;;
  stop)
# If this is a final shutdown/halt, check for network FS,
# and unmount them even if the user didn't turn on netfs

...snip...

The sleep 10 ensures that the server will get its IP address from the ISP with dhclient, before the firewall script runs. I found that sometimes, things were slow and caused problems at startup. The delay took care of that.


Final Test and Network Traffic Analysis

Test your firewall using nmap to see which ports are open:

# nmap -sT -P0 -v -F 111.222.333.444

Use the IP address of eth0 for the nmap command above.

Investigate the open ports and shut down services that are not needed, or block the ports with a DROP command. This script keeps my machines safe, but don't make any assumptions regarding security, since it is easy to verify yourself.

I usually create a little script called /usr/local/bin/drop to cut off an attacking host:

#! /bin/bash
# Drop all communications to/from an annoying host
iptables -I INPUT -s $1 -j DROP

and another little script called /usr/local/bin/block:

#! /bin/bash
# Drop all communications on an annoying port
iptables -I INPUT -i eth0 --dport $1 -j DROP

With those two scripts, one can quickly sew up holes in the net.

You can see which processes are doing what on the network using netstat:

# netstat -pa
# netstat -tlpn
# netstat -ulpn

To see name resolution, opening sockets, writing/reading sockets, use strace:

# strace -e trace=network curl --head http://www.redhat.com

or simply monitor network traffic with tcpdump:

# tcpdump -l -i eth0 port 80

once you know what port to look at.


Speed-ups

The next thing to configure would be squid, the http proxy, to buffer web requests. It readily reduces the bandwidth consumption by 30%. Also consider running BIND as a slave server, since it will speed up page accesses enormously - instead of waiting 250ms for each address to resolve, a local instance of BIND will do that in less than 1ms.


Intrusion Protection

On a public machine, intrusion protection is a big concern. There are a few simple steps that you can take to effectively protect the machine. First of all, always use very long usernames and passwords. This makes it unlikely that an automated brute force script will get in. I use descriptive user names, like john.doe.example.com with password j0hnd033x4mpl3c0m$1234. These kind of things are easy to remember and easy to type in.

With SSH, don't allow protocol 1 and don't allow root logins. This is set in /etc/ssh/sshd.conf. You should also consider not using the default port 22 for SSH (or FTP), but rather use something like 2222. That is still easy to remember and will throw automated attacks off, since most automated attacks are very dumb and an equally dumb defense could be very effective!

Rate limiting of new connection attempts is a general method to make brute force attacks infeasible and slow down denial of service attacks. The above firewall script has some protection in the INPUT rules. It will allow a burst of 5 new connection attempts, then limit at a rate of 1 per second. This will exhaust the patience of any common scr1pt k1dd13.

Finally, consider doing some active protection using Snort, Sentry Tools or Denyhost - all available from SourceForge.net. However, note that automatic denial of hosts could potentially cause you to lock yourself out, or an attack from the script called 'Fuck Port Sentry' could add the whole world to the deny list. I once left PortSentry running for a few months and then found that there were over 10,000 addresses in /etc/hosts.deny. Therefore, you need to add a process that will periodically clear the denied hosts.


Working on a Remote Server

Maintenance of a remote server deserves special mention. How do you safely make modifications to a remote server, without running the risk of locking yourself out?

The problem being that you can easily make a mistake and cause iptables to block all network traffic, with the result that your remote SSH or Webmin session dies. You then have to phone the Server Farm support desk with your tail between your legs and ask them to please go and fix it...

The solution is to create a safety net using the 'at' daemon. At allows you to enter a bunch of commands for later execution. This is very convenient for construction of a safety net. A simple safety, is to flush all iptables rules, then set the default policies to ACCEPT:

# at now + 20 min [Enter]
at> iptables -F
at> iptables -P INPUT ACCEPT
at> iptables -P OUTPUT ACCEPT
at> iptables -P FORWARD ACCEPT
at> [CTRL-D]
#

After entering the above, you have twenty minutes to fix the firewall and delete the at job, otherwise it will trigger and flush netfilter for you, so you can recover from your booboo.

You can see the queued jobs with 'atq' and remove a job with 'atrm jobnumber'.

As you can gather, I did lock myself out of a machine on the other side of the world once. Fortunately I had the foresight to talk to the server farm help desk before I started, so when I had to make the inevitable call for help, they could get me going again very quickly. However, the experience made me think how to prevent that from happening again and the at (or cron) daemon has saved me on numerous occations since!



Copyright © 2005-2008, Aerospace Software Ltd., GPL.