#!/bin/sh
#
# firewall
#
# author: Seann Herdejurgen (seann@herdejurgen.com)
#
# date: September 2001
#
# chkconfig: 345 11 92
#
# description: custom iptables firewall script
#
# This firewall script utilizes Linux kernel 2.4.10+
# netfilter capabilities by using iptables 1.2.4 and
# some experimental firewalling features.
#
# Make sure the following kernel options are enabled:
#
#      CONFIG_IP_NF_IPTABLES=y
#      CONFIG_IP_NF_CONNTRACK=y
#      CONFIG_IP_NF_MATCH_LIMIT=m
#      CONFIG_IP_NF_MATCH_PSD=m
#      CONFIG_IP_NF_MATCH_STATE=m
#      CONFIG_IP_NF_MATCH_IPLIMIT=m
#      CONFIG_IP_NF_MATCH_STRING=m
#      CONFIG_IP_NF_FILTER=m
#      CONFIG_IP_NF_TARGET_REJECT=m
#      CONFIG_IP_NF_NAT=m
#      CONFIG_IP_NF_TARGET_MASQUERADE=m
#      CONFIG_IP_NF_TARGET_REDIRECT=m
#      CONFIG_IP_NF_MANGLE=m
#      CONFIG_IP_NF_TARGET_TOS=m
#      CONFIG_IP_NF_TARGET_LOG=m
#      CONFIG_IP_ROUTE_TOS=y
#      CONFIG_SYN_COOKIES=y
#
# Your network interfaces must be up prior to
# starting the firewall.
#

# Get IP address for network interface
getip() {
 ifconfig $1 | \
 awk -F: '/inet addr/ { print $2 }' | \
 awk '{ print $1 }';
}

# Disable firewall rules
firewalloff() {
 # Set default policies
 iptables -t filter -P INPUT ACCEPT
 iptables -t filter -P FORWARD ACCEPT
 iptables -t filter -P OUTPUT ACCEPT
 iptables -t nat -P PREROUTING ACCEPT
 iptables -t nat -P POSTROUTING ACCEPT
 iptables -t nat -P OUTPUT ACCEPT
 iptables -t mangle -P PREROUTING ACCEPT
 iptables -t mangle -P OUTPUT ACCEPT

 # Flush standard chains
 iptables -F -t filter
 iptables -F -t nat
 iptables -F -t mangle
 iptables -X -t filter
 iptables -X -t nat
}

# Enable firewall rules
firewallon() {

 # Define network interfaces
 #
 # This script allows for an internal network and
 # any number of external network interfaces.
 # The internal interface is eth0 and the external
 # interfaces are eth1 and eth2.
 #
 #           eth1 ---+----------.          internal
 # Internet          | firewall +--- eth0   network
 #           eth2 ---+----------'         10.0.0.0/24
 #
 INT_IFACE="eth0"
 EXT_IFACES="eth1 eth2"

 # Determine internal network subnet address
 #
 # iproute must be installed.  It is available from:
 #   ftp://ftp.inr.ac.ru/ip-routing/
 #
 INT_NET=`ip route | awk /$INT_IFACE/' { print $1 }'`

 # Set default policies
 iptables -t filter -P INPUT DROP
 iptables -t filter -P FORWARD DROP
 iptables -t filter -P OUTPUT DROP
 iptables -t nat -P PREROUTING ACCEPT
 iptables -t nat -P POSTROUTING ACCEPT
 iptables -t nat -P OUTPUT ACCEPT
 iptables -t mangle -P PREROUTING ACCEPT
 iptables -t mangle -P OUTPUT ACCEPT

 # Flush standard chains
 iptables -F -t filter
 iptables -F -t nat
 iptables -F -t mangle
 iptables -X -t filter
 iptables -X -t nat

 # Create DROPLOG chains
 iptables -t filter -N DROPLOG
 iptables -t filter -A DROPLOG -j LOG --log-level info
 iptables -t filter -A DROPLOG -j DROP
 iptables -t nat -N DROPLOG
 iptables -t nat -A DROPLOG -j LOG --log-level info
 iptables -t nat -A DROPLOG -j DROP

 # INPUT chain
 INPUT="iptables -t filter -A INPUT"

 # ACCEPT all traffic on loopback and internal network
 $INPUT -i lo -j ACCEPT
 $INPUT -i $INT_IFACE -j ACCEPT

 for EXT_IFACE in $EXT_IFACES; do

   IP=`getip $EXT_IFACE`

   # DROP HTTP packets related to CodeRed and Nimda
   # viruses silently
   $INPUT -i $EXT_IFACE -p tcp -d $IP --dport http \
     -m string --string "/default.ida?" -j DROP
   $INPUT -i $EXT_IFACE -p tcp -d $IP --dport http \
     -m string --string ".exe?/c+dir" -j DROP
   $INPUT -i $EXT_IFACE -p tcp -d $IP --dport http \
     -m string --string ".exe?/c+tftp" -j DROP

   # ACCEPT active FTP data connections
   $INPUT -m state --state RELATED -i $EXT_IFACE \
     -p tcp -d $IP --dport 1024: --sport ftp-data \
     -j ACCEPT

   # ACCEPT inbound DNS requests
   $INPUT -i $EXT_IFACE -p udp \
     -d $IP --dport domain -j ACCEPT

   # ACCEPT inbound NTP updates from time servers
   # tick.usno.navy.mil & tock.usno.navy.mil
   for timehost in 192.5.41.40 192.5.41.41; do
     $INPUT -i $EXT_IFACE -p udp -d $IP --dport ntp \
       -s $timehost --sport ntp -j ACCEPT
   done

   # ACCEPT inbound TCP connections for various
   # services found in /etc/services
   for service in ftp ssh smtp domain \
                  http auth ldap https; do
     $INPUT -m state --state NEW,ESTABLISHED \
       -i $EXT_IFACE -p tcp -d $IP --dport $service \
       -j ACCEPT
   done
   # domain is for DNS zone transfers
   # auth is for sendmail ident authentication

   # ACCEPT inbound ICMP packets
   $INPUT -m state --state NEW,ESTABLISHED,RELATED \
     -i $EXT_IFACE -p icmp -d $IP -j ACCEPT

   # ACCEPT return TCP/UDP traffic (stateful firewall)
   $INPUT -m state --state ESTABLISHED -i $EXT_IFACE \
     -p tcp -d $IP --dport 1024: -j ACCEPT
   $INPUT -m state --state ESTABLISHED -i $EXT_IFACE \
     -p udp -d $IP --dport 1024: -j ACCEPT

 done

 # DROP and log everything else
 $INPUT -j DROPLOG

 # FORWARD chain
 FORWARD="iptables -t filter -A FORWARD"

 # Masquerade active FTP connections
 modprobe ip_nat_ftp

 # ACCEPT new outbound traffic (stateful firewall)
 $FORWARD -m state --state NEW,ESTABLISHED \
   -i $INT_IFACE -s $INT_NET -j ACCEPT

 for EXT_IFACE in $EXT_IFACES; do

   # ACCEPT return traffic (stateful firewall)
   $FORWARD -m state --state NEW,ESTABLISHED,RELATED \
     -i $EXT_IFACE -s ! $INT_NET -j ACCEPT

 done

 # Pass Internet traffic to internal network
 # unmodified
 iptables -t nat -A POSTROUTING -o $INT_IFACE \
   -j ACCEPT

 for EXT_IFACE in $EXT_IFACES; do

   # Masquerading outbound connections from
   # internal network
   iptables -t nat -A POSTROUTING -o $EXT_IFACE \
     -j MASQUERADE

 done

 # DROP and log everything else.
 $FORWARD -j DROPLOG

 # OUTPUT chain
 OUTPUT="iptables -t filter -A OUTPUT"

 # ACCEPT all traffic on loopback and internal network
 $OUTPUT -o lo -j ACCEPT
 $OUTPUT -o $INT_IFACE -j ACCEPT

 for message in echo-reply destination-unreachable \
                source-quench redirect echo-request \
                time-exceeded parameter-problem; do

   # ACCEPT various ICMP messages
   $OUTPUT -p icmp -s 0/0 --icmp-type $message \
     -m state --state NEW,ESTABLISHED \
     -j ACCEPT

 done

 # REJECT all other ICMP messages
 $OUTPUT -p icmp -j REJECT

 for EXT_IFACE in $EXT_IFACES; do

   IP=`getip $EXT_IFACE`

   # ACCEPT new outbound traffic (stateful firewall)
   $OUTPUT -m state --state NEW,ESTABLISHED \
     -o $EXT_IFACE -s $IP -j ACCEPT

 done

 # REJECT everything else
 $OUTPUT -j REJECT

 # PREROUTING chain
 PREROUTING="iptables -t nat -A PREROUTING"

 # Create syn-flood chain for detecting
 # Denial of Service attacks
 iptables -t nat -N syn-flood

 # Limit 12 connections per second (burst to 24)
 iptables -t nat -A syn-flood -m limit --limit 12/s \
   --limit-burst 24 -j RETURN
 iptables -t nat -A syn-flood -j DROPLOG

 # Setup transparent Squid proxy for internal network
 #
 # For details on setting up Squid, see:
 #   http://www.unxsoft.com/TransparentProxy.html
 #
 #$PREROUTING -i $INT_IFACE -p tcp --dport 80 \
 #  -j REDIRECT --to-port 3128

 # ACCEPT all traffic on internal network
 $PREROUTING -i $INT_IFACE -j ACCEPT

 # DROP XMAS & NULL TCP packets
 $PREROUTING -p tcp --tcp-flags ALL ALL -j DROPLOG
 $PREROUTING -p tcp --tcp-flags ALL NONE -j DROPLOG

 # DROP invalid packets w/o SYN bit set
 $PREROUTING -p tcp ! --syn -m state --state NEW \
   -j DROPLOG
 $PREROUTING -p tcp -m state --state INVALID \
   -j DROPLOG

 for EXT_IFACE in $EXT_IFACES; do

   IP=`getip $EXT_IFACE`

   # DROP inbound port scans
   $PREROUTING -i $EXT_IFACE -d $IP -m psd -j DROPLOG

   # DROP packets from hosts with more than 16
   # active connections
   $PREROUTING -i $EXT_IFACE -p tcp --syn -d $IP \
     -m iplimit --iplimit-above 16 -j DROPLOG

   # Check for DoS attack
   $PREROUTING -i $EXT_IFACE -d $IP -p tcp --syn \
     -j syn-flood

   # DROP IP spoofing
   $PREROUTING -d $IP ! -i $EXT_IFACE -j DROPLOG
   $PREROUTING -s $IP -j DROPLOG

 done

 # DROP local IP spoofing
 IP=`getip $INT_IFACE`
 $PREROUTING -s $IP -j DROPLOG
 $PREROUTING -s $INT_NET ! -i $INT_IFACE -j DROPLOG
 $PREROUTING -d $INT_NET ! -i $INT_IFACE -j DROPLOG

 # DROP loopback spoofing
 $PREROUTING -s 127.0.0.0/8 -j DROPLOG
 $PREROUTING -d 127.0.0.0/8 ! -i lo -j DROPLOG

 # DROP broadcast source packets
 $PREROUTING -s 0.0.0.0 -j DROPLOG
 $PREROUTING -s 255.255.255.255 -j DROPLOG

 # DROP "reserved" non-routable networks
 $PREROUTING -s 0.0.0.0/8 -j DROPLOG
 $PREROUTING -s 10.0.0.0/8 -j DROPLOG
 $PREROUTING -s 169.254.0.0/16 -j DROPLOG
 $PREROUTING -s 172.16.0.0/12 -j DROPLOG
 $PREROUTING -s 192.0.2.0/24 -j DROPLOG
 $PREROUTING -s 192.168.0.0/16 -j DROPLOG
 $PREROUTING -s 224.0.0.0/4 -j DROPLOG
 $PREROUTING -s 240.0.0.0/5 -j DROPLOG
 $PREROUTING -s 248.0.0.0/5 -j DROPLOG

 # Use DNAT to port forward http
 #$PREROUTING ! -i $INT_IFACE -p tcp \
 #  --destination-port 80 -j DNAT --to 10.0.0.3:80

 # Setup mangle table to modify TOS (Type of Service)
 # flags for various services:
 #    Minimize-Delay
 #    Maximize-Throughput
 #    Maximize-Reliability
 #    Minimize-Cost
 PREROUTING="iptables -t mangle -A PREROUTING"
 $PREROUTING -j TOS --set-tos Minimize-Delay       \
   -p tcp --dport ssh
 $PREROUTING -j TOS --set-tos Maximize-Reliability \
   -p tcp --dport smtp
 $PREROUTING -j TOS --set-tos Minimize-Delay       \
   -p udp --dport domain
 $PREROUTING -j TOS --set-tos Minimize-Delay       \
   -p tcp --dport http
 $PREROUTING -j TOS --set-tos Maximize-Reliability \
   -p tcp --dport auth
 $PREROUTING -j TOS --set-tos Minimize-Delay       \
   -p tcp --dport https

 OUTPUT="iptables -t mangle -A OUTPUT"
 $OUTPUT -j TOS --set-tos Maximize-Throughput  \
   -p tcp --dport ftp
 $OUTPUT -j TOS --set-tos Minimize-Delay       \
   -p tcp --sport ssh
 $OUTPUT -j TOS --set-tos Maximize-Reliability \
   -p tcp --sport smtp
 $OUTPUT -j TOS --set-tos Minimize-Delay       \
   -p udp --sport domain
 $OUTPUT -j TOS --set-tos Minimize-Delay       \
   -p tcp --sport domain
 $OUTPUT -j TOS --set-tos Minimize-Delay       \
   -p tcp --sport http
 $OUTPUT -j TOS --set-tos Maximize-Reliability \
   -p tcp --dport auth
 $OUTPUT -j TOS --set-tos Maximize-Throughput  \
   -p tcp --dport nntp
 $OUTPUT -j TOS --set-tos Minimize-Delay       \
   -p udp --dport ntp
 $OUTPUT -j TOS --set-tos Maximize-Reliability \
   -p tcp --sport ldap
 $OUTPUT -j TOS --set-tos Minimize-Delay       \
   -p tcp --sport https
 $OUTPUT -j TOS --set-tos Minimize-Delay       \
   -p icmp

 # Enable IP forwarding
 echo 1 > /proc/sys/net/ipv4/ip_forward

 # Enable TCP SYN cookies
 echo 1 > /proc/sys/net/ipv4/tcp_syncookies

 # Ignore various ICMP messages
 echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
 echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

 for i in /proc/sys/net/ipv4/conf/*; do

   # Disable source routed packets
   echo 0 > $i/accept_source_route

   # Enable reverse path routing - antispoof
   echo 1 > $i/rp_filter

   # Ignore ICMP redirects
   echo 0 > $i/accept_redirects

   # Log packets with impossible addresses
   echo 1 > $i/log_martians

 done
}

PATH=/usr/local/sbin:/sbin:$PATH
export PATH

# See how we were called
case "$1" in
  start|restart)
        echo "Starting firewall"
        firewallon
        ;;
  stop)
        echo "Stopping firewall"
        firewalloff
        ;;
  status)
        for table in filter nat mangle; do
           iptables --line-numbers -L -t $table -n -v
           echo ""
        done
        ;;
  *)
        echo "Usage: firewall {start|stop|status}"
        exit 1
esac

exit 0
