#!/bin/bash
#
# fwall2: Alex' Firewall Script for Linux NetFilter
# Copyright (c)2001-2003 by Alexander Barton, licensed under the GNU GPL.
# E-Mail: alex@barton.de, http://www.barton.de/, http://arthur.ath.cx/
#

# --- Dokumentation ---

# Firewall:
#
# - Beim Start des Scripts werden alle noetigen Kerneloptionen gesetzt sowie
#   alle notwendigen Kernel-Module (so vorhanden) nachgeladen.
#
# - Alle Pakete (ausser auf den SECURE_IFACES, hier werden Pakete immer(!)
#   akzeptiert) durchlaufen zunaechst einige allgemeine Tests: hier werden
#   offensichtlich ungueltige Pakete sowie Pakete von gesperrten IP-Adressen
#   (siehe BLOCK_IPS) protokolliert & verworfen.
#
# - Pakete, die ueber Gateways empfangen oder gesendet wurden werden erkannt
#   und die entsprechenden Regelkette (*_FWD_*), die dem Ziel-Netz entspricht
#   (LAN bzw. WAN), ausgefuehrt. Die Herkunft des Pakets ist also irrelevant.
#   Zudem durchlaufen Pakete, die geforwarded werden, _nicht_ die IN- bzw.
#   OUT-Filter des Firewallsystems!
#
# - Standardmaessig werden nur die Protokolle ICMP (immer) sowie TCP und UDP
#   nach den konfigurierten Regeln erlaubt. Zudem werden Pakete/Protokolle,
#   die dem Netfilter-Status "established" und "related" entsprechen, ebenfalls
#   immer erlaubt.
#
# - Mit dem Befehl "fwall2.sh block <ip>" kann eine beliebige IP im laufenden
#   Betrieb blockiert werden; Gegenstueck: "fwall2.sh unlock <ip>".
#
# Masquerading:
#
# - es werden nur Pakete maskiert, die ueber eines der MASQ_IFACES den Rechner
#   verlassen und(!) aus einem der MASQ_NETS kommen.
#
# Konfiguration:
#
# - Alle Optionen dieses Firewall-Scripts werden ueber Variablen konfiguriert.
#   Diese koennen prinzipiell direkt im Quellcode des Scripts angegeben werden,
#   davon sollte man jedoch absehen(!), da Updates so erschwert werden.
#   BESSER:
#   Den Dokumentations- und Konfigurationsabschnitt (also von Beginn bis zur
#   "Trennlinie" weiter unten) als /etc/fwall2.conf abspeichern und alle
#   Anpassungen dort vornehmen.
#   Unbenutzte Variablen (d. h. solche, die nicht angepasst werden) koennen
#   aus /etc/fwall2.conf geloescht werden, das Script verwendet dann auto-
#   matisch seine Defaults. So sind Updates problemlos(er) moeglich :-)
#
# Aufruf des Scripts:
#
# - fwall2.sh {start|stop}
#   Script komplett (Firewall und Masquerading, falls konfiguriert) starten
#   bzw. stoppen. Achtung: beim Stoppen wird die sog. "default policy" auf
#   DROP gestellt, d. h. alle Pakete verworfen! Das Script sollte jedoch
#   erkennen, wenn von einem entfernten Terminal (SSH, Telnet) gearbeitet
#   wird und diesen Schritt dann verbieten ...
#
# - fwall2.sh {reload|restart}
#   Konfiguration neu einlesen bzw. Script komplett neu initialisieren.
#   Ersteres (reload) kann Problemlos von entfernten Rechnern (z. B. via SSH)
#   ausgefuehrt werden, zweiteres nicht: restart entspricht einem Stoppen
#   und anschliessendem Neustart der kompletten Firewall, siehe oben.
#
# - fwall2.sh {startmasqonly|stopmasqonly}
#   Nur Masquerading durchfuehren, keine Filterregeln konfigurieren. Die sog.
#   "default policy" der Netfilter-Regeln wird auf ACCEPT gestellt, d. h. es
#   ist jeglicher Netzwerkverkehr erlaubt.
#
# - fwall2.sh {block|unblock} <ip>
#   IP-Adresse im laufenden Betrieb der Firewall zur Liste der komplett
#   blockierten Hosts hinzufuegen bzw. loeschen.
#
# - fwall2.sh status
#   Betriebsstatus der Firewall ausgeben.
#
# - fwall2.sh list
#   Komplette Regelliste ausgeben.

# --- Firewall ---

# Zusaetzliche Debugmeldungen ausgeben. Im "normalen" Betrieb in der Regel
# wenig erwuenscht, erleichtert jedoch die Fehlersuche im Script selber.
# Moegliche Werte: "true" (an) oder "false" (aus).

DEBUG=false

# Interfaces der "Aussenanbindung", d. h. unsichere Interfaces. Mehrere
# werden durch Leerzeichen getrennt angegeben; die Schreibweise "<if>+" um
# eine ganze Klasse abzudecken (z. B. "ppp+") ist erlaubt -- siehe auch die
# manual page zu iptables(8).
# Auf hier konfigurierte Interfaces beziehen sich unten alle Regeln, die
# ein "WORLD" im Namen tragen.

WORLD_IFACES=""

# Interfaces und Netzmasken des internen "sicheren" Netzes. Auch hier koennen
# jeweils mehrere Interfaces und Netze durch Leerzeichen getrennt angegeben
# werden; die "<ip>+"-Schreibweise ist auch hier erlaubt.
# Auf hier konfigurierte Interfaces/Netze beziehen sich unten alle Regeln,
# die "LAN" im Namen tragen.

LAN_IFACES=""
LAN_NETS=""

# Absolut sichere Interfaces, auf diesen wird ueberhaupt nicht gefiltert.
# In der Regel wird das Loopback-Interface "lo" hier angegeben.

SECURE_IFACES="lo"

# Im Folgenden werden die Regeln fuer "world" und "lan" konfiguriert. Hierbei
# wird angegeben, was erlaubt sein soll, per Default ist alles verboten.
#
# - {IN|OUT}_{WORLD|LAN}_ALLOW_{UDP|TCP}:
#   Hiermit werden Ports und Portbereiche konfiguriert, die fuer eingehenden
#   bzw. ausgehenden UDP- bzw. TCP-Traffic erlaubt werden.
#   Es koennen Portnummern, Service-Namen (aus /etc/services) und Bereiche
#   mit der Syntax "<von>:<bis>" angeben werden.
#   Mit dem speziellen Bereich ":" werden alle Ports abgedeckt, d. h. alle
#   Ports sind erlaubt. Dies kann v. a. fuer {IN|OUT}_LAN_ALLOW_{UDP|TCP}
#   interessant sein.
#   Beispiel: "ssh 25 137:139 http".
#
# - {IN|OUT}_{WORLD|LAN}_ALLOW_PROTO:
#   Standardmaessig werden nur die Protokolle ICMP (immer) sowie TCP und UDP
#   nach den konfigurierten Regeln erlaubt. Zudem werden Pakete/Protokolle,
#   die dem Netfilter-Status "established" und "related" entsprechen, ebenfalls
#   immer erlaubt. Werden weitere Protokoll benoetigt (z. B. GRE fuer PPTP)
#   so koennen diese hier, entweder numerisch oder als Bezeichnung wie in
#   /etc/protocols aufgefuehrt, hier angegeben werden. Diese werden dann
#   pauschal erlaubt (wenn sie nicht durch "generische" Regeln oder BLOCK_IPS
#   schon verworfen wurden).
#
# - FWD_{WORLD|LAN}_REJECT_{UDP|TCP}:
#   Pakete, die geforwarded werden, werden normalerweise nicht speziell gefil-
#   tert, anders als bei IN und OUT wird hier alles erlaubt. Sollen spezielle
#   Ports verboten werden, so koennen diese hier aufgefuehrt werden. Auch hier
#   sind Bereiche ("<von>:<bis>") und mehrere Ports/Bereiche (mit Leerzeichen
#   getrennt) moeglich.
#   FWD_WORLD_* bezieht sich auf Pakete, die auf "world interfaces" geforwarded
#   werden, FWD_LAN_* auf solche ins LAN.

IN_WORLD_ALLOW_TCP=""
IN_WORLD_ALLOW_UDP=""
IN_WORLD_ALLOW_PROTO=""
OUT_WORLD_ALLOW_TCP=""
OUT_WORLD_ALLOW_UDP=""
OUT_WORLD_ALLOW_PROTO=""
FWD_WORLD_DROP_TCP=""
FWD_WORLD_DROP_UDP=""
FWD_WORLD_REJECT_TCP=""
FWD_WORLD_REJECT_UDP=""

IN_LAN_ALLOW_TCP=""
IN_LAN_ALLOW_UDP=""
IN_LAN_ALLOW_PROTO=""
OUT_LAN_ALLOW_TCP=""
OUT_LAN_ALLOW_UDP=""
OUT_LAN_ALLOW_PROTO=""
FWD_LAN_DROP_TCP=""
FWD_LAN_DROP_UDP=""
FWD_LAN_REJECT_TCP=""
FWD_LAN_REJECT_UDP=""

# Mit BLOCK_IPS kann eine Liste von IP-Adressen konfiguriert werden, die
# immer, unabhaengig von anderen Regeln, geblockt werden. Mehrere Adressen
# werden mit Leerzeichen getrennt; Hostnamen koennen verwendet werden, sie
# werden jedoch beim Starten der Firewall in IP-Adressen uebersetzt, d. h.
# spaetere Aenderungen im DNS bekommt die Firewall nicht mit!

BLOCK_IPS=""

# --- Masquerading ---

# Interfaces, auf denen Pakete aus bestimmten Subnetzen "maskiert" werden
# sollen, d. h. mit denen PAT ("port address translation") gemacht wird.
# Mehrere Interfaces und Netze werden mit Leerzeichen getrennt.

MASQ_IFACES=""
MASQ_NETS=""

# --- Optionen ---

# Pakete, die ueber ein Interface empfangen werden, ueber welches sie mit der
# aktuellen Routing-Konfiguration aber nicht gesendet wuerden, protokollieren?
# In "kleinen" Netzen ist dieser Fall haeufig ein Hinweis auf eine Fehlkon-
# figuration, in "grossen" Netzen mit "komplexerem" Routing oft normal; hier
# sollte LOG_MARTIANS mit "false" deaktiviert werden (Default: "true", an).

LOG_MARTIANS="true"

# Loglevel fuer die Syslog-Meldungen, vgl. syslog.h und iptables(8).

LOGLEVEL="7"

# Log-Limit fuer Netfilter, vgl. manual page fuer iptables(8). Der Default
# sollte in der Regel ausreichend sein ...

LIMIT="5/minute"

# --- ChangeLog ---
#
# 2003-12-02: Release 6
# - Beschreibung der Funktionsweise und Dokumentation der einzelnen Variablen
#   endlich verfollstaendigt bzw. ergaenzt.
# - LOG_MARTIANS versteht nun, analog zu DEBUG, auch true/false. Das alte
#   yes/no ist nach wie vor moeglich, jedoch "undokumentiert".
# - Copyright-Zeile in About-Funktion korrigiert (2003 fehlte) ;-)
#
# 2003-04-28:
# - Aufrufe von /etc/fwall2.local und /etc/fwall2.local-masq eingebaut.
#
# 2003-02-24:
# - Test auf $rc_done und $rc_failed verbessert;
# - Debug-Mode (Variable DEBUG) implementiert.
#
# 2003-02-04:
# - ip_conntrac_irc und ip_nat_irc in Modul-Liste aufgenommen.

#
# Ende des Konfigurations- und Dokumentationsabschnitts. Hier beginnt nun
# das "eigentliche" Script, Aenerungen sind ab hier nicht mehr erforderlich.
#

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

NAME="fwall2"
RELEASE="6"
RELEASE_DATE="2003-12-02"

# --- Initialisieren ---

$DEBUG && echo "[DEBUG] Initializing ..."

DefAction="REJECT"
DefActionTxt="Reject"

# versuchen, das ipchains-Modul zu entladen
$DEBUG && echo "[DEBUG] Unloading ipchains kernel module ..."
modprobe -r ipchains > /dev/null 2>&1

# ggf. IP-Tables-Modul laden
$DEBUG && echo "[DEBUG] Probing for iptables kernel module ..."
modprobe -a ip_tables > /dev/null 2>&1

# iptables ok?
$DEBUG && echo "[DEBUG] Testing iptables command ..."
iptables -L -n > /dev/null 2>&1
if [ $? -ne 0 ]; then
	echo -n "Oops, iptables reported error!? "
	echo -e $FAILED
	logger -t $NAME "Oops, iptables reported error!? Aborting."
	echo; exit 1
fi

$DEBUG && echo "[DEBUG] Reading /etc/rc.config ..."
[ -r /etc/rc.config ] && . /etc/rc.config

[ -n "$rc_done" ] && DONE=$rc_done || DONE="Ok."
[ -n "$rc_failed" ] && FAILED=$rc_failed || FAILED="FAILED!"

$DEBUG && echo "[DEBUG] Reading /etc/$NAME.conf ..."
[ -r /etc/$NAME.conf ] && . /etc/$NAME.conf

[ -z "$LOGLEVEL" ] && LOGLEVEL="7"
[ -z "$LIMIT" ] && LIMIT="5/minute"

MODULES="$MODULES \
 ip_conntrack ip_conntrack_ftp ip_conntrack_irc \
 iptable_nat ip_nat_ftp ip_nat_irc \
 ipt_LOG ipt_REJECT ipt_MASQUERADE"

export PATH="/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin"

# --- Funktionen ---

About( )
{
	$DEBUG && echo "[DEBUG] About() called ..."
	echo "$NAME, Alex' Firewall script (Release $RELEASE, $RELEASE_DATE)"
	echo "Copyright (c)2001-2003 by Alexander Barton, licensed under the GNU GPL."
	[ "$LOGHELLO" -ne 0 ] && logger -t $NAME "Alex' Firewall script (Release $RELEASE, $RELEASE_DATE)"
}

Init( )
{
	$DEBUG && echo "[DEBUG] Init() called ..."
	# Kernel-Module laden
	echo -n "- Initializing Kernel ... "
	test -n "$MODULES" && modprobe -a $MODULES > /dev/null 2>&1 || true
	if [ $? -ne 0 ]; then
		echo -e $FAILED
		exit 1
	fi
	# Kernel-Option "Always Defragment" einschalten
	test -f /proc/sys/net/ipv4/ip_always_defrag && echo 1 > /proc/sys/net/ipv4/ip_always_defrag
	# TCP SYN-Cookies einschalten
	test -f /proc/sys/net/ipv4/tcp_syncookies && echo 1 > /proc/sys/net/ipv4/tcp_syncookies
	# ICMP Echo-Broadcast verwerfen
	test -f /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts && echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
	# Gefährliche ICMP-Fehlermeldungen verwerfen
	test -f /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses && echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
	# Source Address Verification einschalten
	for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f; done
	# ICMP Redirect verwerfen
	for f in /proc/sys/net/ipv4/conf/*/accept_redirects; do echo 0 > $f; done
	# Source Routed Packets verwerfen
	for f in /proc/sys/net/ipv4/conf/*/accept_source_route; do echo 0 > $f; done
	# Spoofed Packets, Source Routed Packets und Redirect Packets loggen
	if [ "$LOG_MARTIANS" != "no" -a "$LOG_MARTIANS" != "false" ]; then
		for f in /proc/sys/net/ipv4/conf/*/log_martians; do echo 1 > $f; done
	else
		for f in /proc/sys/net/ipv4/conf/*/log_martians; do echo 0 > $f; done
	fi
	# IP Forwarding einschalten
	test -f /proc/sys/net/ipv4/ip_forward && echo 1 > /proc/sys/net/ipv4/ip_forward
	echo -e $DONE
}

Start_Fwall( )
{
	$DEBUG \
	  && echo "[DEBUG] Start_Fwall() called ..." \
	  || echo -n "- Initializing Firewall ... "

	iptables -N Check
	iptables -N CheckBlock

	iptables -N In-World
	iptables -N Out-World
	iptables -N In-Lan
	iptables -N Out-Lan

	iptables -N Fwd-World
	iptables -N Fwd-Lan

	iptables -N In-Gate
	iptables -N Out-Gate

	# "Check-Chain" einhängen
	iptables -I In-World -j Check
	iptables -I Out-World -j Check
	iptables -I In-Lan -j Check
	iptables -I Out-Lan -j Check
	iptables -I Fwd-World -j Check
	iptables -I Fwd-Lan -j Check
	iptables -I In-Gate -j Check
	iptables -I Out-Gate -j Check

	# -- CheckBlock --

	$DEBUG && echo "[DEBUG]  - CheckBlock"
	for i in $BLOCK_IPS; do
	  iptables -A CheckBlock -s $i -j DROP
	  iptables -A CheckBlock -d $i -j DROP
	done

	# Default: Return
	iptables -A CheckBlock -j RETURN
	
	# -- Check --
	
	# Diese Chain wird von jedem Paket durchlaufen, welches durch ein
	# "legales" Interface (World, Local, ...) empfangen, gesendet oder
	# geforwarded wird.

	$DEBUG && echo "[DEBUG]  - Check"

	# zunaechst pruefen, ob IP blockiert
	iptables -A Check -j CheckBlock
	
	# Fragmente verwerfen (-> "always defragment" ist schließlich an!)
	iptables -A Check --fragment -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Fragment: "
	iptables -A Check --fragment -j DROP

	# Packete einer "ungültigen" Verbindung verwerfen
	#iptables -A Check -m state --state INVALID -m limit \
	# --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Invalid Packet: "
	#iptables -A Check -m state --state INVALID -j DROP
	
	# "unsaubere" Pakete verwerfen (Achtung: buggy in Kernel 2.4.[67]!)
	#iptables -A Check -m unclean -m limit \
	# --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Unclean Packet: "
	#iptables -A Check -m unclean -j DROP
	
	# FIN+URG+PSH ("XMAS-Scan")
	iptables -A Check -p tcp --tcp-flags ALL FIN,URG,PSH -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "XMAS Flags: "
	iptables -A Check -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
	
	# SYN+RST
	iptables -A Check -p tcp --tcp-flags SYN,RST SYN,RST -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "SYN+RST Flag: "
	iptables -A Check -p tcp --tcp-flags SYN,RST SYN,RST -j DROP

	# SYN+FIN
	iptables -A Check -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "SYN+FIN Flag: "
	iptables -A Check -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
	
	# TCP-Options checken
	iptables -A Check -p tcp --tcp-option 64 -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Bogus TCP Option: "
	iptables -A Check -p tcp --tcp-option 64 -j DROP
	iptables -A Check -p tcp --tcp-option 128 -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Bogus TCP Option: "
	iptables -A Check -p tcp --tcp-option 128 -j DROP
	
	# Pakete, die zu einer aufgebauten Verbindung gehören, erlauben
	iptables -A Check -m state --state ESTABLISHED,RELATED -j ACCEPT

	# ICMP pauschal erlauben
	iptables -A Check -p icmp -j ACCEPT

	# Return-Regel
	iptables -A Check -j RETURN
	
	# -- In-World --

	$DEBUG && echo "[DEBUG]  - In-World"

	# Generische Port-Regeln
	for port in $IN_WORLD_ALLOW_TCP; do
		iptables -A In-World -p tcp --dport $port -j ACCEPT
	done
	for port in $IN_WORLD_ALLOW_UDP; do
		iptables -A In-World -p udp --dport $port -j ACCEPT
	done

	for proto in $IN_WORLD_ALLOW_PROTO; do
		iptables -A In-World -p $proto -j ACCEPT
	done

	# Default-Regel
	iptables -A In-World -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "$DefActionTxt In-World: "
	iptables -A In-World -j $DefAction
	
	# -- In-Lan --

	$DEBUG && echo "[DEBUG]  - In-Lan"

	# Generische Port-Regeln
	for port in $IN_LAN_ALLOW_TCP; do
		iptables -A In-Lan -p tcp --dport $port -j ACCEPT
	done
	for port in $IN_LAN_ALLOW_UDP; do
		iptables -A In-Lan -p udp --dport $port -j ACCEPT
	done

	for proto in $IN_LAN_ALLOW_PROTO; do
		iptables -A In-Lan -p $proto -j ACCEPT
	done

	# Default-Regel
	iptables -A In-Lan -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "$DefActionTxt In-Lan: "
	iptables -A In-Lan -j $DefAction
	
	# -- Out-World --

	$DEBUG && echo "[DEBUG]  - Out-World"

	# Generische Port-Regeln
	for port in $OUT_WORLD_ALLOW_TCP; do
		iptables -A Out-World -p tcp --dport $port -j ACCEPT
	done
	for port in $OUT_WORLD_ALLOW_UDP; do
		iptables -A Out-World -p udp --dport $port -j ACCEPT
	done

	for proto in $OUT_WORLD_ALLOW_PROTO; do
		iptables -A Out-World -p $proto -j ACCEPT
	done

	# Default-Regel
	iptables -A Out-World -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "$DefActionTxt Out-World: "
	iptables -A Out-World -j $DefAction
	
	# -- Out-Lan --

	$DEBUG && echo "[DEBUG]  - Out-Lan"

	# Generische Port-Regeln
	for port in $OUT_LAN_ALLOW_TCP; do
		iptables -A Out-Lan -p tcp --dport $port -j ACCEPT
	done
	for port in $OUT_LAN_ALLOW_UDP; do
		iptables -A Out-Lan -p udp --dport $port -j ACCEPT
	done

	for proto in $OUT_LAN_ALLOW_PROTO; do
		iptables -A Out-Lan -p $proto -j ACCEPT
	done
	
	# Default-Regel
	iptables -A Out-Lan -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "$DefActionTxt Out-Lan: "
	iptables -A Out-Lan -j $DefAction
	
	# -- Fwd-World --

	$DEBUG && echo "[DEBUG]  - Fwd-World"
	
	# Dises Chain durchläuft jewes geforwardede Paket in die weite Welt.
	# In dieser Chain wird nur explizit gefiltert! Der Default ist RETURN.
	
	# Generische Port-Regeln
	for port in $FWD_WORLD_DROP_TCP; do
		iptables -A Fwd-World -p tcp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Drop Fwd-World: "
		iptables -A Fwd-World -p tcp --dport $port -j DROP
	done
	for port in $FWD_WORLD_DROP_UDP; do
		iptables -A Fwd-World -p udp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Drop Fwd-World: "
		iptables -A Fwd-World -p udp --dport $port -j DROP
	done
	for port in $FWD_WORLD_REJECT_TCP; do
		iptables -A Fwd-World -p tcp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Reject Fwd-World: "
		iptables -A Fwd-World -p tcp --dport $port -j REJECT --reject-with tcp-reset
	done
	for port in $FWD_WORLD_REJECT_UDP; do
		iptables -A Fwd-World -p udp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Reject Fwd-World: "
		iptables -A Fwd-World -p udp --dport $port -j REJECT
	done

	# Default ACCEPT-Regel
	iptables -A Fwd-World -j ACCEPT

	# -- Fwd-Lan --

	$DEBUG && echo "[DEBUG]  - Fwd-Lan"
	
	# Dises Chain durchläuft jewes geforwardede Paket in die weite Welt.
	# In dieser Chain wird nur explizit gefiltert! Der Default ist RETURN.

	# Generische Port-Regeln
	for port in $FWD_LAN_DROP_TCP; do
		iptables -A Fwd-Lan -p tcp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Drop Fwd-Lan: "
		iptables -A Fwd-Lan -p tcp --dport $port -j DROP
	done
	for port in $FWD_LAN_DROP_UDP; do
		iptables -A Fwd-Lan -p udp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Drop Fwd-Lan: "
		iptables -A Fwd-Lan -p udp --dport $port -j DROP
	done
	for port in $FWD_LAN_REJECT_TCP; do
		iptables -A Fwd-Lan -p tcp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Reject Fwd-Lan: "
		iptables -A Fwd-Lan -p tcp --dport $port -j REJECT --reject-with tcp-reset
	done
	for port in $FWD_LAN_REJECT_UDP; do
		iptables -A Fwd-Lan -p udp --dport $port -m limit \
		  --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Reject Fwd-Lan: "
		iptables -A Fwd-Lan -p udp --dport $port -j REJECT
	done
	
	# Default ACCEPT-Regel
	iptables -A Fwd-Lan -j ACCEPT

	# -- In-Gate --

	$DEBUG && echo "[DEBUG]  - In-Gate"

	# Pakete in dieser Chain kommen zwar über ein lokales Interface,
	# stammen aber nicht aus dem LAN. Sie kamen also über ein Gate.

	# LAN Gate?
	for net in $LAN_NETS; do
		iptables -A In-Gate --src $net -j In-Lan
	done

	# Default: World Gate
	iptables -A In-Gate -j In-World

	# -- Out-Gate --

	$DEBUG && echo "[DEBUG]  - Out-Gate"

	# Pakete in dieser Chain gehen zwar auf ein lokales Interface, sind
	# aber nicht für das LAN bestimmt. Sie sollen also zu einem Gate.

	# LAN Gate?
	for net in $LAN_NETS; do
		iptables -A Out-Gate --dst $net -j Out-Lan
	done

	# Default: World Gate
	iptables -A Out-Gate -j Out-World
	
	# -- Haupt-Chains: Input & Output --

	$DEBUG && echo "[DEBUG]  - Input & Output"

	# World-Interfaces einhängen
	for iface in $WORLD_IFACES; do
		iptables -A INPUT -i $iface -j In-World
		iptables -A OUTPUT -o $iface -j Out-World
	done
	
	# Lokale-Interfaces einhängen
	for iface in $LAN_IFACES; do
		for net in $LAN_NETS; do
			iptables -A INPUT -i $iface --src $net -j In-Lan
			iptables -A OUTPUT -o $iface --dst $net -j Out-Lan
		done
		# Broadcasts
		iptables -A INPUT -i $iface --src 0.0.0.0 -j In-Lan
		iptables -A OUTPUT -o $iface --dst 255.255.255.255 -j Out-Lan
		# Geroutete Pakete
		iptables -A INPUT -i $iface -j In-Gate
		iptables -A OUTPUT -o $iface -j Out-Gate
	done

	# auf sicheren Interfaces ist alles erlaubt :-)
	for iface in $SECURE_IFACES; do
		iptables -A INPUT -i $iface -j ACCEPT
		iptables -A OUTPUT -o $iface -j ACCEPT
	done

	# Generische LOG- und DROP-Regeln für Input und Output
	# (die Default-Policies der Chains ist somit an sich überflüssig)
	iptables -A INPUT -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Drop In-Unknown: "
	iptables -A INPUT -j DROP
	iptables -A OUTPUT -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Drop Out-Unknown: "
	iptables -A OUTPUT -j DROP

	# -- Haupt-Chains: Forward --

	$DEBUG && echo "[DEBUG]  - Forward"
	
	# Forward-Filter
	for iface in $WORLD_IFACES; do
		iptables -A FORWARD -o $iface -j Fwd-World
	done
	for iface in $LAN_IFACES; do
		iptables -A FORWARD -o $iface -j Fwd-Lan
	done

	# Generische LOG- und DROP-Regeln für Forward
	# (die Default-Policies der Chains ist somit ansich überflüssig)
	iptables -A FORWARD -m limit \
	 --limit $LIMIT -j LOG --log-level $LOGLEVEL --log-prefix "Drop Fwd-Unknown: "
	iptables -A FORWARD -j DROP

	logger -t $NAME "Firewall started."

	$DEBUG \
	  && echo "[DEBUG] Start_Fwall() done." \
	  || echo -e $DONE

	[ -r /etc/fwall2.local ] && . /etc/fwall2.local
}

Start_Masq( )
{
	if [ -n "$MASQ_IFACES" ]; then
		$DEBUG \
		  && echo "[DEBUG] Start_Masq() called ..." \
		  || echo -n "- Setting up Masquerading ... "
		for iface in $MASQ_IFACES; do
			for net in $MASQ_NETS; do
				iptables -t nat -A POSTROUTING -s $net -o $iface -j MASQUERADE
			done
		done
		logger -t $NAME "Masquerading started."
		$DEBUG \
		  && echo "[DEBUG] Start_Masq() done." \
		  || echo -e $DONE
	fi

	[ -r /etc/fwall2.local-masq ] && . /etc/fwall2.local-masq
}

Stop_Fwall( )
{
	$DEBUG \
	  && echo "[DEBUG] Stop_Fwall() called ..." \
	  || echo -n "- Stopping Firewall ... "
	iptables -F
	iptables -X
	logger -t $NAME "Firewall stopped."
	$DEBUG \
	  && echo "[DEBUG] Stop_Fwall() done." \
	  || echo -e $DONE
}

Stop_Masq( )
{
	$DEBUG \
	  && echo "[DEBUG] Stop_Masq() called ..." \
	  || echo -n "- Stopping Masquerading ... "
	iptables -t nat -F
	iptables -t nat -X
	logger -t $NAME "Masquerading stopped."
	$DEBUG \
	  && echo "[DEBUG] Stop_Masq() done." \
	  || echo -e $DONE
}

Set_Default_Policies( )
{
	$DEBUG && echo "[DEBUG] Set_Default_Policies() called ..."
	iptables -P INPUT $1
	iptables -P FORWARD $1
	iptables -P OUTPUT $1
	$DEBUG && echo "[DEBUG] Set_Default_Policies() done."
}

Check_Running( )
{
	$DEBUG && echo "[DEBUG] Check_Running() called ..."
	iptables -L -n | grep "In-World" > /dev/null 2>&1
	if [ $? -ne 0 ]; then
		echo "Oops, fwall2 not active?"; echo
		exit 1
	fi
	$DEBUG && echo "[DEBUG] Check_Running() done."
}

Check_Not_Running( )
{
	$DEBUG && echo "[DEBUG] Check_Not_Running() called ..."
	iptables -L -n | grep "In-World" > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo "Oops, fwall2 already active?"; echo
		exit 1
	fi
	$DEBUG && echo "[DEBUG] Check_Not_Running() done."
}

Do_Start( )
{
	$DEBUG && echo "[DEBUG] Do_Start() called ..."
	Check_Not_Running
	Set_Default_Policies DROP
	Init
	Start_Fwall
	Start_Masq
	$DEBUG && echo "[DEBUG] Do_Start() done."
}

Do_Stop( )
{
	$DEBUG && echo "[DEBUG] Do_Stop() called."
	Check_Running
	Set_Default_Policies DROP
	Stop_Masq
	Stop_Fwall
	$DEBUG && echo "[DEBUG] Do_Stop() done."
}

Do_Reload( )
{
	$DEBUG && echo "[DEBUG] Do_Reload() called ..."
	Check_Running
	Set_Default_Policies ACCEPT
	Stop_Masq
	Stop_Fwall
	Init
	Start_Fwall
	Start_Masq
	Set_Default_Policies DROP
	$DEBUG && echo "[DEBUG] Do_Reload() done."
}

Do_Masqonly_Start( )
{
	$DEBUG && echo "[DEBUG] Do_Masqonly_Start() called ..."
	Check_Running
	logger -t $NAME "Switching to masquerading-only mode ..."
	Set_Default_Policies ACCEPT
	Stop_Fwall
	$DEBUG && echo "[DEBUG] Do_Masqonly_Start() done."
}

Do_Masqonly_End( )
{
	$DEBUG && echo "[DEBUG] Do_Masqonly_End() called ..."
	Check_Not_Running
	logger -t $NAME "Switching to full firewall mode ..."
	Set_Default_Policies ACCEPT
	Start_Fwall
	Set_Default_Policies DROP
	$DEBUG && echo "[DEBUG] Do_Masqonly_End() done."
}

Do_Status( )
{
	# Exit-Status:
	#  10: Firewall und Masquerading laufen nicht;
	#  11: Alles (Firewall und Masquerading) ist aktiv;
	#  12: Nur das Masquerading ist aktiv, die Firewall nicht.

	echo -n "$NAME: "
	iptables -L -n | grep "In-World" > /dev/null 2>&1
	if [ $? -eq 0 ]; then
	  echo "Firewall up and running."; exit 11
	else
	  iptables -t nat -L -n | grep "MASQUERADE" > /dev/null 2>&1
	  if [ $? -eq 0 ]; then
	    echo "Masquerading only."; exit 12
	  else
	    echo "Not active."; exit 10
	  fi
	fi
}

LOGHELLO=0
case "$1" in
	--start|start)
		LOGHELLO=1
		echo; About
		Do_Start
		echo
		;;
	--stop|stop)
		LOGHELLO=1
		echo; About
		Do_Stop
		echo
		;;
	--startmasqonly|startmasqonly|--masqonly|masqonly|--masq|masq)
		LOGHELLO=1
		echo; About
		Do_Masqonly_Start
		echo
		;;
	--stopmasqonly|stopmasqonly)
		LOGHELLO=1
		echo; About
		Do_Masqonly_End
		echo
		;;
	--block|block)
		if [ "$2" ]; then
		  iptables -I CheckBlock -s $2 -j DROP > /dev/null 2>&1
		  iptables -I CheckBlock -d $2 -j DROP > /dev/null 2>&1
		  if [ $? -eq 0 ]; then
		    echo "$NAME: blocked \"$2\"."
		    logger -t $NAME "blocked \"$2\"."
		  else
		    echo "$NAME: can't block \"$2\"!?"
		    logger -t $NAME "can't block \"$2\"!?"
 		  fi
		else
		  echo "Usage: $name block <ip>"
		fi
		;;
	--unblock|unblock)
		if [ "$2" ]; then
		  iptables -D CheckBlock -s $2 -j DROP > /dev/null 2>&1
		  iptables -D CheckBlock -d $2 -j DROP > /dev/null 2>&1
		  if [ $? -eq 0 ]; then
		    echo "$NAME: unblocked $2."
		    logger -t $NAME "unblocked \"$2\"."
		  else
		    echo "$NAME: can't unblock $2!?"
		    logger -t $NAME "can't unblock \"$2\"!?"
		  fi
		else
		  echo "Usage: $name block <ip>"
		fi
		;;
	--reload|reload)
		LOGHELLO=1
		echo; About
		Do_Reload
		echo
		;;
	--restart|restart)
		LOGHELLO=1
		echo; About
		tty | grep "p" > /dev/null 2>&1
		if [ $? -ne 0 ]; then
			Do_Stop; Do_Start
		else
			echo;
			echo "ERROR: Can't restart firewall if terminal is not local!"
			logger -t $NAME "Can't restart firewall: terminal is not local!"
		fi
		echo
		;;
	--status|status)
		Do_Status
		;;
	--list|list|-L)
		iptables -L -n -v | less
		;;
	--version)
		About
		;;
	--help|*)
		echo; About; echo
		echo "Usage: $name {start|stop|reload|restart}"
		echo "       $name {startmasqonly|stopmasqonly}"
		echo "       $name {block|unblock} <ip>"
		echo "       $name {status|list}"
		echo; exit 2
		;;
esac

exit 0

# -eof-
