Linux Firewall mit ipchains

22.05.2001 von Dr. Peter Beringer
Auf einem abgesicherten Linux lässt sich mittels ipchains eine wirkungsvolle Firewall realisieren. Schritt für Schritt zeigt Ihnen dieser Beitrag, wie Sie dabei vorgehen sollten.

Auf Basis des abgesicherten Systems aus dem ersten Teil der Artikelreihe können Sie sich nun daran machen, das IPv4-Firewalling per ipchains auzusetzten.

Überprüfen Sie dazu zunächst, ob der aktive Kernel dies überhaupt unterstützt. Die dazugehörigen Einträge im /proc-Dateisystem lauten /proc/net/ip_fwchains (beinhaltet maschinenlesbar alle aktiven Filter) und/proc/net/ip_fwnames (beinhaltet die Namen aller Listen).

Existieren diese Einträge nicht, ist zunächst ein neuer Kernel zu kompilieren. Folgende Optionen müssen hierbei in der Datei/usr/src/linux/.config aktiviert sein:

Einträge in .config

Name

Eintrag

Zusätzliche Information

Packet socket

CONFIG_PACKET=y

Notwendig für tcpdump

Network firewalls

CONFIG_FIREWALL=y

IP: firewalling

CONFIG_IP_FIREWALL=y

IP: transparent proxy support

CONFIG_IP_TRANSPARENT_PROXY=y

Nur bei Masquerading notwendig

IP: masquerading

CONFIG_IP_MASQUERADE=y

Nur bei Masquerading notwendig

IP: ICMP masquerading

CONFIG_IP_MASQUERADE_ICMP=y

Nur bei Masquerading notwendig

Weitere Informationen, wie Sie einen neuen Kernel kompilieren und installieren, finden Sie in den How-tos.

Kontrollprogramm ipchains

Ist Firewalling im Kernel aktiviert, stehen drei vordefinierte Filterlisten, die sogenannten "chains", zur Verfügung. Sie heißen "input", "forward" und "output".

Zudem können diese drei fest installierten Listen auf benutzerdefinierte Filter zurückgreifen, um die Regelsätze zu strukturieren und zu dezimieren.

Die Portfilterregeln lassen sich im Falle vom Kernel 2.2.x mit dem Programm ipchains verwalten. Zur ersten Information bieten die How-tos einen guten Überblick.

Kurzreferenz ipchains

Die Befehlszeile von ipchains enthält als erste Option das auszuführende Kommando. Danach folgen verschiedene Optionen, die vom jeweiligen Kommando abhängen. Die wichtigsten Kommandos von ipchains sind:

Kommandozeile von ipchains

ipchains ...

Aktion

-L optionen

Auflisten aller Regeln

-L listenname optionen

Auflisten aller Regeln einer Liste

Zusatzoptionen

-n

keine DNS-Auflösung (meist vorteilhaft)

-v

ausführlich (mit Paketzähler und spezifizierter Schnittstelle)

--line-numbers

mit Zeilennummer

-P listenname ziel optionen

Setzen des Standardverhaltens (Policy) von vordefinierten Listen

-A listenname regel optionen

Anfügen einer Regel am Ende einer Liste

-I listenname nummer regel optionen

Einfügen einer Regel an einer bestimmten Position einer Liste (vor die Regel mit der betreffenden "Nummer")

-I listenname regel optionen

Einfügen einer Regel am Anfang einer Liste

-R listenname nummer regel optionen

Ersetzen einer Regel an einer bestimmten Position einer Liste (angeben durch deren "Nummer")

-D listenname nummer optionen

Löschen einer Regel an einer bestimmten Position in einer Liste (angegeben durch die betreffende "Nummer")

-D listenname regel optionen

Löschen einer entsprechenden Regel in einer Liste

-F listenname

Löschen aller Regeln in einer Liste

-N neuerlistenname

Erstellen einer benutzerdefinierten Liste

-X listenname

Löschen einer leeren benutzerdefinierten Liste

-Z listenname optionen

Löschen der Paket- und Byte-Zähler einer Liste

-C listenname regel optionen

Test einer Liste mit einem simulierten Paket entsprechend der angegebenen Regel

-M -S optionen

Setzen der Maskierungsparameter

-M -L optionen

Anzeigen aller aktuell maskierten Verbindungen

Die Regeln sind innerhalb der einzelnen Listen (input, output etc.) durchnummeriert und damit eindeutig identifizierbar. Beim Löschen von Regeln (-D) können Sie statt der Nummer auch Ihre Eigenschaften angeben.

Eigenschaften von Regeln

Die einzelnen Regeln sind zeilenorientiert abgelegt und lassen sich in den jeweiligen Listen einzeln einfügen oder löschen. Die Filter arbeiten für jedes Netzwerkpaket, das die Firewall passiert, eine Liste ab, bis das Paket eine Regel erfüllt. Erfüllt es keine Regel, kommt die Default-Aktion (Policy) für die jeweilige Liste zum Einsatz.

Die Definition einer Regel bestimmt zum Beispiel, auf welche Ports oder Source-Adressen die Regel passt. Beim Anlegen oder Ändern einer Regel können Sie über eine ganze Reihe von Optionen in der Kommandozeile die Eigenschaften der Regel festlegen. Einen Überblick über die ipchains-Optionen bzw. Regeleigenschaften gibt die folgende Tabelle:

Parameter für Regeln

Regelparameter

Beschreibung

-p protokollnummer

Protokoll des IPv4-Pakets, z.B. tcp, udp, icmp, all oder eine Nummer, die in /etc/protocols definiert ist

-s quelladresse

Quelladresse/-netzwerk

-s quelladresse port

Quelladresse/-netzwerk mit Angabe des Quellports/-portbereichs

-sport port

Quellport/-portbereich ohne Angabe einer Adresse

-d zieladresse

Zieladresse/-netzwerk

-d zieladresse

Zieladresse/-netzwerk mit Angabe des Zielports/-portbereichs

-dport port

Zielport/-portbereich ohne Angabe einer Adresse

--icmp-type typbezeichnung

ICMP-Typ bzw. Untertyp

-i schnittstelle

Schnittstelle des Pakets (bei input ankommendes, bei forward und output ausgehendes)

-i schnittstellenpräfix+

Schnittstellen, die mit dem Präfix beginnen

-y

Paket initiiert eine TCP-Verbindung (SYN gesetzt, ACK und FIN gelöscht)

-j aktion

Aktion beim Erfüllen der Regel (nicht zwingend nötig)

-l

Protokollieren des Pakets, wenn Regel passend

! parameter

Negiert den Parameter, z.B. Adresse, Port, Verbindungsaufbau, Schnittstelle

portstart:portende

Definiert einen Portbereich von "portstart" bis "portende"

portstart:

Definiert einen Portbereich von "portstart" bis 65535

:portende

Definiert einen Portbereich von 0 bis "portende"

Aktionen von Regeln

Passt eine Regel auf ein Netzwerkpaket, dann wird die angegebene Aktion ausgeführt. Die jeweilige Aktion geben Sie beim Anlegen oder Ersetzen der Regel als Option "-j" in der ipchains-Zeile an.

Mögliche Aktionen von ipchains

Aktion

Beschreibung

ACCEPT

Paket wird akzeptiert und verlässt den Filter.

DENY

Paket wird verworfen, keine Benachrichtigung des Absenders durch ICMP.

REJECT

Ein ICMP-Paket wird an den Absender zurückgeschickt, soweit möglich (nicht, wenn das REJECTed Paket selbst ein ICMP-Paket ist, denn dies ist per Definition verboten: RFC 792).

listenname

Benutzerdefinierte Liste wird abgearbeitet.

REDIRECT port

Paket wird an einen spezifizierten lokalen Port weitergeleitet (nur für benutzte Listen im Input-Filter).

RETURN

Benutzerdefinierte Liste wird verlassen und zur aufrufenden Liste zurückgekehrt (nur in benutzerdefinierten Filterlisten).

MASQ

Paket wird mit der lokalen ausgehenden Adresse maskiert (nur für benutzte Listen im Forward-Filter).

Ein Beispiel für eine Regel, die jeden über die Schnittstelle ppp0 (Wählverbindung per PPP) ankommenden TCP-Verbindungsaufbau blockiert und mitprotokolliert, ist

ipchains -I input -i ppp0 -p tcp -y -j DENY -l

Die Aufgaben der einzelnen Optionen können Sie den oben aufgeführten Tabellen entnehmen.

Rückzug auf Standardregeln

Ist keine Aktion angegeben, kommt die nächste Regel an die Reihe. Wenn das Ende der Liste erreicht ist, schlägt im Falle der vordefinierten Listen das eingestellte Standardverhalten (Policy) zu. Bei benutzerdefinierten Listen springt der Filter zur aufrufenden Liste zurück. Ist für eine Regel die Protokollierung (Option "-l") aktiviert, schickt der Kernel Informationen durch den Kernel-Log-Daemon (klogd) an den System-Log-Daemon (syslogd) vom Typ (Facility) "kern" und Priorität (Priority) "debug".

Diese Logzeilen enthalten außer den Paketdaten auch die Nummer der Regel. Im hier gezeigten Beispiel war es Regel 1 (Angabe #1) der Filterliste "input". Beim Testen der ipchains-Konfiguration ist es immer hilfreich, auf einem Konsolenfenster ein

tail -f /var/log/kernel

beziehungsweise ein

tail -f /var/log/messages

mitlaufen zu lassen. Damit erkennen Sie fehlende Regeln frühzeitig und können andere von der Protokollierung ausnehmen.

Erste wichtige Portfilterregeln

Eine Firewall sollte immer nach folgendem Grundsatz arbeiten: "Alles, was nicht erlaubt ist, ist verboten". Bei Linux mit Kernel 2.2.x ist nur eine einfache Portfilterung möglich. Es existieren keine "state tables", in welchen der aktuelle Status einer Verbindung gespeichert ist. Deshalb muss für jeden benötigten Dienst der Datenverkehr statisch erlaubt werden.

Mit diesen Kenntnissen können Sie damit beginnen, das Firewalling systematisch zu konfigurieren. Den Beginn macht das Festlegen des Standardverhaltens (Policy) der vorinstallierten Filterlisten. Für die input-Liste bietet sich ein DENY an, denn damit ist die Firewall für eingehende abgelehnte Pakete unsichtbar. Absender von ausgehenden oder weitergeleiteten Paketen sollten bei Filterung via ICMP darüber benachrichtigt werden, sonst entstehen unnötige Verzögerungen beim Versuch eines verbotenen Verbindungsaufbaus. Sie erreichen das durch die Policy REJECT für die Listen output und forward.

# Setze Standardverhalten der eingebauten Filterlisten
ipchains -P input DENY
ipchains -P forward REJECT
ipchains -P output REJECT

Ein Problem besteht allerdings noch: Sie erhalten keine Informationen über Pakete, die das Ende der Liste erreichen und dann entsprechend der Policy behandelt werden. Dies behindert die Fehlersuche und die Optimierung. Deshalb sollten Sie zumindest temporär am Ende jeder Standardliste eine Regel einzufügen, die abgelehnte Pakete protokolliert.

# Protokolliere Pakete, die das Ende der Liste erreichen
ipchains -A input -j DENY -l
ipchains -A forward -j REJECT -l
ipchains -A output -j REJECT -l

Achtung: Falls Sie die jetzt weitere Regeln eingeben, während sich die eben gezeigten schon in den Listen befinden, werden diese nie abgearbeitet. Löschen Sie also obige Regeln wieder und fügen Sie sie immer am Ende ein. Alternativ können Sie auch ein Skript erstellen (siehe nächste Seiten) und damit den Regelsatz aufbauen.

Portfilter: erlaubte Zugriffe

Als erste wichtige Filterregel sollte man den lokalen Verkehr erlauben, der über die sogenannte loopback-Schnittstelle (lo) läuft. Strenggenommen müssten Sie auch hier Filter installieren, doch das würde den Rahmen dieses Artikels sprengen:

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

Falls Sie die Firewall per SSH fernadministrieren wollen, erlaubt die nächste Regel den Zugriff vom internen Netz über Port 22 auf die Firewall. Die benötigten Angaben sind der interne Netzwerkbereich (z.B. 192.168.1.0/24) sowie die IPv4-Adresse der internen Schnittstelle (hier 192.168.1.1 an eth0). Anzumerken ist auch, dass SSH-Clients von Unix-Hosts teilweise mit Quellports zwischen 513 und 1023 eine Verbindung aufbauen, Windows-Hosts (mit z. B. PuTTY) dagegen immer ab 1024. Eingehende Pakete lassen Sie mit folgender Regel passieren:

# intern -> SSH auf Firewall (eingehend)
ipchains -A input -i eth0 -p tcp -s 192.168.1.0/24 512: -d 192.168.1.1 22 -j ACCEPT

Damit der SSH-Dienst auch Antwortpakete zurücksenden kann, müssen diese natürlich auch erlaubt sein. Das erledigt diese Regel:

# intern -> SSH auf Firewall (Antwort)
ipchains -A output -i eth0 -p tcp -s 192.168.1.1 22 -d 192.168.1.0/24 512: ! -y -j ACCEPT

Sie erlaubt durch den Schalter "! -y" keinen von der Firewall ausgehenden Verbindungsaufbau mit Quellport 22. Das behindert nicht die Funktionalität, sondern erhöht die Sicherheit.

Webproxy auf der Firewall

Falls dem Intranet ein Webproxy auf der Firewall zur Verfügung stehen soll, muss auch die Verbindung von intern zu diesem erlaubt sein. Nach Festlegen des definierten Ports (3128, 8080 oder 8000) helfen hier folgende Regeln:

# intern -> Webproxy auf Firewall + Antwort
ipchains -A input -i eth0 -p tcp -s 192.168.1.0/24 1024: -d 192.168.1.1 3128 -j ACCEPT
ipchains -A output -i eth0 -p tcp -s 192.168.1.1 3128 -d 192.168.1.0/24 1024: ! -y -j ACCEPT

Damit der Webproxy nun allerdings selbst die geforderten Inhalte aus dem Internet holen kann, sind dessen Zugriffe ebenfalls freizuschalten. Das Beispiel geht von folgenden Annahmen aus:

Bei Bedarf fügen Sie ähnliche Filter mit anderen Ports hinzu. Wie schon im ersten Teil erwähnt, soll die Firewall für abgehende Verbindungen nur Ports aus dem Bereich 32768 bis 60999 benutzen. Also sind auch nur diese zugelassen.

# Webproxy -> Internet (Port 80/HTTP) + Antwort
ipchains -A output -i ppp0 -p tcp --sport 32768:60999 --dport 80 -j ACCEPT
ipchains -A input -i ppp0 -p tcp --sport 80 --dport 32768:60999 ! -y -j ACCEPT
# Webproxy -> Internet (Port 443/HTTPS) + Antwort
ipchains -A output -i ppp0 -p tcp --sport 32768:60999 --dport 443 -j ACCEPT
ipchains -A input -i ppp0 -p tcp --sport 443 --dport 32768:60999 ! -y -j ACCEPT
# Webproxy -> Internet (FTP:Kommandokanal) + Antwort
ipchains -A output -i ppp0 -p tcp --sport 32768:60999 --dport 21 -j ACCEPT
ipchains -A input -i ppp0 -p tcp --sport 21 --dport 32768:60999 ! -y -j ACCEPT
# Webproxy -> Internet (FTP: passiver Datentransfer) + Antwort
ipchains -A output -i ppp0 -p tcp --sport 32768:60999 --dport 1024: -j ACCEPT
ipchains -A input -i ppp0 -p tcp --sport 1024: --dport 32768:60999 ! -y -j ACCEPT

Wichtig ist hier, dass die Regeln in der input-Liste unbedingt mit "! -y" definiert sind. Andernfalls kann jeder aus dem Internet eine Verbindung zu Ports zwischen 32768 und 60999 aufbauen. Dort könnten noch Dienste aktiv sein wie etwa Netzwerk-Backup-Software.

Falls die Firewall auf der externen Schnittstelle eine feste IPv4-Adresse hat, sollte diese in den Regeln auch dediziert konfiguriert sein, als Beispiel hier für 1.2.3.4 und HTTP:

# # Webproxy -> Internet (Port 80/HTTP), ausgehende Adresse bekannt + Antwort
ipchains -A output -i ppp0 -p tcp -s 1.2.3.4 32768:60999 --dport 80 -j ACCEPT
ipchains -I input -i ppp0 -p tcp --sport 80 -d 1.2.3.4 32768:60999 ! -y -j ACCEPT

Surfen benötigt auch DNS

Das Surfen im Internet wird bis jetzt nicht funktionieren, da DNS-Anfragen der Firewall in Richtung Internet noch verboten sind. Die nächsten Filterregeln helfen hier weiter und erlauben UDP.

# DNS -> Internet (UDP) + Antwort
ipchains -A output -i ppp0 -p udp --sport 32768:60999 --dport 53 -j ACCEPT
ipchains -A input -i ppp0 -p udp --sport 53 --dport 32768:60999 -j ACCEPT

Wenn allerdings Antworten auf DNS-Anfragen eine Paketgröße von 512 Bytes überschreiten, wird dem Surfen ein jähes Ende gesetzt. Der Transport der DNS-Daten schaltet dann nämlich automatisch auf TCP um. Aus diesem Grund muss dies auch erlaubt werden:

# DNS -> Internet (TCP) + Antwort
ipchains -A output -i ppp0 -p tcp --sport 32768:60999 --dport 53 -j ACCEPT
ipchains -A input -i ppp0 -p tcp --sport 53 --dport 32768:60999 ! -y -j ACCEPT

Beim Regelsatz für DNS-Anfragen über UDP sollte eine Warnlampe beim Firewall-Administrator aufleuchten! Da der Linux-Kernel 2.2.x nur statische Filter zur Verfügung stellt, kann jeder beliebige Host im Internet über ein geeignetes Werkzeug (etwa netcat) eine UDP-Verbindung mit Quellport 53 zu einem Port zwischen 32768 und 60999 auf die Firewall aufbauen. Eventuell sind jedoch UDP-Dienste auf solchen Ports aktiv, die sich nicht an eine bestimmte, interne Schnittstellenadresse binden lassen. Werden diese Ports nicht extra gegen eingehende Pakete geblockt, dann entsteht hier ein massives Sicherheitsloch. Ein Beispiel für einen dedizierten Portblocker (hier Port 40000) wäre:

# Dedizierter Portblocker (mit Log) wegen eines von intern benötigten Dienstes auf diesem Port
ipchains -A input -i ppp0 -p tcp --dport 40000 -j DENY -l
ipchains -A input -i ppp0 -p udp --dport 40000 -j DENY -l

Erstellen eines Skripts für den Regelsatz

Bislang ist die Firewall noch ziemlich zugesperrt, das Intranet kann nur über den Proxy surfen. Trotzdem haben sich schon acht Regeln pro Liste angesammelt. Dies kann schnell auf das zehnfache ansteigen, worunter dann die Übersicht leidet. Auch das spätere Nachvollziehen durch mangelhafte Dokumentationsmöglichkeiten in diversen grafischen Konfigurationswerkzeugen ist meist schwierig.

Damit Ihr Regelsatz nicht zu einem "write once, edit never"-Unterfangen mutiert, empfiehlt sich der Einsatz eines eigenen Firewall-Setup-Scripts. Dieses wird beim Start der Firewall automatisch aktiviert. Am Ende dieses Beitrags finden Sie eine Basis für ein eigenes Firewall-Setup-Script.

Außerdem sollten Sie der Übersichtlich halber benutzerdefinierte Listen verwenden. Da diese bei strukturiertem Einsatz anfänglich verwirrend sind, gehen wir hier nicht näher darauf ein. Stattdessen verweisen wir auf ein zum Download bereitgestelltes Script.

Ein Vorteil eines solchen Scripts ist auch, dass Sie die Regeln direkt dokumentieren und kommentieren können. Zudem besteht die Möglichkeit, Regelsätze automatisch zu konstruieren.

Aktivieren des Scripts

Nachdem Sie die Filterkommandos im Skript eingefügt haben, können Sie es mit

/etc/rc.d/init.d/firewalling start

aktivieren. Der Aufruf von

/etc/rc.d/init.d/firewalling stop

löscht alle Regeln und benutzerdefinierten Listen, entfernt geladene Masquerading-Module und schaltet die Paketweiterleitung global ab. Das Skript

/etc/rc.d/init.d/firewalling restart

führt "stop" und "start" nacheinander aus und sollte dann verwendet werden, wenn man den Regelsatz von der Ferne aus modifizieren will.

Das Firewall-Skript kann und sollte beim Systemstart automatisch abgearbeitet werden. Unter Red Hat Linux wird es dazu in das Verzeichnis "/etc/rc.d/init.d" unter dem Namen "firewalling" kopiert. Mit

chkconfig firewalling on

legen Sie einen Verweis in den einzelnen Runlevel-Verzeichnissen ab. Die Informationen dazu bezieht chkconfig aus der Zeile # chkconfig: 2345 12 89 des Skripts.

DNS-Auflösung für intern

Damit die Clients für DNS-Anfragen keine Verbindung ins Internet aufbauen müssen, sollten Sie auf der Firewall auch einen Caching-DNS-Server installieren. Achten Sie darauf, dass der Server nur an der internen bzw. loopback-Schnittstelle aktiv ist, damit er unter keinen Umständen von außen benutzbar ist. Dies erreichen Sie beispielsweise bei named (BIND) durch die Konfigurationsoption "listen-on{127.0.0.1;192.168.1.1;};". Die entsprechenden Portfilterregeln lauten dann:

# intern -> DNS auf Firewall (UDP)
ipchains -A input -i eth0 -p udp -s 192.168.1.0/24 1024: -d 192.168.1.1 53 -j ACCEPT
# Antwort erlauben
ipchains -A output -i eth0 -p udp -s 192.168.1.1 53 -d 192.168.1.0/24 1024: -j ACCEPT
# intern -> DNS auf Firewall (TCP)
ipchains -A input -i eth0 -p tcp -s 192.168.1.0/24 1024: -d 192.168.1.1 53 -j ACCEPT
# Antwort erlauben
ipchains -A output -i eth0 -p tcp -s 192.168.1.1 53 -d 192.168.1.0/24 1024: ! -y -j ACCEPT

auth/ident und ICMP

Ein weiterer wichtiger Punkt ist, dass noch viele im Internet befindliche unter Unix laufende FTP-Server (und auch E-Mail-Server) bei einem Verbindungsaufbau einen sogenannten "auth/ident-lookup" durchführen. Sie wollen dadurch erfahren, welche Benutzerkennung auf dem Client eben diese Verbindung aufbauen will.

Dieser Dienst kann im Intranet nützlich sein (in Zusammenarbeit mit "tcp_wrapper" für erweiterte Zugriffskontrolle), doch im Internet ist er nicht mehr wirklich sinnvoll (außer vielleicht bei IRC). Bei Windows-Clients ist dieser Dienst sowieso nicht standardmäßig vorhanden, bei Unix-Clients hoffentlich deaktiviert.

Das Login eines solchen FTP-Servers erscheint nur, wenn diese Anfrage erfolgreich war oder eine bestimmte Zeit vergangen ist. Da auf einer Firewall ein solcher Dienst nicht aktiv ist, können Verbindungen zu FTP-Server über den Proxy etwas länger dauern, denn in der bisherigen Konfiguration verwirft die Firewall einfach die Pakete, ohne dem Absender (FTP-Server) eine Rückmeldung zu geben.

Um dies zu ändern und damit die Verzögerung zu verkürzen, kommen zwei weitere Regeln ins Spiel. Die erste führt beim Versuch eines Verbindungsaufbaus einen "reject" durch, indem ein ICMP-Paket mit dem Typ "port-unreachable" zurückgeschickt wird. Das Versenden eben dieses Pakets erlaubt die zweite Regel.

# Internet -> Firewall: auth/ident-lookup (REJECT)
ipchains -A input -i ppp0 -p tcp -dport 113 -y -j REJECT
# Firewall -> Internet: port unreachable
ipchains -A output -i ppp0 -p icmp --icmp-type port-unreachable -j ACCEPT

Unreachable ICMP-Pakete erlauben

Auch sind ankommende ICMP-Pakete aus den Gruppen "unreachable", "time-exceeded", "source-quench" und "parameter-problem" sowohl von intern als auch von extern zu erlauben. Damit erfährt die Firewall, wenn Verbindungsfehler auftreten, und die Verbindungen beleiben nicht bis zum Timeout bestehen.

# Internet -> Firewall: ICMP-Pakete zur Benachrichtung bei Verbindungsproblemen
ipchains -A input -i ppp0 -p icmp --icmp-type destination-unreachable -j ACCEPT
# time exceeded
ipchains -A input -i ppp0 -p icmp --icmp-type time-exceeded -j ACCEPT
# source quench
ipchains -A input -i ppp0 -p icmp --icmp-type source-quench -j ACCEPT
# parameter problem
ipchains -A input -i ppp0 -p icmp --icmp-type parameter-problem -j ACCEPT
# intern -> Firewall: ICMP-Pakete zur Benachrichtung bei Verbindungsproblemen
ipchains -A input -i eth0 -p icmp -s 192.168.1.0/24 -d 192.168.1.1 --icmp-type destination-unreachable -j ACCEPT
# time exceeded
ipchains -A input -i eth0 -p icmp -s 192.168.1.0/24 -d 192.168.1.1 --icmp-type time-exceeded -j ACCEPT
# source quench
ipchains -A input -i eth0 -p icmp -s 192.168.1.0/24 -d 192.168.1.1 --icmp-type source-quench -j ACCEPT
# parameter problem
ipchains -A input -i eth0 -p icmp -s 192.168.1.0/24 -d 192.168.1.1 --icmp-type parameter-problem -j ACCEPT

Pings und andere Feinheiten

Falls der Administrator Verbindungstests durchführen will, so muss er Ping-Pakete und deren Antworten freischalten.

# Firewall -> Internet: ICMP-Pakete für Verbindungstests
ipchains -A output -i ppp0 -p icmp --icmp-type echo-request -j ACCEPT
# Antwort erlauben
ipchains -A input -i ppp0 -p icmp --icmp-type echo-reply -j ACCEPT

# Firewall -> intern: ICMP-Pakete für Verbindungstests
ipchains -A output -i eth0 -p icmp -s 192.168.1.1 -d 192.168.1.0/24 --icmp-type echo-request -j ACCEPT
# antwort erlauben
ipchains -A input -i eth0 -p icmp -s 192.168.1.0/24 -d 192.168.1.1 --icmp-type echo-reply -j ACCEPT

Zum Abschluss sollten Sie noch einige ausgehende ICMP-Nachrichten nach intern und extern freischalten, damit auch die Firewall den Sender oder Empfänger bei Problemen benachrichtigen kann:

Zum einen Meldungen nach außen, die für die Flusskontrolle und die "Path MTU discovery" (Erkennen der maximal transportablen Paketgröße zur Vermeidung von Fragmentierung) notwendig sind:

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

Zum anderen Meldungen nach innen bei Verbindungsproblemen:

# Firewall -> intern: ICMP-Pakete zur Benachrichtigung bei Verbindungsproblemen
ipchains -A output -i eth0 -p icmp -s 192.168.1.1 -d 192.168.1.0/24 --icmp-type source-quench -j ACCEPT
ipchains -A output -i eth0 -p icmp -s 192.168.1.1 -d 192.168.1.0/24 --icmp-type destination-unreachable -j ACCEPT
ipchains -A output -i eth0 -p icmp -s 192.168.1.1 -d 192.168.1.0/24 --icmp-type time-exceeded -j ACCEPT
ipchains -A output -i eth0 -p icmp -s 192.168.1.1 -d 192.168.1.0/24 --icmp-type parameter-problem -j ACCEPT

Damit sollte die problemlose Nutzung des Web über den Proxy auf der Firewall bereits möglich sein.

Durchgreifender Verkehr

Auf das Thema Masquerading gehen wir im nächsten Teil der Artikelreihe im Detail ein. Doch noch ein paar Worte zum direkten durchgreifenden Netzwerkverkehr. In manchen Szenarien existiert direktes Routing von intern oder extern in eine DMZ oder es kommen intern offizielle IPv4-Adressen zum Einsatz. Der Netzwerkverkehr soll zwar gefiltert, jedoch nicht via Adressumsetzung in irgendeiner Weise verfälscht werden (etwa wegen Authentifizierung anhand der Client-Adresse oder Nutzung von IPsec). Dazu muss folgendes erfüllt sein:

Ein Beispiel für den erlaubten direkten Zugriff von intern auf Webserver, die im Netzwerk 7.8.9.0/24 plaziert sind, lautet wie folgt:

# intern -> Webserver in 7.8.9.0/24
ipchains -A input -i eth0 -p tcp -s 192.168.1.0/24 1024: -d 7.8.9.0/24 80 -j ACCEPT
ipchains -A forward -i eth1 -p tcp -s 192.168.1.0/24 1024: -d 7.8.9.0/24 80 -j ACCEPT
ipchains -A output -i eth1 -p tcp -s 192.168.1.0/24 1024: -d 7.8.9.0/24 80 -j ACCEPT
# Antwortpakete
ipchains -A input -i eth1 -p tcp -s 7.8.9.0/24 80 -d 192.168.1.0/24 1024: ! -y -j ACCEPT
ipchains -A forward -i eth0 -p tcp -s 7.8.9.0/24 80 -d 192.168.1.0/24 1024: ! -y -j ACCEPT
ipchains -A output -i eth0 -p tcp -s 7.8.9.0/24 80 -d 192.168.1.0/24 1024: ! -y -j ACCEPT

Benutzedefinierte Listen

Da sicher auch Regeln für andere Verbindungen und ICMP hinzukommen, resultiert das sehr schnell in unübersichtlichen Standardlisten, insbesondere, da jede Verbindung sechs Regeln produziert. Hier sollte der Einsatz von zwei benutzerdefinierten Listen erwägt werden, die dann je dreimal von den Standardlisten aufgerufen werden.

# Erstelle benutzerdefierte Listen
# für Traffic von intern zur DMZ
ipchains -N int2dmz
# für Traffic von der DMZ nach intern
ipchains -N dmz2int
# Paketverteilung intern -> dmz
ipchains -A input -i eth0 -s 192.168.1.0/24 -d 7.8.9.0/24 -j int2dmz
ipchains -A forward -i eth1 -s 192.168.1.0/24 -d 7.8.9.0/24 -j int2dmz
ipchains -A output -i eth1 -s 192.168.1.0/24 -d 7.8.9.0/24 -j int2dmz
# Paketverteilung dmz -> intern
ipchains -A input -i eth1 -s 7.8.9.0/24 -d 192.168.1.0/24 -j dmz2int
ipchains -A forward -i eth0 -s 7.8.9.0/24 -d 192.168.1.0/24 -j dmz2int
ipchains -A output -i eth0 -s 7.8.9.0/24 -d 192.168.1.0/24 -j dmz2int
# intern -> Webserver in 7.8.9.0/24 via int2dmz/dmz2int HTTP+HTTPS
ipchains -A int2dmz -p tcp --sport 1024: --dport 80 -j ACCEPT
ipchains -A int2dmz -p tcp --sport 1024: --dport 443 -j ACCEPT
# Antwortpakete
ipchains -A dmz2int -p tcp --sport 80 --dport 1024: ! -y -j ACCEPT
ipchains -A dmz2int -p tcp --sport 443 --dport 1024: ! -y -j ACCEPT

Gleiches gilt für Regelsätze von extern in eine DMZ. Auch hier sollten Sie mit speziellen Listen arbeiten. Dienste wie SMTP, POP, IMAP, HTTP oder HTTPS stellen für statische Portfilter kein Problem dar, weil sie nur einen Port benutzen.

FTP-Server in der DMZ

Wenn auch ein FTP-Server in der DMZ steht, sollten Sie unbedingt den Portbereich für den passiven Transfer (nur diesen können Webbrowser benutzen) serverseitig einschränken. Bei ProFTPD hilft die Option "PassivePorts", bei WU-FTPD wird diese "passive ports" genannt. Andernfalls müssten alle Ports zwischen 1024 und 65535 für einen Verbindungsaufbau von extern geöffnet sein. Dann müssten jedoch etwaige Dienste auf höheren Ports dediziert geschützt werden. Dies bedeutet zum einen Aufwand, zum anderen ist es fehleranfällig, wenn ein neuer Dienst hinzukommt. Ein Beispiel für Portfilter von extern auf einen FTP-Server (7.8.9.100) in einer DMZ mit Port-Einschränkung von 49152 bis 65534 würde wie folgt aussehen:

# Erstelle benutzerdefierte Listen
ipchains -N ext2dmz
ipchains -N dmz2ext
# Paketverteilung extern -> DMZ
ipchains -A input -i eth3 -d 7.8.9.0/24 -j ext2dmz
ipchains -A forward -i eth2 -d 7.8.9.0/24 -j ext2dmz
ipchains -A output -i eth2 -d 7.8.9.0/24 -j ext2dmz
# Paketverteilung DMZ -> extern
ipchains -A input -i eth2 -s 7.8.9.0/24 -j dmz2ext
ipchains -A forward -i eth3 -s 7.8.9.0/24 -j dmz2ext
ipchains -A output -i eth3 -s 7.8.9.0/24 -j dmz2ext
## extern -> FTP-Server 7.8.9.100 via ext2dmz/dmz2ext
# Kontrollkanal + Antwort
ipchains -A ext2dmz -p tcp --sport 1024: -d 7.8.9.100 21 -j ACCEPT
ipchains -A dmz2ext -p tcp -s 7.8.9.100 21 --dport 1024: ! -y -j ACCEPT
# Aktiver Transfer (Verbindungsaufbau vom Server zum Client) + Antwort
ipchains -A dmz2ext -p tcp -s 7.8.9.100 20 --dport 1024: -j ACCEPT
ipchains -A ext2dmz -p tcp --sport 1024: -d 7.8.9.100 20 ! -y -j ACCEPT
# Passiver Transfer (Verbindungsaufbau vom Client zum Server) + Antwort
ipchains -A ext2dmz -p tcp --sport 1024: -d 7.8.9.100 49152:65534 -j ACCEPT
ipchains -A dmz2ext -p tcp -s 7.8.9.100 49152:65534 --dport 1024: ! -y -j ACCEPT

Fazit

Mit den in diesem Teil der Artikelreihe vorgestellten Methoden zur Paketfilterung mittels ipchains können Sie bereits Ihr Netzwerk sehr gut vor Eindringlingen schützen. Nicht alles jedoch lässt sich über Proxies regeln, sodass unter Umständen auch der direkte Zugriff von internen Rechnern auf externe Ressourcen nötig ist. Dazu bietet es sich an, die internen IP-Adressen via Masquerading vor dem Internet zu verstecken. Wie Sie das mit Linux realisieren, lesen Sie im nächsten Teil der Artikelreihe. Der vierte und vorerst letzte Teil beschäftigt sich damit, wie Sie Angriffe auf Ihr Netzwerk erkennen und entsprechend reagieren können.

Im Anhang finden Sie ein Basisscript für die Konfiguration der Firewall, das Sie nur noch mit den eigenen Regeln füllen müssen. Folgende fertige Scripte von unserem Autor Dr. Peter Bieringer geben Ihnen weitere Anhaltspunkte: Dieses Beispiel verwendet benutzerdefinierte Listen. Weniger strukturiert aber dafür leichter erkennbar in der Zuordnung von "input", "output" und "forward" ist dieses Beispiel, das ohne benutzerdefinierte Listen auskommt. mha)

Anhang: Basis für Firewall-Setup-Skript

Hier finden Sie eine Basis für ein Firewall-Skript ohne vordefinierte Regeln. Diese fügen Sie ab der Zeile "# Eigene Regeln ab hier" ein. Anstatt per Copy & Paste den Code in einen Texteditor zu überführen, können Sie das Basis-Skript auch hier downloaden. Speichern Sie die Datei in /etc/rc.d/init.d/ unter dem Namen firewalling ab und bearbeiten Sie sie dann.

#!/bin/sh
#
# firewalling TCP/IP firewalling + masquerading.
#
# description: This script sets various firewall rules
#
# chkconfig: 2345 98 02
#
# processname: firewallsetup
#
# (P) & (C) 2001 by Peter Bieringer <pb@bieringer.de>
#
# 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, deshalb zur Verifizierung
# mit nmap von außerhalb testen!


# ChangeLog:
# hier sollte eine Historie aufgebaut werden,
# damit Änderungen nachvollzogen werden können

# 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

# Ausführen von ipchains, zeigt die Regel an, falls fehlerhaft
ipchains() {
rule="$*"
#echo "$rule"
/sbin/ipchains $rule

if [ $? -gt 0 ]; then
echo -e "\\a Fehler in Regel: $rule"
fi
}

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

# 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
# Setze Policies
ipchains -P input DENY
ipchains -P forward REJECT
ipchains -P output REJECT

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

# Eigene Regeln ab hier

# Protokolliere Pakete, die das Ende der Liste erreiche
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

exit $RETVAL