Was soll erreicht werden?
Ein Gateway soll ein lokales Netz mit privaten IP Adressen ins Internet routen und das lokale Netz (sowie sich selbst) vor unerwünschten Zugriffen schützen. Der erste Teil der Aufgabe wird mittels Network Address Translation realisiert. Dabei geht es darum, mit nur einer einzigen echten IP, nämlich derjenigen des Gateway selbst, die entweder fest ist oder die er bei der Einwahl ins Internet vom Provider dynamisch zugewiesen bekommt, das gesamte lokale Netz mit dem Internet zu verbinden.
Da die Adressen im lokalen Netz aus einem für private Netze reservierten Adressraum stammen (im Beispiel 192.168.0.X), können sie im Internet nicht weitertransportiert werden: Jeder Router, der ein Datenpaket mit einer solchen Absenderadresse empfängt, lässt es schlicht und einfach fallen. Die einzige IP im lokalen Netz, die wirklich internettauglich ist, ist die IP des Gerätes, mit der der Gateway mit dem Internet verbunden ist, also etwa der ISDN-Karte. Nebenbei bemerkt: Nicht Rechner sondern Geräte haben IP Adressen. So wird der Gateway mindestens zwei Geräte haben, nämlich eines, das ihn mit dem Lokal Area Network (LAN) verbindet (im Beispiel die Ethernetkarte eth0) und eines, das ihn mit dem Wide Area Network (WAN) verbindet (im Beispiel die ISDN-Karte ippp0). Also hat er zwei IP Adressen: Die Ethernetkarte heißt "192.168.0.1" und die ISDN-Karte bekommt ihre eigene, echte IP bei der Einwahl vom Provider dynamisch zugewiesen.
Die NAT bewirkt nun folgendes: Empfängt der Gateway ein Paket aus dem LAN, also mit einer Absenderadresse aus dem Bereich 192.168.0.X, das eine Zieladresse im WAN hat, also ins Internet geroutet werden soll, dann ersetzt er die Absenderadresse durch seine eigene, echte IP (die der ISDN-Karte) und merkt sich die ursprüngliche Absenderadresse. Trifft das Antwortpaket ein, dann wird die ursprüngliche Absenderadresse wieder als aktuelle Zieladresse eingesetzt. Der Rechner im LAN bekommt davon nichts mit. Die NAT ist eine der Funktionen, die mit iptables konfiguriert weren können.
Der zweite Teil der Aufgabe besteht im Schutz des Gateway und des LAN vor unerwünschtem Datenverkehr. Dies geschieht durch Filtern der Datenpakete: Jedes Paket hat eine Reihe von Eigenschaften, an denen sich ablesen läßt, ob es erwünscht ist oder nicht. Dazu zählen: Protokolltyp, Absenderadresse, Zieladresse, Absenderport, Zielport, Flags (SYN, ACK, ...) etc. Nach diesen Kriterien konnte man bereits mit ipchains filtern. Darüber hinaus kann iptables den Status von Verbindungen (REALATED, ESTABLISHED, etc.) als Kriterium für die Zulässigkeit eines Datenpaketes heranziehen.
Der Weg eines Datenpaketes durch das TCP/IP System eines Linux-Gateways wird im Packet Filtering HOWTO genau beschrieben. Wichtig für uns ist die Unterscheidung der "Hauptverkehrsrichtungen":
INPUT: LAN -> Gateway
WAN -> Gateway
FORWARD: LAN -> WAN
WAN -> LAN
OUTPUT: Gateway -> LAN
Gateway -> WAN
Somit gibt es sechs Fälle, die unsere Firewall zu berücksichtigen hat. Für jeden dieser Fälle wird eine sogenannte "chain" eingerichtet. Eine chain ist eine Kette von Filterregeln, die ein Paket der Reihe nach passieren muss. Jede Filterregel kann ein Datenpaket abhängig von bstimmten Eigenschaften zu unterschiedlichen "Weiterbearbeitungen" schicken (ACCEPT, DROP, an eine andere chain, etc.). Die built-in chains INPUT, FORWARD und OUTPUT sind immer die ersten, in denen ein Paket landet. Von dort aus kann man die Pakete in selbstdefinierte chains schicken um sie dort weiterzuverarbeiten. In unserem Beispiel schicken wir die Pakete abhängig von Absender- und Zieladresse in sechs slebstdefinierte chains. Dadurch wird der gesamte Datenverkehr in Hauptverkehrswege gesplittet und die Regeln für die jeweiligen Verkehrsrichtungen werden sehr übersichtlich.
SeitenanfangSchritte zur Konfiguration der Firewall
Wie immer müssen zuerst die erforderlichen Softwarepakete installiert werden. Wir benötigen die iptables Kernelmodule und das Konfigurationsprogramm "iptables". Damit die Module letztlich auch geladen werden können, dürfen vorher keine anderen Module, die den Firewallcode des Kernels benutzen, geladen werden. Manche Disributionen (z.B. ältere SuSE) installieren "personal firewalls", die beim booten die (älteren) ipchains Module laden, so dass die iptables Module dann nicht mehr erfolgreich geladen werden können. Die Abhilfe ist einfach: Man löscht oder umbenennt die symbolischen Links in /etc/init.d/rc.X, die die personal firewalls der Distribution starten, so dass die ipchains Module beim booten nicht mehr geladen werden.
Unsere Firewallkonfiguration wird durch ein bash Script (im Beispiel "myfirewall") gesteuert. Dieses bash Script kann, wie üblich, mit den Kommandozeilenparametern start, stop, restart und status aufgerufen werden. Es lädt die erforderlichen Module, legt die benötigten chains an und füllt diese mit Regeln. Beim Aufruf mit stop werden alle selbstdefinierten chains wieder geleert und gelöscht. Also ist die Firewall nach dem Aufruf von myfirewall mit start aktiv und nach dem Aufruf mit stop inaktiv.
Damit die Firewall beim Starten und Beenden der fraglichen runlevel automatisch aktiviert und deaktiviert wird, bauen wir das Script in das Standardsystem der Ressourcenkontrolle ein:
- Das Script "myfirewall" wird in /etc/init.d kopiert.
- In /etc/init.d/rc3.d und /etc/init.d/rc5.d (für die runlevel 3 und 5 = SuSE; bei anderen Distributionen können die Nummern der runlevel mit Netzwerk anders lauten; das bekommt man in /etc/inittab heraus) werden symbolische Links angelegt, die auf /etc/init.d/myfirewall zeigen, und zwar je zwei:
a) SXXmyfirewall (zum Starten beim Booten) und
b) KXXmyfirewall (zum Anhalten beim Herunterfahren)
Dabei ist XX durch eine geignete Zahl zu ersetzen, so dass das Script zum richtigen Zeitpunkt gestartet wird. - Für das bequeme, tippfaule Benutzen des Scripts legt man in /sbin einen weiteren symbolischen Link auf myfirewall mit Namen "rcmyfirewall" an. Dann kann man, weil /sbin für den user "root" in PATH steht, auf der Shell das Script einfach durch
> rcmyfirewall startoder
> rcmyfirewall stopbedienen.
Wenn alles richtig eingerichtet ist (Ausführungsrechte nicht vergessen), dann sollte unsere Firewallkonfiguration bei jedem Systemstart automatisch aktiviert werden. Um zu sehen, ob noch Fehler beim Ausführen des Scripts auftreten, sollte man genau auf etwaige Fehlermeldungen nach einem Aufruf von Hand achten ( > rcmyfirewall start).
Das Script myfirewall
In unserem Beispiel läuft auf dem Gateway noch ein Nameserver (bind, Port 53), ein File- und Printserver (Samba, Ports 137,138,139) und ein SMTP Server (sendmail, Port 25). In einem professionellen Netzwerk würde man diese Dienste nicht auf dem Firewallrechner sondern auf eigenen Maschinen laufen lassen. In unserem Fall dagegen müssen wir die Kommunikation mit dem Gateway auf diesen Ports gezielt zulassen. Außerdem soll der Zugriff via SSH erlaubt sein (sshd, Port 22).
Die Standardbehandlung von Paketen in allen Richtungen ist DROP, d.h. es werden alle Pakete weggeworfen, die nicht explizit durch eine Regel zugelassen werden ($IT -P INPUT/FORWARD/OUTPUT DROP). Am Ende jeder chain werden alle Pakete, die es nicht geschafft haben, geloggt bevor sie endgültig gedropt werden. Dabei bekommen sie jeweils einen Präfix, der im Logfile anzeigt, um welche Richtung es sich gehandelt hat. Die Beipielkonfiguration kann noch erheblich restriktiver gemacht werden, indem man für die jeweiligen Verkehrsrichtungen engere Bedingungen an ACCEPT knüpft. Für Ergänzugs- und Änderungsvorschläge bin ich jederzeit dankbar (Email s.u.). Hier nun das Script:
#! /bin/sh
# Zuerst werden einige Variablen gesetzt, damit
# wir später im Script weniger Tipparbeit haben
# und etwaige Änderungen nur an dieser Stelle
# vornehmen müssen:
IT="/usr/sbin/iptables" # Pfad zu iptables
MP="/sbin/modprobe" # Pfad zu modprobe
GAT="192.168.0.1/32" # Gateway Adresse LAN
# /32 steht für die Netzmaske 255.255.255.255
# 192.168.0.1 ist die IP der Ethernetkarte
WIF="ippp0" # Gateway Interface WAN
# ippp0 ist die ISDN-Karte
# hier verwenden wir das Gerät statt der IP, weil
# diese dynamisch ist und sich laufend ändert,
# nicht aber das Interface
LOP="127.0.0.1/32" # Addresse des loopback device
# /32 steht für die Netzmaske 255.255.255.255
LAN="192.168.0.0/24" # Netzwerk Adresse LAN
# /24 steht für die Netzmaske 255.255.255.0
case "$1" in
start)
# Vorbereitungen:
#===============
echo -n "Starting Firewall ... "
# Lade NAT- und implizite Module
$MP iptable_nat
$MP ip_nat_ftp
$MP ip_conntrack_ftp
# Set up spoof protection
for dummy in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo "1" > $dummy
done
# Etwaige alte chains leeren und löschen und default policies setzen
$IT -F
$IT -X
$IT -P INPUT DROP
$IT -P FORWARD DROP
$IT -P OUTPUT DROP
# NAT einrichten ...
$IT -t nat -A POSTROUTING -o $WIF -s $LAN -j MASQUERADE
# ... und IP forwarding aktivieren
echo 1 > /proc/sys/net/ipv4/ip_forward
# User chains für die Verkehrswege anlegen:
# =========================================
$IT -N LanGat
$IT -N WanGat
$IT -N LanWan
$IT -N WanLan
$IT -N GatLan
$IT -N GatWan
# Traffic splitten:
# ================
$IT -A INPUT -s $LOP -d $LOP -j ACCEPT
$IT -A INPUT -s $LAN -d $GAT -j LanGat
$IT -A INPUT -i $WIF -j WanGat
$IT -A FORWARD -s $LAN -d ! $LAN -j LanWan
$IT -A FORWARD -s ! $LAN -d $LAN -j WanLan
$IT -A OUTPUT -s $LOP -d $LOP -j ACCEPT
$IT -A OUTPUT -s $GAT -d $LAN -j GatLan
$IT -A OUTPUT -o $WIF -j GatWan
# Die user chains mit Regeln füllen:
# ==================================
# Regeln für die Richtung LAN -> Gateway ...
# a) named(dns)
$IT -A LanGat -p udp --dport 53 -j ACCEPT
# b) smbd/nmbd(smb)
$IT -A LanGat -p udp --dport 137 -j ACCEPT
$IT -A LanGat -p udp --dport 138 -j ACCEPT
$IT -A LanGat -p tcp --dport 139 -j ACCEPT
$IT -A LanGat -p tcp --sport 139 -j ACCEPT
# c) sendmail(smtp)
$IT -A LanGat -p tcp --dport 25 -j ACCEPT
# d) sshd(ssh)
$IT -A LanGat -p tcp --dport 22 -j ACCEPT
# e) ping
$IT -A LanGat -p icmp -m limit --limit 4/s -j ACCEPT
# ... der Rest wird geloggt und weggeschmissen ...
$IT -A LanGat -j LOG --log-prefix "FW Drop LAN->gateway: "
# Regeln für die Richtung WAN -> Gateway ...
# a) named(dns)
$IT -A WanGat -p udp --sport 53 -m state --state ESTABLISHED -j ACCEPT
# b) sendmail(smtp)
$IT -A WanGat -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT
# ... der Rest wird geloggt und weggeschmissen ...
$IT -A WanGat -j LOG --log-prefix "FW Drop WAN->gateway: "
# Regeln für die Richtung LAN -> WAN ...
# Hier könnte man die Kommunikationsmöglichkeiten für die Rechner
# im LAN einschränken um z.B. Trojanern die Kontaktaufnahme mit Rechnern
# im Internet zu verwehren. In diesem Beispiel ist von "drinnen" nach
# "draussen" alles erlaubt. Die Zeile für das Loggen und Droppen steht
# also für den Fall hier, dass man die generelle ACCEPT Regel durch etwas
# restriktiveres ersetzt.
$IT -A LanWan -j ACCEPT
# ... der Rest wird geloggt und weggeschmissen ...
$IT -A LanWan -j LOG --log-prefix "FW Drop LAN->WAN: "
# Regeln für die Richtung WAN -> LAN ...
# Das Zulassen von Paketen mit dem Verbindungsstatus RELATED oder ESTABLISHED
# ermöglicht *Antworten* auf http, nntp, smtp, pop3 etc. etc. und:
# passives FTP. Alle Verbindungen, die neu oder
# ungültig sind (wie etwa Portscans), werden nicht zugelassen.
$IT -A WanLan -m state --state RELATED,ESTABLISHED -j ACCEPT
# ... der Rest wird geloggt und weggeschmissen ...
$IT -A WanLan -j LOG --log-prefix "FW Drop WAN->LAN: "
# Regeln für die Richtung Gateway -> LAN ...
# a) named(dns)
$IT -A GatLan -p udp --sport 53 -j ACCEPT
# b) smbd/nmbd(smb)
$IT -A GatLan -p udp --sport 137 -j ACCEPT
$IT -A GatLan -p udp --sport 138 -j ACCEPT
$IT -A GatLan -p tcp --sport 139 -j ACCEPT
$IT -A GatLan -p tcp --dport 139 -j ACCEPT
# c) sendmail(smtp)
$IT -A GatLan -p tcp --sport 25 -j ACCEPT
# d) sshd(ssh)
$IT -A GatLan -p tcp --sport 22 -j ACCEPT
# e) ping
$IT -A GatLan -p icmp -m limit --limit 4/s -j ACCEPT
# ... der Rest wird geloggt und weggeschmissen ...
$IT -A GatLan -j LOG --log-prefix "FW Drop gateway->LAN: "
# Regeln für die Richtung Gateway -> WAN ...
# a) named(dns)
$IT -A GatWan -p udp --dport 53 -j ACCEPT
# b) sendmail(smtp)
$IT -A GatWan -p tcp --dport 25 -j ACCEPT
# ... der Rest wird geloggt und weggeschmissen ...
$IT -A GatWan -j LOG --log-prefix "FW Drop gateway->WAN: "
echo "done."
;;
stop)
echo -n "Shutting down Firewall ... "
# Chains leeren und löschen und default policies setzen
$IT -F
$IT -X
$IT -P INPUT ACCEPT
$IT -P OUTPUT ACCEPT
$IT -P FORWARD ACCEPT
# Disable IP forwarding
echo 0 > /proc/sys/net/ipv4/ip_forward
echo "done."
;;
restart)
$0 stop
$0 start
;;
status)
echo "Checking for Firewall ... "
$IT -L -n -v
echo "done."
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
exit 1
;;
esac
exit 0
Konfiguration der Clients
Die Clients bekommen je eine IP Adresse aus dem lokalen, privaten Netz (hier: 192.168.0.X) und die Netzmaske 255.255.255.0. Als default gateway wird die Adresse des Linux Gateways (hier: 192.168.0.1) eingetragen. Proxy-Einstellungen sind nicht erforderlich. Der NAT Gateway arbeitet vollständig transparent. Nameserver ist ebenfalls 192.168.0.1 (insofern er auch läuft, siehe Anleitung zu bind) oder der Nameserver des Providers.
SeitenanfangDiagnosemöglichkeiten bei Problemen
- Ist das Programm "iptables" überhaupt installiert?
> whereis iptables - Startet das Script ohne Fehlermeldungen?
> rcmyfirewall restart - Wird myfirewall auch direkt beim Booten ausgeführt?
> rcmyfirewall status
nach dem Booten sollte eine Auflistung der verschiedenen chains und Regeln zeigen. - Werden versehentlich gewünschte Pakete herausgefiltert?
> tail -f /var/log/messages