#!/bin/sh
#
# firewalling    TCP/IP firewalling + masquerading
#
# Extended Edition, German Version for Red Hat Linux 6.2
#
# (P) & (C) 2001 by Dr. Peter Bieringer <pb@bieringer.de>
#
# Version: 2001-04-20
#
# description: This script sets various firewall rules
#
# chkconfig: 345 98 02
#
# processname: firewallsetup
#
#
# Beispielkonfiguration beruht auf folgenden Daten:
#  Interne Schnittstelle:  eth0
#  Interne IPv4-Adresse:   192.168.1.1
#  Internes Netzwerk:      192.168.1.0/24
#
#  Externe Schnittstellen: ppp+, ippp+
#  Externe IPv4-Adresse:   dynamisch zugewiesen
#
# Dieses Skript ist nur ein Demonstrationsbeispiel
#  und beim Autor nicht im produktiven Einsatz.
#  Eine Weiterentwicklung außer Fehlerbehebung wird es deshalb 
#  nicht geben.
#
# Achtung: keine Garantie auf Schutzwirkung, zur Verifizierung mit
#  nmap deshalb von außerhalb testen!
#
# ChangeLog:
#  20010320: Erste Version
#  20010321: Einfügen von Schalter für die einzelnen Features
#  20010322: Blockieren von T-Online-Mail
#  20010328: Review
#  20010405: Fix ip_local_port_range
#  20010417: Ändere RunLevel-Werte, damit Internetconnectivity vor dem Ausführen
#             des Skripts besteht (wg. DNS-Abfragen), Checke ip_local_port_range
#  20010418: Wrapper für sysctl entfernt
#  20010420: Hinweis für /etc/sysctl.conf war buggy (".." funktioniert nicht)

## Schalter
OPTION_BASIC_ICMP="ja"
OPTION_INTERN_DNS="ja"
OPTION_MASQUERADE="ja"
OPTION_MASQ_FTP="ja"
OPTION_MASQ_FTP_ACTIVE="ja"
OPTION_MASQ_PGP="ja"
OPTION_MASQ_POP="ja"
OPTION_MASQ_IMAP="ja"
OPTION_MASQ_SMTP="ja"
OPTION_MASQ_BLOCK_TONLINE_MAIL="ja"
OPTION_WEBPROXY_FTP="ja"

# 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

[ -x /sbin/ipchains ] || exit 1
[ -x /sbin/sysctl ] || exit 1
RETVAL=0
#set -x

# Return all IPv4 addresses of a given hostname via DNS
resolvelistIPv4() {
	hostname=$1
	if [ -z "$hostname" ]; then
		return 1
	fi

	LC_ALL=C dig $hostname A IN +pfmin | grep "IN A" | awk '{ print $5 }'
	return 0
}


# Execute ipchains, display error if occurs
ipchains() {
	rule="$*"
	#echo "$rule"
	/sbin/ipchains $rule
	
	if [ $? -gt 0 ]; then
		echo -e "\a Error in rule: $rule"
	fi
}

# See how we were called.
case "$1" in
  start)
        echo -n $"Starting firewalling: "

        # Setze Policies
        ipchains -P input DENY
        ipchains -P forward REJECT
        ipchains -P output REJECT

        # Aktiviere TCP-Syncookies
        sysctl -w net.ipv4.tcp_syncookies=1

        # Reagiere nicht auf seltsame ICMP-Pakete
        sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=1

        # Reagiere nicht auf Pings an die Broadcastadresse
        sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1

        # Setze Limits für die Aussenderate von ICMP-Paketen
		#  in jiffies (auf Intel 1/100s)
        sysctl -w net.ipv4.icmp_destunreach_rate=100
        sysctl -w net.ipv4.icmp_echoreply_rate=100
        sysctl -w net.ipv4.icmp_paramprob_rate=100
        sysctl -w net.ipv4.icmp_timeexceed_rate=100

        # Deaktiviere globales IPv4 forwarding
        sysctl -w net.ipv4.ip_forward=0

		# Checke Portbereich für ausgehende Pakete
		portstart="`sysctl net.ipv4.ip_local_port_range | awk '{ print $3 }'`"
		portende="`sysctl net.ipv4.ip_local_port_range | awk '{ print $4 }'`"
		if [ "$portstart" != "32768" -o "$portende" != "60099" ]; then
			echo "Firewalling benötigt eine spezielle Einstellung bzgl. der ip_local_port_range" >/dev/stderr
			echo " bitte folgende Zeilen in /etc/sysctl.conf einfügen und rebooten:" >/dev/stderr
			echo "  # Ändere Portbereich für ausgehende Pakete" >/dev/stderr
			echo "  net.ipv4.ip_local_port_range = 32768 60099" >/dev/stderr
			exit 1
		fi

        # Defragmentiere immer
        sysctl -w net.ipv4.ip_always_defrag=1

        # Diverse pro-Interface Schalter im Kernel aktivieren
        find /proc/sys/net/ipv4/conf/ -mindepth 1 -maxdepth 1 -type d | awk -F/ '{ print $NF}' | while read interface; do
            # Protokolliere Pakete mit unmöglichen IPv4-Adressen
            sysctl -w net.ipv4.conf.$interface.log_martians=1
            # Nichtakzeptieren von IPv4 source routing
            sysctl -w net.ipv4.conf.$interface.accept_source_route=0
            # Nichtakzeptieren von ICMP redirects
            sysctl -w net.ipv4.conf.$interface.accept_redirects=0
            # Stelle Antispoofingfilter auf streng
            sysctl -w net.ipv4.conf.$interface.rp_filter=2
            # Deaktiviere Weiterleitung von Paketen, die an dieser Schnittstelle eintreffen
            sysctl -w net.ipv4.conf.$interface.forwarding=0
        done


        # Eigene Regeln ab hier

		# Broadcast-Pakete vom Logging ausnehmen
		ipchains -N nobroad
		ipchains -A nobroad -d 0.0.0.255/0.0.0.255         -j DENY
		ipchains -A nobroad -d 0.0.255.255/0.0.255.255     -j DENY
		ipchains -A nobroad -d 0.255.255.255/0.255.255.255 -j DENY

		#ipchains -A input -j nobroad
	
		# Benutzerdefierte Listen zum Verteilen der Pakete
		ipchains -N intIN		# intern   -> Firewall
		ipchains -N intOUT		# Firewall -> intern
		ipchains -N extIN 		# extern   -> Firewall
		ipchains -N extOUT		# Firewall -> extern

		ipchains -N extDeMSQ	# extern   -> Firewall zum demaskieren
		ipchains -N extMASQ		# intern über Firewall zum maskieren

		# Loopback-Verkehr erlauben
		ipchains -A input  -i lo -j ACCEPT
		ipchains -A output -i lo -j ACCEPT

		# Eintreffende Pakete an der internen Schnittstelle für den Firewall
		ipchains -A input  -i eth0 -s 192.168.1.0/24 -d 192.168.1.1 -j intIN

		# Ausgehende Pakete zur internen Schnittstelle vom Firewall
		ipchains -A output -i eth0 -s 192.168.1.1 -d 192.168.1.0/24 -j intOUT

		# Eintreffende Pakete an externen Schnittstellen 
		ipchains -A input  -i ppp+  -j extIN
		ipchains -A input  -i ippp+ -j extIN

		# Ableitung eintreffender Pakete als Antwort von maskierten Paketen an externen Schnittstellen 
		ipchains -A extIN  -p tcp  --dport 61000:65095 -j extDeMSQ
		ipchains -A extIN  -p udp  --dport 61000:65095 -j extDeMSQ

		# Ausgehende Pakete zu externen Schnittstellen vom Firewall direkt
		ipchains -A output -i ppp+  -j extOUT
		ipchains -A output -i ippp+ -j extOUT

		# Keine Pakete mit internen Quelladressen nach außen versenden
		ipchains -I extOUT -s 192.168.1.0/24 -j REJECT -l

		# Ausgehende Pakete zu externen Schnittstellen vom Maskieren
		ipchains -A extOUT -p tcp  --sport 61000:65095 -j extMASQ
		ipchains -A extOUT -p udp  --sport 61000:65095 -j extMASQ


		# intern -> SSH auf Firewall
		ipchains -A intIN  -p tcp --sport 512: --dport 22        -j ACCEPT
		ipchains -A intOUT -p tcp --sport 22   --dport 512: ! -y -j ACCEPT


		# intern -> Webproxy auf Firewall
		ipchains -A intIN  -p tcp --sport 1024: --dport 3128       -j ACCEPT
		ipchains -A intOUT -p tcp --sport 3128  --dport 1024: ! -y -j ACCEPT

		
		# Webproxy -> Internet (Port 80/HTTP) + Antwort
		ipchains -A extOUT -p tcp --dport 80         -j ACCEPT
		ipchains -A extIN  -p tcp --sport 80    ! -y -j ACCEPT

		# Webproxy -> Internet (Port 443/HTTPS) + Antwort
		ipchains -A extOUT -p tcp --dport 443        -j ACCEPT
		ipchains -A extIN  -p tcp --sport 443   ! -y -j ACCEPT

		if [ "$OPTION_WEBPROXY_FTP" = "ja" ]; then
			# Webproxy -> Internet (FTP:Kommandokanal) + Antwort
			ipchains -A extOUT -p tcp --dport 21         -j ACCEPT
			ipchains -A extIN  -p tcp --sport 21    ! -y -j ACCEPT

			# Webproxy -> Internet (FTP: passiver Datentransfer) + Antwort
			ipchains -A extOUT -p tcp --dport 1024:      -j ACCEPT
			ipchains -A extIN  -p tcp --sport 1024: ! -y -j ACCEPT
		fi

		# DNS -> Internet (UDP) + Antwort
		ipchains -A extOUT -p udp --dport 53         -j ACCEPT
		ipchains -A extIN  -p udp --sport 53         -j ACCEPT

		# DNS -> Internet (TCP) + Antwort
		ipchains -A extOUT -p tcp --dport 53         -j ACCEPT
		ipchains -A extIN  -p tcp --sport 53    ! -y -j ACCEPT

		# Internet -> Firewall: auth/ident-lookup (REJECT)
		ipchains -A extIN  -p tcp --dport 113 -y -j REJECT

		# Firewall -> Internet: port unreachable
		ipchains -A extOUT -p icmp --icmp-type port-unreachable -j ACCEPT

		if [ "$OPTION_INTERN_DNS" = "ja" ]; then
			# intern -> DNS auf Firewall (UDP)
			ipchains -A intIN  -p udp --sport 1024: --dport 53         -j ACCEPT
			ipchains -A intOUT -p udp --sport 53    --dport 1024:      -j ACCEPT

			# intern -> DNS auf Firewall (TCP)
			ipchains -A intIN  -p tcp --sport 1024: --dport 53         -j ACCEPT
			ipchains -A intOUT -p tcp --sport 53    --dport 1024: ! -y -j ACCEPT
		fi
	
		if [ "$OPTION_BASIC_ICMP" = "ja" ]; then
			# Internet -> Firewall: ICMP-Pakete zur Benachrichtung bei Verbindungsproblemen
            ipchains -A extIN -p icmp --icmp-type destination-unreachable -j ACCEPT
            ipchains -A extIN -p icmp --icmp-type time-exceeded           -j ACCEPT
            ipchains -A extIN -p icmp --icmp-type source-quench           -j ACCEPT
            ipchains -A extIN -p icmp --icmp-type parameter-problem       -j ACCEPT

			# intern -> Firewall: ICMP-Pakete zur Benachrichtung bei Verbindungsproblemen
            ipchains -A intIN -p icmp --icmp-type destination-unreachable -j ACCEPT
            ipchains -A intIN -p icmp --icmp-type time-exceeded           -j ACCEPT
            ipchains -A intIN -p icmp --icmp-type source-quench           -j ACCEPT
            ipchains -A intIN -p icmp --icmp-type parameter-problem       -j ACCEPT
			
			# Firewall -> Internet: ICMP-Pakete für Verbindungstests + Antwort
            ipchains -A extOUT -p icmp --icmp-type echo-request -j ACCEPT
            ipchains -A extIN  -p icmp --icmp-type echo-reply   -j ACCEPT

			 # Firewall -> intern: ICMP-Pakete für Verbindungstests + Antwort
            ipchains -A intOUT -p icmp --icmp-type echo-request -j ACCEPT
            ipchains -A intIN  -p icmp --icmp-type echo-reply   -j ACCEPT

			# Firewall -> Internet: ICMP-Pakete zur Benachrichtigung Flußkontrolle und Path MTU discovery
            ipchains -A extOUT -p icmp --icmp-type source-quench        -j ACCEPT
            ipchains -A extOUT -p icmp --icmp-type fragmentation-needed -j ACCEPT

			# Firewall -> intern: ICMP-Pakete zur Benachrichtigung bei Verbindungsproblemen
            ipchains -A intOUT -p icmp --icmp-type source-quench           -j ACCEPT
            ipchains -A intOUT -p icmp --icmp-type destination-unreachable -j ACCEPT
            ipchains -A intOUT -p icmp --icmp-type time-exceeded           -j ACCEPT
            ipchains -A intOUT -p icmp --icmp-type parameter-problem       -j ACCEPT
        fi


		if [ "$OPTION_MASQUERADE" = "ja" ]; then
			## Masquerading

			# Erlaube forwarding
			sysctl -w net.ipv4.conf.eth0.forwarding=1
            sysctl -w net.ipv4.conf.ppp0.forwarding=1


			# Filterliste: Erlaubt für Masquerading
			ipchains -N int2masq

			# Filterliste: Erlaubte Antwortpakete für Masquerading
			ipchains -N masq4int

			# Filter, der den Filter für erlaubte Pakete aufruft und auf den Rücksprung wartet
			ipchains -N int4masq
			ipchains -A int4masq -j int2masq
			ipchains -A int4masq -j ACCEPT

			# Filter, der auch wieder den Filter für erlaubte Pakete aufruft und auf den Rücksprung wartet
			ipchains -N fwd4masq
			ipchains -A fwd4masq -j int2masq
			ipchains -A fwd4masq -j MASQ

			# Filter, der das Versenden maskierter Pakete erlaubt

			# Ausgehende Paketverteilung
			ipchains -A input   -i eth0  -s 192.168.1.0/24   -d ! 192.168.1.0/24 -j int4masq
			ipchains -A forward -i ppp+  -s 192.168.1.0/24   -d ! 192.168.1.0/24 -j fwd4masq
			ipchains -A forward -i ippp+ -s 192.168.1.0/24   -d ! 192.168.1.0/24 -j fwd4masq

			# Ankommende Paketverteilung
			ipchains -A extDeMSQ -s ! 192.168.1.0/24                             -j masq4int
			ipchains -A output  -i eth0  -s ! 192.168.1.0/24 -d 192.168.1.0/24   -j masq4int

			## Füllung der Masquerading Listen

			# Ping und Traceroute von intern via Masquerading
			ipchains -A int2masq -p icmp --icmp-type echo-request            -j RETURN
			ipchains -A masq4int -p icmp --icmp-type echo-reply              -j ACCEPT
			ipchains -A masq4int -p icmp --icmp-type time-exceeded           -j ACCEPT
			ipchains -A masq4int -p icmp --icmp-type destination-unreachable -j ACCEPT

			if [ "$OPTION_MASQ_BLOCK_TONLINE_MAIL" = "ja" ]; then
				# Blockiere POP zu T-Online
				resolvelistIPv4 pop.t-online.de | while read ip rest; do
					ipchains -A int2masq -p tcp -d $ip 110 -j REJECT -l
				done
				# Blockiere SMTP zu T-Online
				resolvelistIPv4 smtp.t-online.de | while read ip rest; do
					ipchains -A int2masq -p tcp -d $ip  25 -j REJECT -l
				done
			fi

			if [ "$OPTION_MASQ_POP" = "ja" ]; then
				# POP via Masquerading
				ipchains -A int2masq -p tcp --dport 110        -j RETURN
				ipchains -A masq4int -p tcp --sport 110   ! -y -j ACCEPT
			fi

			if [ "$OPTION_MASQ_SMTP" = "ja" ]; then
				# SMTP via Masquerading
				ipchains -A int2masq -p tcp --dport 25         -j RETURN
				ipchains -A masq4int -p tcp --sport 25    ! -y -j ACCEPT
			fi

			if [ "$OPTION_MASQ_FTP" = "ja" ]; then
				# Modul für FTP-Masquerading laden
				modprobe ip_masq_ftp

				# Passive FTP von intern via Masquerading
				ipchains -A int2masq -p tcp --dport 21         -j RETURN
				ipchains -A int2masq -p tcp --dport 1024:      -j RETURN
				ipchains -A masq4int -p tcp --sport 21    ! -y -j ACCEPT
				ipchains -A masq4int -p tcp --sport 1024: ! -y -j ACCEPT
				
				if [ "$OPTION_MASQ_FTP_ACTIVE" = "ja" ]; then
					# Freischaltung von aktiven Datentransfer bei FTP von intern via Masquerading
					ipchains -A masq4int -p tcp --sport 20      -j ACCEPT
					ipchains -A int2masq -p tcp --dport 20 ! -y -j RETURN
				fi
			fi

			if [ "$OPTION_MASQ_PGP" = "ja" ]; then
				# Verbindung zu PGP-Keyservers via Masquerading
				resolvelistIPv4 europe.keys.pgp.com | while read ip rest; do
					ipchains -A int2masq -p tcp -d $ip 11370       -j RETURN
					ipchains -A masq4int -p tcp -s $ip 11370  ! -y -j ACCEPT
				done
				resolvelistIPv4 pgpkeys.mit.edu | while read ip rest; do
					ipchains -A int2masq -p tcp -d $ip 11371       -j RETURN
					ipchains -A masq4int -p tcp -s $ip 11371  ! -y -j ACCEPT
				done
				resolvelistIPv4 keyserver.pgp.com | while read ip rest; do
					ipchains -A int2masq -p tcp -d $ip 389         -j RETURN
					ipchains -A masq4int -p tcp -s $ip 389    ! -y -j ACCEPT
				done
			fi

			ipchains -A extMASQ -j int2masq
			ipchains -A extMASQ -j ACCEPT 

			# Beende benutzerdefinierte Listen mit Log
			ipchains -A int2masq -j REJECT -l
			ipchains -A masq4int -j DENY   -l

		fi # Ende von OPTION_MASQUERADE

        # Protokolliere alle abgelehnten Pakete
        ipchains -A intIN    -j DENY   -l
        ipchains -A intOUT   -j REJECT -l
        ipchains -A extIN    -j DENY   -l
        ipchains -A extOUT   -j REJECT -l
        ipchains -A extDeMSQ -j DENY   -l
 
        ipchains -A input    -j DENY   -l
        ipchains -A forward  -j REJECT -l
        ipchains -A output   -j REJECT -l
        ;;
  stop)
        echo -n $"Stopping firewalling: "

		# Schalte Forwarding aus
        sysctl -w net.ipv4.ip_forward=0

        # Setze Policies
        ipchains -P input DENY
        ipchains -P forward REJECT
        ipchains -P output REJECT

        # Lösche alle Regeln in den Standard-Filterlisten
        ipchains -F forward
        ipchains -F output
        ipchains -F input

        # Lösche alle Regeln in den benutzerdefinierten Filterlisten
		cat /proc/net/ip_fwnames | egrep -v "input|forward|output" | while read list rest; do
			ipchains -F $list
		done

		# Lösche alle benutzedefinierten Filterlisten
		cat /proc/net/ip_fwnames | egrep -v "input|forward|output" | while read list rest; do
			ipchains -X $list
        done

		# Entfernen aller Masquerading-Module
		lsmod | grep ^ip_masq | awk '{ print $1 }' | while read module; do rmmod $module; done

        ;;
  restart|reload)
        $0 stop
        $0 start
        ;;
  *)#
       echo $"Usage: firewalling {start|stop|restart|reload}"
       exit 1
esac

