#! /bin/sh
#
# firewall+masq      TCP/IP firewalling + masquerading.
#
# Author:       Peter Bieringer <pb@bieringer.de>
#
# description: This script sets various firewall rules
#
# chkconfig: 345 12 89
#
# processname: firewall+masq

# Changes to
#  19990205: ipchains/kernel 2.1+2.2 ready
#            Quick merge from my old DLD 5.4 compatible script
#  1.00: initial merging
#  1.01: option for selecting specific masquerading modules (not load all)
#  1.02: some basic outgoing blocking (firewalling) to prevent dial-on-demand
#  1.03: major incoming blocking (firewalling)
#  1.04: add new FW rule for time-exceeded (used by traceroute)
#  1.05: add new FW and options to allow IDENT (auth) connections
#  1.06: add new FW rule against routed
#  1.07: modify masq timeouts, add some logging toggles and an udp logger
#  20000108: Review for RedHat 6.1, remove obsolete "ipfwadm"
#  20000109: Add option "unsecure"
#  20000205: Block broadcasts to dialup
#  20000423: Fix ippp dialin
#  20000702: Allow DHCP
#  20000721: Allow tunneled IPv6
#  20000722: Allow ICMP echo reply out to IPv6 tunnel host
#  20000816: Allow all on interface lo
#  20000923: Block IGMP
#  20001029: Change dialup interface, enable incoming RealAudio UDP
#  20001031: Redesign to use with different dialup interfaces (ADSL+ISDN)
#  20001101: Hardening dedicated port filter rules, add some special ones
#  20001104: Renaming user chains, adjust RTP/UDP, add sysctl, some switches
#  20001108: Allow local ICMP

#set -x

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

# Get config.
. /etc/sysconfig/network

# Check that networking is up.
if [ ${NETWORKING} = "no" ]
then
	exit 0
fi

IPFW=/sbin/ipchains

[ -f $IPFW ] || exit 0
[ -f /sbin/insmod ] || exit 0
[ -f /sbin/rmmod ] || exit 0
[ -f /sbin/lsmod ] || exit 0


RETVAL=0


subsys_parameter=$1
LOCKDIR=/var/lock/subsys

ALL="0.0.0.0/0"
LocalNet="192.168.0.0/22"
DialInNet="192.168.3.0/24"

# Specify IPv4 masquerading modules (7 at the moment (2.2.1))
IPMASQALLMODULES="ip_masq*" # matches all modules for removing
#IPMASQMODULES="ip_masq*" # all existing modules
IPMASQMODULES="ip_masq_ftp ip_masq_raudio" # only selected ones

# Firewalling?
#FW_OUTGOING=no
FW_OUTGOING=yes

#FW_INTERFACES="ippp+"
#FW_INTERFACES="ppp+"
FW_INTERFACES="ppp+ ippp+"

# Given IPv4 addresses for pppoe startup configuration
FW_PPPoEINITIAL="yes"
FW_PPPoELOCALINITAL="10.112.112.112"

# Allow incoming IPv6 packets through an IPv6-in-IPv4 tunnel
FW_ALLOWTUNNELEDIPV6=yes
IPv4_TUNNELIP=195.226.187.50


FW_LOGDEFAULTINCOMINGDENY="yes"
#FW_LOGDEFAULTINCOMINGDENY="no"


# Allow incoming Real Audio (UDP 6970-6999)
FW_ENABLE_REALAUDIO="yes"

# Enable active FTP (not recommended, because all local binded daemons, such
#  as 0.0.0.0:port are reachable from outside using source port 20)
FW_ENABLE_ACTIVE_FTP="no"


# If active FTP is enabled, you should block several ports
# Fill here in all listening ports >1023 you found with 
#  netstat -lnp --ip | grep ^tcp |awk  '{ print $4 "\t" $6 }' | grep ^0.0.0.0
#  3128 8080 8081 8082: squid, junkbuster
#  6105 6106 20011: isdninfo
FW_INCOMING_PORTBLOCK="3128 8080 8081 8082 6105 6106 20011"


######-------nothing to be changed here--------

# Test if masquerading is enabled in kernel	
if ! [ -f /proc/net/ip_masq -o -f /proc/net/ip_masquerade ]; then
    echo -e "\a Error: Kernel doesn't support masquerading!"
    echo "  You have to compile a new one, don't forget to enable this feature."
    exit $STARTUP_FAIL
fi

	
#Get Kernel Version for module loading
VERSION=`cat /proc/version | awk '{ print $3 }' `
    
## Switch on forwarding in the kernel (Name of the file is different between 2.0.x and 2.1.x)
PROC_IPFORWARD="`ls /proc/sys/net/ipv4/ip_forward* 2>/dev/null`"


#  Following switches on forwarding for all devices, perhaps against security...
#    if [ -f /proc/sys/net/ipv4/conf/all/forwarding ]; then
#	# for kernel 2.1.90+
#	for i in /proc/sys/net/ipv4/conf/*/forwarding; do
#    	    if ! [ "`cat $i`" = "1" ]; then
#		device=`echo $i | cut -d / -f 7` 
#		echo "  Switch on IPv4 forwarding for device '$device' in the kernel"
#    	        echo "1" > $i
#	    fi
#	done
#    fi



showinfo()
{
    ipchains -n -L -v
}


fwrules_insert()
{
    echo " Switch on IP forwarding"
    echo "1" >$PROC_IPFORWARD     

    # Forward policy: REJECT
    ipchains -P forward REJECT 

    # Input policy: REJECT
    ipchains -P output REJECT
    
    # Input policy: DENY
    ipchains -P input DENY

    
    # Create new chains for Internet connection
    ipchains -N extOUT
    ipchains -N extIN
    
    echo " Bypass local dialin addresses"
    ipchains -A input   -s $DialInNet -j ACCEPT
    ipchains -A output  -d $DialInNet -j ACCEPT
    ipchains -A forward -d $DialInNet -j ACCEPT
   
    if [ "$FW_PPPoEINITIAL" = "yes" ]; then 
	echo " Bypass PPPoE local interface IP (for startup issues)"
	ipchains -A extOUT -s $FW_PPPoELOCALINITAL -j ACCEPT
    fi

    # Put all traffic relating Internet connections into that interfaces
    echo -n " Add defined interfaces to Internet chains: "
    for iface in $FW_INTERFACES; do
	echo -n "$iface "
	ipchains -A input  -i $iface -j extIN
	ipchains -A output -i $iface -j extOUT
	
	ipchains -A forward -j MASQ -p all -s $LocalNet -i $iface
    done
    echo

    # Masquerading parameters
    ipchains -M -S 7200 120 180
    
    echo " Allow local addresses"
    ipchains -A input   -s $LocalNet -j ACCEPT
    ipchains -A output  -d $LocalNet -j ACCEPT
    ipchains -A forward -d $LocalNet -j ACCEPT
    ipchains -A input   -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
    ipchains -A output  -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
    ipchains -A input   -i lo -j ACCEPT
    ipchains -A output  -i lo -j ACCEPT

    echo " FW rule to prevent outgoing and incoming RfC 1822 addresses"
    ipchains -A extOUT -s 10.0.0.0/8     -j REJECT -l
    ipchains -A extOUT -s 172.16.0.0/12  -j REJECT -l
    ipchains -A extOUT -s 192.168.0.0/16 -j REJECT -l
    ipchains -A extIN  -d 10.0.0.0/8     -j DENY -l
    ipchains -A extIN  -d 172.16.0.0/12  -j DENY -l
    ipchains -A extIN  -d 192.168.0.0/16 -j DENY -l
    
    if [ "$FW_OUTGOING" = "yes" ]; then
        echo " FW rules to prevent netbios dial-on-demand (block all outgoing NetBIOS traffic)"
        ipchains -A extOUT -p tcp --dport 135         -j REJECT
        ipchains -A extOUT -p udp --dport 135         -j REJECT
        ipchains -A extOUT -p tcp --dport netbios-ns  -j REJECT
        ipchains -A extOUT -p udp --dport netbios-ns  -j REJECT
        ipchains -A extOUT -p tcp --dport netbios-dgm -j REJECT
        ipchains -A extOUT -p udp --dport netbios-dgm -j REJECT
        ipchains -A extOUT -p tcp --dport netbios-ssn -j REJECT
        ipchains -A extOUT -p udp --dport netbios-ssn -j REJECT
        ipchains -A extOUT -p tcp --dport 445         -j REJECT
        ipchains -A extOUT -p udp --dport 445         -j REJECT

        echo " FW rules to prevent broadcast/anycast dialouts"
        ipchains -A extOUT -d 0.0.0.0/255.255.255.255     -j REJECT
        ipchains -A extOUT -d 0.0.0.255/0.0.0.255         -j REJECT
        ipchains -A extOUT -d 0.0.255.255/0.0.255.255     -j REJECT
        ipchains -A extOUT -d 0.255.255.255/0.255.255.255 -j REJECT

        echo " FW rules to prevent routed"
        ipchains -A extOUT -p udp --sport router -j REJECT
    fi
    
        echo " FW rules to block incoming (unwanted) NetBIOS traffic"
        ipchains -A extIN  -p tcp --dport 135         -j DENY -l
        ipchains -A extIN  -p udp --dport 135         -j DENY -l
        ipchains -A extIN  -p tcp --dport netbios-ns  -j DENY -l
        ipchains -A extIN  -p udp --dport netbios-ns  -j DENY -l
        ipchains -A extIN  -p tcp --dport netbios-dgm -j DENY -l
        ipchains -A extIN  -p udp --dport netbios-dgm -j DENY -l
        ipchains -A extIN  -p tcp --dport netbios-ssn -j DENY -l
        ipchains -A extIN  -p udp --dport netbios-ssn -j DENY -l
        ipchains -A extIN  -p tcp --dport 445         -j DENY -l
        ipchains -A extIN  -p udp --dport 445         -j DENY -l

	# Reject incoming auth/ident (mostly from foreign FTP or SMTP servers)
        echo " FW rule to reject incoming TCP auth/ident requests"
        ipchains -A extIN  -p tcp --dport auth -j REJECT
    
    if [ "$FW_ALLOWTUNNELEDIPV6" = "yes" ]; then
	# IPv6-in-IPv4 tunnel
	ipchains -A extIN  -p ipv6 -s $IPv4_TUNNELIP -j ACCEPT
	ipchains -A extOUT -p ipv6 -d $IPv4_TUNNELIP -j ACCEPT
	# Ping (dynamic tunnel tester)
        ipchains -A extIN  -p icmp -s $IPv4_TUNNELIP --icmp-type echo-request -j ACCEPT
        ipchains -A extOUT -p icmp -d $IPv4_TUNNELIP --icmp-type echo-reply   -j ACCEPT
    fi

    # Block TCP ports for incoming connections (safety)
    if [ ! -z "$FW_INCOMING_PORTBLOCK" ]; then
    	echo " FW rule to block listening TCP ports (because the later active FTP data connection rule is able to allow connections with source port 20)"
	for port in $FW_INCOMING_PORTBLOCK; do
   	    ipchains -A extIN -p tcp --dport  $port -j DENY -l
	done
    fi

    if [ "$FW_ENABLE_ACTIVE_FTP" = "yes" ]; then
	echo " FW rule to allow active FTP data connections (SYN set)"
    	ipchains -A extIN -p tcp --sport ftp-data --dport 1024: -j ACCEPT
    fi
			
    echo " FW rule to block listening UDP ports (because the later DNS rule is able to allow connections with source port 53)"
    # Fill here in all listening ports >1023 you found with 
    #  netstat -lnp --ip | grep ^udp |awk  '{ print $4 "\t" $6} ' | grep ^0.0.0.0  | egrep -v "named|squid"
    # FYI: named & squid are binding on startup an UDP port >1023 for DNS lookups to the Internet - this ports should'nt be blocked!"
	# Nothing >1023 found on my system at the moment

    echo " FW rule to allow incoming UDP/DNS response"
    ipchains -A extIN -p udp --sport domain --dport 1024: -j ACCEPT
   
    if [ "$FW_ENABLE_REALAUDIO" = "yes" ]; then 
	echo " FW rule to enable incoming RealAudio UDP"
	ipchains -A extIN -p udp --sport 1024: --dport 6970:6999 -j ACCEPT
    fi

    echo " FW rule to allow only a few outgoing ICMP packets"
    ipchains -A extOUT -p icmp --icmp-type echo-request            -j ACCEPT
    ipchains -A extOUT -p icmp --icmp-type destination-unreachable -j ACCEPT
    ipchains -A extOUT -p icmp --icmp-type time-exceeded           -j ACCEPT
	    
    echo " FW rule to allow some incoming ICMP packets"
    #ipchains -A extIN  -p icmp --icmp-type echo-request            -j ACCEPT
    ipchains -A extIN  -p icmp --icmp-type echo-reply              -j ACCEPT
    ipchains -A extIN  -p icmp --icmp-type destination-unreachable -j ACCEPT
    ipchains -A extIN  -p icmp --icmp-type time-exceeded           -j ACCEPT

    echo " FW rule for Cisco packages, but don't log"
    ipchains -A extIN -p 88 -j REJECT

    echo " FW rule to block IGMP"
    ipchains -A extIN  -p igmp -j REJECT
    ipchains -A extOUT -p igmp -j REJECT

    echo " FW rule to allow incoming TCP response (SYN not set)"
    ipchains -A extIN -p tcp ! -y -j ACCEPT

    if [ "$FW_LOGDEFAULTINCOMINGDENY" = "yes" ]; then
    	echo " FW default policies (DENY all incoming from the Internet and log)"
    	ipchains -A extIN  -j DENY   -l
    else
    	echo " FW default policies (DENY all incoming from the Internet)"
    	ipchains -A extIN  -j DENY
    fi

    echo " FW default policies (ACCEPT all outgoing TCP/UDP to the Internet)"
    ipchains -A extOUT -p tcp -j ACCEPT
    ipchains -A extOUT -p udp -j ACCEPT

    echo " FW default policies (REJECT the rest and log)"
    ipchains -A extOUT -j REJECT -l

    echo " FW default policies (log rules)"
    ipchains -A input   -j DENY   -l
    ipchains -A output  -j REJECT -l
    ipchains -A forward -j REJECT -l
}

# Enable kernel security
function proc_ipv4_dosecure () {
        echo " Set some /proc switches to enable security features provided by k
ernel"

        sysctl -w net.ipv4.ip_always_defrag=1
        sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1
        sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
        sysctl -w net.ipv4.conf.default.log_martians=1
        sysctl -w net.ipv4.conf.all.log_martians=1
        sysctl -w net.ipv4.conf.default.accept_source_route=0
        sysctl -w net.ipv4.conf.all.accept_source_route=0
        sysctl -w net.ipv4.conf.default.accept_redirects=0
        sysctl -w net.ipv4.conf.all.accept_redirects=0
        sysctl -w net.ipv4.conf.default.rp_filter=1
        sysctl -w net.ipv4.conf.all.rp_filter=1
}

# Disable kernel security
function proc_ipv4_dounsecure () {
        echo " Set some /proc switches to DISABLE some security features provide
d by kernel"

        sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=0
        sysctl -w net.ipv4.conf.default.log_martians=0
        sysctl -w net.ipv4.conf.all.log_martians=0
        sysctl -w net.ipv4.conf.default.accept_redirects=1
        sysctl -w net.ipv4.conf.all.accept_redirects=1
        sysctl -w net.ipv4.conf.default.rp_filter=0
        sysctl -w net.ipv4.conf.all.rp_filter=0
}


fwrules_remove()
{
    echo " Remove all FW rules"
    ipchains -F forward
    ipchains -F output
    ipchains -F input
    
    # Delete user chains
    ipchains -F extOUT
    ipchains -F extIN
    ipchains -X extOUT
    ipchains -X extIN
    

    echo " Switch off IP forwarding"
    echo "0" >$PROC_IPFORWARD     
}




case "$1" in
  start)
	echo "Start firewalling..."
	
	if [ -f $LOCKDIR/firewall+masq ]; then
	    echo -e "\a Alredy running, stop first!"
	fi

	echo " Load IP-Masquerading Modules:"
        cd /lib/modules/$VERSION/ipv4 
        for i in $IPMASQMODULES; do 
	     echo -n " $i: "
	      insmod $i;	
	done
	echo

	proc_ipv4_dosecure		
	fwrules_insert
	

	touch $LOCKDIR/firewall+masq
	;;
  stop)
	echo "Stop firewalling..."
    
	fwrules_remove
		
	# unload ip_masquerading modules 
	echo -n " Unload IP-Masquerading Modules:"
	lsmod | grep ^$IPMASQALLMODULES | while read mname rest; do
    	    echo -n " $mname"
	    rmmod $mname
	done
	
	echo

	rm -f $LOCKDIR/firewall+masq
	;;
	
 unsecure)
	$0 stop

	echo "Reset default policies to ACCEPT"
    	ipchains -P input ACCEPT
    	ipchains -P forward ACCEPT
    	ipchains -P output ACCEPT
	proc_ipv4_dounsecure
	;;
  restart)
	$0 stop
	$0 start
	exit $?
	;;
  status)
	showinfo
	exit $STARTUP_OK
	;;
  *)
	echo "Usage: firewall {start|stop|restart|status|unsecure}"
	exit $STARTUP_FAIL
    ;;
esac

exit $STARTUP_OK 
