Aus Linux-Magazin 12/2005

Firewall-Builder: Vom grafischen Frontend zur Konfigurationsdatei

Für verschiedene Firewalls eine gemeinsame Oberfläche anbieten, die dem Admin zudem hilfreich unter die Arme greift: Wie FW-Builder dieses Kunststück vollbringt und welche Kniffe die internen Regel-Compiler dabei verwenden, erklärt der Autor der Software selbst.

Firewall-Admins haben es schwer. Jeder Hersteller und jedes Projekt verwendet eigene Tools und Konfigurationssprachen, die es perfekt zu beherrschen gilt, um nicht versehentlich Lücken in den Netzwerkschutz zu reißen. Die Fähigkeiten und Funktionsweisen der Firewalls weichen stark voneinander ab. Welche Eigenschaften der Netzwerkpakete sie analysieren und wie sehr sie den Inhalt manipulieren variiert. All dies muss der Admin berücksichtigen.

Als Ausweg bietet sich der Firewall-Builder [1] an, entwickelt vom Autor des Artikels. Das GPL-Framework (für freie Betriebssysteme) präsentiert sich als grafisches Konfigurationswerkzeug (Abbildung 1), das auf vielen Systemen läuft und Einstellungen für viele Firewall-Varianten erstellt – Multi-Plattform im doppelten Sinne. Der Admin entwickelt seine Policy anhand einer abstrakten, idealisierten Firewall-Architektur. FW-Builder erzeugt daraus die konkreten Regeln in der jeweiligen Konfigurationssprache.

Der Übersetzungsschritt hat praktische Vorteile. Fehlt beispielsweise ein Feature des abstrakten Modells in einer Ziel-Firewall, dann versucht FW-Builder diese Funktion mit einem Workaround nachzubilden. Dank dieser Taktik sind selbst sperrige Firewalls so einfach zu konfigurieren wie ihre leistungsfähigeren Mitbewerber. Zudem entdecken die Compiler einige typische Fehler in der Konfiguration. Derzeit existieren freie Compiler für IPtables ([2], Linux), IPfilter ([3], unter anderem FreeBSD und NetBSD), PF ([4], OpenBSD) und IPfw ([5], FreeBSD) sowie ein kommerzieller Ableger für Cisco PIX [6].

Aufgeräumte Oberfläche

Neben dem GUI besteht FW-Builder aus einem API (und der dazu passenden Bibliothek) sowie einem Satz eigenständiger Policy-Compiler. Letztere übersetzen den Regelsatz (Policy) in die konkrete Konfiguration. Dabei verwendet das Tool einen objektorientierten Ansatz: Es ist selbst in C++ programmiert (seit Version 2.0 mit Qt), aber auch der Admin arbeitet mit Objekten.

Alle Objekte, aus denen er eine Regel aufbaut, findet er am linken Rand in einer baumförmigen Hierarchie (Abbildung 1). Er kann sie in Gruppen zusammenfassen und diese Gruppen wieder als Objekt verwenden. Objekte lassen sich beliebig oft einsetzen. Jede Änderung an ihnen wirkt sich unmittelbar auf alle Gruppen und Regeln aus, die dieses Objekt einbinden.

Gut organisiert

FW-Builder kennt eine Menge Objekttypen: Firewalls, Hosts, Interfaces (als Teil eines Host oder einer Firewall), IP- und MAC-Adressen, Netzwerke, Adressräume, Gruppen der bisher genannten Objekte, Dienste (IP, ICMP, TCP, UDP, Custom) und Gruppen von Diensten sowie Zeitintervalle. Einige Objekte sind vordefiniert, etwa die privaten IP-Adressen aus RFC 1918 sowie über hundert verbreitete Dienste. Der Admin kann auch eigene Objektbibliotheken anlegen und sie im- oder exportieren.

Alle Objekte sammelt das GUI in einem Tree-Widget am linken Rand des Fensters. Interfaces gehören zu einem Host oder einer Firewall, IP-Adressen zu einem Netzwerk – nach diesem Prinzip ordnet die Oberfläche alle Objekte logisch an. Jedes Firewall-Objekte hat mehrere Regelsätze (zu sehen im Hauptteil des Fensters): eine globale Policy, eine eigene Policy für jedes Interface sowie NAT-Regeln. Globale Regeln gelten für jedes Paket, egal auf welchem Weg es die Firewall betritt oder verlässt, während sich Interface-spezifische Regeln auf eine Schnittstelle beschränken.

Ein Doppelklick auf ein Objekt im Baum öffnet den passenden Editor. In die Policy gelangen die Objekte per einfachem Drag&Drop, auch klassisches Copy& Paste funktioniert. Tooltipps zeigen die Details jedes Objekts, wenn der Mauszeiger über ihm verharrt.

Abbildung 1: Die FW-Builder-Oberfläche sortiert links alle Objekte hierarchisch. Zu sehen sind vier Firewalls, zwei aufgeklappt mit je drei Ethernet-Interfaces. Die Konfiguration des Objekts steht links unten. Den Hauptteil des Fensters nimmt die Policy ein; hier hinein zieht der Admin Objekte aus der Baumdarstellung.

Abbildung 1: Die FW-Builder-Oberfläche sortiert links alle Objekte hierarchisch. Zu sehen sind vier Firewalls, zwei aufgeklappt mit je drei Ethernet-Interfaces. Die Konfiguration des Objekts steht links unten. Den Hauptteil des Fensters nimmt die Policy ein; hier hinein zieht der Admin Objekte aus der Baumdarstellung.

Da FW-Builder auf der Workstation des Admin läuft, müssen die Regelsätze erst auf die Firewall gelangen, um wirksam zu werden. Dazu enthält die Oberfläche einen Installer [7], der die Konfiguration per SSH überträgt und aktiviert. Der Admin braucht nur noch sein Passwort oder die Passphrase für seinen SSH-Schlüssel einzutippen.

Funktionen der abstrakten
Firewall

FW-Builder stellt die Firewall-Policy und NAT-Einstellungen als plattformunabhängigen Regelsatz dar. Der Admin bearbeitet die Regeln, indem er per Drag&Drop Netzwerk- und Dienst-Objekte einsetzt. Die Regeln erhalten Quelle, Ziel und Dienst sowie einen Parameter, der die gewünschte Aktion festlegt. Weitere Parameter sind optional, etwa um das Interface festzulegen sowie die Richtung, in der Pakete die Schnittstelle überqueren.

Nur die erste auf ein Paket passende Regel bestimmt, was mit ihm passiert (Accept, Drop, Reject). Nachfolgende Regeln bleiben wirkungslos. Bei IPtables und Cisco PIX entspricht dies dem Standardverhalten, für IPfilter und PF setzt FW-Builder die »quick«-Option.

Einheitliche Default-Policy

Eine leere Policy blockiert jedes Paket. Für IPtables setzt der Compiler mit der Option »-P« das Standardverhalten auf »DROP«; auf anderen Plattformen fügt er Regeln ans Ende des Regelsatzes, die Gleiches bewirken.

Die Firewall übersetzt erst Adressen (NAT), bevor sie die Regeln der Policy anwendet. Alle unterstützten Open-Source-Firewalls verhalten sich per Default so, nur für Cisco PIX ist dazu eine Emulation nötig.

Negationen sind in Policy- und NAT-Regeln möglich. Der Admin kann mehrere Objekte in ein Regelelement aufnehmen (etwa als Quelle) und die Liste invertieren, also nur auf Adressen filtern, die nicht in der Liste stehen. Der Compiler hat dann einiges zu tun: Selbst wenn eine Plattform Negationen unterstützt, beherrscht sie das nur für einzelne Adressen. Bei IPtables behilft sich der Compiler mit eigens definierten Chains, während er bei IPfilter das »skip«-Schlüsselwort einsetzt.

Varianten der Network Address Translation

FW-Builder implementiert mehrere Arten von NAT-Regeln. Die Regeln manipulieren folgende Bestandteile eins Pakets:

  • Quelladresse und optional den Quellport
  • Zieladresse und optional den Zielport
  • Quell- und Zieladresse sowie optional die Ports
  • Nur die Portnummern
  • Nichts (»no nat«-Regel)

Die abstrakte Firewall in FW-Builder kombiniert praktische Funktionen aus vorhandenen Implementierungen und ergänzt neue Regeln und Transformationen (siehe Kasten “Funktionen der abstrakten Firewall”). Das Projekt verfolgt ähnliche Ziele wie jede höhere Programmiersprache: Um die schwierigen Teile kümmert sich der Compiler, der Admin soll sich auf die Policy konzentrieren und nicht mit den Details der Konfigurationssprache aufhalten. Beispielsweise verlangen viele Sprachen, dass jede Regel das Interface und die Übertragungsrichtung nennt. Firewall-Builder übernimmt diese fehlerträchtige Fleißarbeit – alle benötigten Informationen stehen schon in den Firewall-Objekten.

Abbildung 2: Firewall-Builder ist keine monolithische Software, die Programmsuite teilt sich in einzelne Module. Im Zentrum steht das gemeinsame API, es verbindet auch die Oberfläche mit den Policy-Compilern.

Abbildung 2: Firewall-Builder ist keine monolithische Software, die Programmsuite teilt sich in einzelne Module. Im Zentrum steht das gemeinsame API, es verbindet auch die Oberfläche mit den Policy-Compilern.

Abbildung 3: Policy-Compiler setzen sich aus mehreren Regel-Prozessoren zusammen, die jeweils eine Teilaufgabe beim Übergang der abstrakten FW-Builder-Firewall zur konkreten Konfigurationssprache übernehmen.

Abbildung 3: Policy-Compiler setzen sich aus mehreren Regel-Prozessoren zusammen, die jeweils eine Teilaufgabe beim Übergang der abstrakten FW-Builder-Firewall zur konkreten Konfigurationssprache übernehmen.

Tabelle 1:
Firewall-Builder-API

 

Modul

Aufgabe

fwbuilder

Grundlegende Klassen für den Zugriff auf Netzwerkobjekte
in der Datenbank sowie etliche Utility-Klassen.

fwcompiler

Gemeinsame Klassen für die Policy-Compiler.

XML

Laden, Speichern und Verarbeiten von XML-Dateien. Bietet auch
automatische Format-Upgrades per XSLT-Transformation.

DNS

Diese Sammlung von Multithreading-fähigen Klassen
löst Hostnamen zu IP-Adressen auf (einzeln oder gesammelt
für mehrere Namen) oder überträgt und analysiert
ganze DNS-Zonen.

SNMP

Einfacher C++-Wrapper für SNMP-Aktionen. Einige
Spezialklassen sammeln Informationen über Interfaces oder ARP-
und Routing-Tabellen.

Network Crawler

Ausgeklügeltes Netzwerk-Discovery. Ausgehend von einem
bekannten Host ermittelt das Modul weitere Rechner und Netzwerke,
die es als Objekte in die Datenbank legt. Wie ausgedehnt es suchen
soll, lässt sich einstellen.

Interface-Wahl

Beim Festlegen der Policy hantiert der Admin normalerweise nur noch mit Quelle, Ziel und Dienst. Wenn nötig, kann er das Interface und die Übertragungsrichtung aber auch explizit angeben, zum Beispiel für Antispoofing-Regeln: Hereinkommende Pakete, deren Quelladresse aus dem internen Netz stammt, oder ausgehende Pakete mit einer Quelladresse, die nicht zum internen Netz gehört, erkennt eine Regel nur, wenn sie Richtung und Interface in die Entscheidung einbezieht.

Automatische Regeln

Firewall-Builder unterstützt den Admin bei vielen weiteren Aufgaben, die Compiler fügen sogar vordefinierte Standardregeln in die Policy ein. Für Stateful-Firewalls ergänzen sie zum Beispiel eine Regel, die – wenn für eine Verbindung ein Zustand gespeichert ist – alle zugehörigen Pakete gleich behandelt. Auch sorgt der Compiler dafür, dass die Firewall diese Zustandsdaten anlegt.

Weitere Standardregeln halten dem Admin einen SSH-Zugang zur Firewall offen: Es genügt, im FW-Builder-GUI die IP-Adresse oder das Subnetz der Management-Workstation festzulegen. Die Compiler erzeugen dann automatisch Regeln, die den SSH-Zugriff auf die Firewall gestatten. Das dient als Sicherheitsnetz, es verhindert, dass sich der Admin versehentlich selbst aussperrt. Wer diese Automatismen nicht mag, schaltet sie in einem Einstellungsdialog ab.

Leider gelingt es nicht immer, fehlende Features einer Firewall mit einfachen Workarounds nachzubilden. Beispielsweise können IPtables-Regeln Datum und Uhrzeit für ihre Gültigkeit enthalten; andere Open-Source-Firewalls haben keinerlei Entsprechung dafür. Um auch diese Funktion nachzubilden, wäre es nötig, einen Daemon oder einen Cronjob auf der Zielplattform zu installieren. Noch gibt es dafür keine Lösung, die Entwickler arbeiten aber daran.

Abbildung 4: Aus dieser Regel, die je zwei Objekte als Quelle und als Dienst verwendet, erzeugt ein Prozessor vier atomare Regeln (Tabelle 2).

Abbildung 4: Aus dieser Regel, die je zwei Objekte als Quelle und als Dienst verwendet, erzeugt ein Prozessor vier atomare Regeln (Tabelle 2).

Tabelle 2: Atomare
Regeln

 

Quelle

Ziel

Dienst

Aktion

netA

hostC

http

Accept

netB

hostC

ftp

Accept

netA

hostC

http

Accept

netB

hostC

ftp

Accept

Im Zentrum der Architektur von FW-Builder (Abbildung 2) steckt das API samt Bibliothek. Der Anwender nutzt diese Module über das GUI oder anhand einiger Kommandozeilenwerkzeuge, die einfache Aufgaben übernehmen. Über das API steuert die Oberfläche auch den Zugriff auf die (selbst modular aufgebauten) Policy-Compiler. Die Compiler arbeiten aber auch als eigenständige Programme.

Einheitliches API

Die Netzwerkobjekte, die der Admin per GUI anlegt, landen intern in einer Network Object Database. Der Zugriff auf deren Elemente gehört zu den Aufgaben des C++-API (Tabelle 1 beschreibt dessen Module). Als Speicherformat dient eine eigene XML-Sprache. Deren DTD (Document Type Definition) verwenden auch andere Entwickler in ihren eigenen Projekten.

Die starke Modularisierung setzt sich in den Policy-Compilern fort (Abbildung 3). Sie bestehen aus kleinen, spezialisierten Klassen, die im FW-Builder-Jargon Regel-Prozessor heißen; meist sind es 50 bis 70 pro Compiler. Jeder Prozessor kümmert sich ausschließlich um eine grundlegende Transformation. Dadurch sind diese Klassen leicht zu debuggen und gut wiederverwendbar. Beispielsweise führt ein Prozessor die Negation der Quelladresse aus, während ein anderer die Zieladresse negiert. Ein weiterer kümmert sich um Logging-Regeln.

Listing 1: Kommentare in
PF

01 #
02 # Rule  0(NAT)
03 nat on fxp1 proto {tcp udp icmp} from 192.168.1.0/24 to any -> 222.222.222.222
04 #
05 # Rule  2(NAT)
06 # Translation for the mail server
07 rdr proto tcp from any to 222.222.222.222 port 25 -> 192.168.1.10 port 25
08 #
09 # Rule  3(NAT)
10 # Redirect to Squid proxy
11 rdr proto tcp from any to any port 80 -> 127.0.0.1 port 3128
12 #
13 # Rule  0(fxp1)
14 # Automatically generated anti-spoofing rule
15 block in log quick on fxp1 inet from {222.222.222.222,192.168.1.1} to any
16 block in log quick on fxp1 inet from 192.168.1.0/24 to any

Viele Prozessor-Klassen erledigen Aufgaben, die jede Zielplattform braucht, daher finden sich diese Klassen im gemeinsamen Firewall-Builder-API. Jeder Prozessor erbt von einer gemeinsamen Basisklasse. Das Compiler-Framework sortiert die ursprünglichen Regeln in eine Queue und übergibt diese an den ersten Prozessor. Der verarbeitet sie nacheinander, schreibt seine Resultate in eine weitere Warteschlange und ruft den nächsten Prozessor auf. Ein Prozessor kann Regeln auch in mehrere aufteilen oder sie verwerfen.

Fehlern auf der Spur

Einige Prozessoren untersuchen die Policy auf typische Fehler in der Konfiguration und im gesamten Policy-Design. Sie weisen den Admin auf mögliche Schwächen hin, bevor er die Regeln in seiner Firewall tatsächlich anwendet. Bei fatalen Fehlern bricht der Compiler sicherheitshalber seine Arbeit ab. In manchen Fällen bietet er einen Workaround an, der den Fehler ausgleicht, oder der Compiler ignoriert den Schnitzer. In jedem Fall produziert er eine deutliche Fehlermeldung.

Listing 2a: Optimierung in
IPtables

01 iptables -N Cid42C44AEF.0
02 iptables -A FORWARD -p icmp  -m icmp  --icmp-type any  -m state --state NEW  -j Cid42C44AEF.0
03 iptables -A FORWARD -p tcp -m tcp  --dport 80  -m state --state NEW  -j Cid42C44AEF.0
04 iptables -N Cid42C44AEF.1
05 iptables -A Cid42C44AEF.0  -s hostA  -j Cid42C44AEF.1
06 iptables -A Cid42C44AEF.0  -s hostB  -j Cid42C44AEF.1
07 iptables -A Cid42C44AEF.1  -d netA  -j ACCEPT
08 iptables -A Cid42C44AEF.1  -d netB  -j ACCEPT

Im Zweifelsfall wählt der Compiler eine konservative Linie und wertet Fehler lieber als fatal, bevor er eine missverständliche Eingabe falsch interpretiert. Er soll so wenig wie möglich an der Policy ändern. Nicht unbedingt fatal, aber eine Warnung wert ist es beispielsweise, ungewöhnlich große Adressbereiche in einer Regel zu verwenden.

Listing 2b: Optimierung in
IPfilter

01 skip 2 in   from hostA  to any
02 skip 1 in   from hostB  to any
03 skip 7 in   from any  to any
04 pass  in  quick proto icmp  from any  to netA  keep state
05 pass  in  quick proto icmp  from any  to netB  keep state
06 skip 2 in   from hostA  to any
07 skip 1 in   from hostB  to any
08 skip 2 in   from any  to any
09 pass  in  quick proto tcp  from any  to netA  port = 80 keep state
10 pass  in  quick proto tcp  from any  to netB  port = 80 keep state

Wenn die Zielplattform solche Bereiche nicht selbst unterstützt, muss sie der Compiler mit vielen CIDR-Adressblöcken (Classless Inter-Domain Routing) nachbilden. Er versucht zwar, die Anzahl der Blöcke zu minimieren, dennoch übersteigt das Ergebnis eventuell die Fähigkeiten der Firewall. In dieser Situation warnt FW-Builder den Admin und schlägt ihm vor, die Regel mit einzelnen Netzwerkobjekten statt des großen Adressbereichs neu aufzusetzen. Die Situation ist nicht fatal, da der Compiler korrekten Code erzeugt, der nichts an der Bedeutung der Policy ändert.

Ein ungefährlicher Fehler wäre auch ein Log-Präfix, das länger ausfällt, als die Ziel-Firewall erlaubt. Der Compiler schneidet das Präfix zurecht. Das ändert nichts an der Bedeutung der Regel, verdient aber einen Hinweis an den Admin. Weitere Patzer, die ein Policy-Compiler automatisch bemerkt und meldet:

  • Fehlkonfiguration in Netzwerkobjekten, beispielsweise Gruppen,
    die sich selbst rekursiv einbinden, oder ungültige
    Kombinationen aus IP-Adresse und Netzmaske.
  • Fehlende Objekte, etwa ein Firewall-Interface ohne
    IP-Adresse.
  • NAT-Regeln mit lückenhaften Adressbereichen, falschen
    Interfaces oder nicht unterstützten Umwandlungen.
  • Regelverdeckung: Manche Regel kann nie zutreffen, weil zuvor
    bereits andere Regeln auf jedes Paket passen, für das sie
    gedacht ist.
Abbildung 5: Enthalten komplexe Regeln mehrere Objekte in mehreren Spalten, wird die Liste atomarer Regeln recht lang (Tabelle 3).

Abbildung 5: Enthalten komplexe Regeln mehrere Objekte in mehreren Spalten, wird die Liste atomarer Regeln recht lang (Tabelle 3).

Als zusätzliche Maßnahme gegen Fehler fügt jeder Compiler Kommentare in den erzeugten Code ein. Sie gestalten die Konfigurationsdatei (oder das Firewall-Skript) lesbar und vermerken, aus welcher Policy-Regel der jeweilige Abschnitt stammt. Auch die Kommentare, die der Admin im GUI einträgt, findet er im generierten Code wieder. Listing 1 zeigt, wie das bei einer Konfigurationsdatei für die OpenBSD-Firewall PF aussieht.

Tabelle 3:
Optimierung

 

Chain

Quelle

Ziel

Dienst

Aktion

Ohne Optimierung

 

 

 

 

 

hostA

netA

http

Accept

 

hostA

netA

icmp

Accept

 

hostA

netB

http

Accept

 

hostA

netB

icmp

Accept

 

hostB

netA

http

Accept

 

hostB

netA

icmp

Accept

 

hostB

netB

http

Accept

 

hostB

netB

icmp

Accept

Optimiert

 

 

 

 

 

hostA

any

any

C1

 

hostB

any

any

C1

C1

any

netA

any

C2

C1

any

netB

any

C2

C2

any

any

http

Accept

C2

any

any

icmp

Accept

Beispiele

Die Arbeit der Compiler und Prozessoren lässt sich am besten an konkreten Beispielen nachvollziehen. Das erste zeigt, wie ein Prozessor eine komplexe Regel in einen ganzen Satz atomarer Regeln übersetzt. Die Ausgangslage zeigt Abbildung 4: Die Regel fasst zwei Quellen und zwei Dienste zusammen.

Beherrscht die Ziel-Firewall keine Gruppierungen, zerlegt ein Prozessor das komplexe Gebilde in atomare Regeln (Tabelle 2). Diese Transformation ist unabhängig von der Zielplattform, sie arbeitet noch auf einer abstrakten Ebene. Da beispielsweise OpenBSD PF das Gruppieren selbst beherrscht, überspringt der zugehörige Compiler den Prozessor für atomare Regeln. Der resultierende Code bleibt schlank und übersichtlich.

Optimierung

Mit der wachsenden Anzahl von Objekten in einer komplexen Regel wird die Liste atomarer Regeln länger. Der Prozessor muss jede mögliche Kombination von Quelle, Ziel und Dienst als Regel einfügen. In Abbildung 5 enthält jede dieser drei Spalten zwei Objekte, es entstehen 23=8 Kombinationen (Tabelle 3, erster Abschnitt). Bei drei Objekten in jeder Spalte wären es schon 27 Kommandos. Was FW-Builder dagegen unternimmt, ist im zweiten Abschnitt der Tabelle 3 zu sehen.

Die optimierte Variante betrachtet jedes Element der Regel einzeln und kann daher den Vergleich mit dem Paket abbrechen, wenn es zu keinem Objekt in der Regel passt. Das Beispiel vergleicht erst die Quelladresse mit »hostA« und »hostB«. Nur wenn einer davon passt, folgt der Vergleich in der eigens definierten Chain »C1«, sie prüft die Zieladresse. Passt auch diese, folgt Chain »C2« mit dem Vergleich der Dienste.

Kürzer und schneller

Der verbesserten Version gelingt es bereits nach zwei Vergleichen, die meisten Pakete auszusortieren, die nicht passen. Die einfachere Variante braucht immer acht Vergleiche, um zum gleichen Ergebnis zu gelangen. Außerdem ist die optimierte Variante kürzer: Sie begnügt sich mit sechs Kommandos, bei drei Objekten pro Spalte wären es neun Befehle. Die Komplexität reduziert sich auf O(N). Der Optimierer wendet diesen Algorithmus aber nur an, wenn das Resultat tatsächlich kürzer ausfällt als bei der einfacheren Technik.

Welchen Code FW-Builder für IPtables produziert, ist in Listing 2a zu sehen. Statt der tatsächlich eingetragenen IP-Adressen der Rechner und Netze sind hier zur besseren Übersicht noch symbolische Namen enthalten. Ein ähnlicher Algorithmus kommt auch bei IPfilter zum Einsatz (siehe Listing 2b). Er verwendet das »skip«-Kommando statt eigener Chains, der Algorithmus analysiert aber ebenfalls die drei Felder Quelle, Ziel und Dienst nacheinander. Er überspringt weitere Regeln, sobald das Paket auf eines der Felder nicht passt. Da der Code länger ausfällt als bei IPtables, setzt FW-Builder die Optimierung bei IPfilter erst später ein.

Abbildung 6: Um die Negation in dieser Regel kümmert sich ein eigener Prozessor (Tabelle 4).

Abbildung 6: Um die Negation in dieser Regel kümmert sich ein eigener Prozessor (Tabelle 4).

Arbeit fällt auch bei den Negationen an. Abbildung 6 negiert die beiden Quell-Netze: Die Regel soll für jedes Netz gelten, nur nicht für »netA« und »netB«. Viele Firewalls verstehen solche Negierungen, die obere Hälfte von Tabelle 4 zeigt die nahe liegende Auflösung (das Ausrufezeichen »!« symbolisiert die Negierung).

Tabelle 4:
Negation

 

Falsch

 

 

 

! netA

hostC

http

Accept

! netB

hostC

http

Accept

Korrekt

 

 

 

netA, netB

any

any

Continue

any

hostC

http

Accept

Falsche Negation

Doch diese einfache Übersetzung ist leider falsch: Die ursprüngliche Regel erlaubt HTTP-Pakete für »hostC«, die weder von »netA« noch von »netB« kommen. Was mit Paketen von »netA« und »netB« geschehen soll, ist nicht definiert, dafür wären weitere Regeln zuständig. Leider gestattet die erste Regel aus der falschen Übersetzung, dass HTTP-Pakete von »netB« zu »hostC« gehen.

Die zweite Hälfte von Tabelle 4 zeigt, wie es der Prozessor richtig macht. Er nimmt erst die beiden Netze A und B aus der Regel aus: Die interne Aktion »Continue« besagt, dass die Verarbeitung für zutreffende Pakete weitergeht, sobald die Regeln aus diesem Prozessor abgearbeitet sind. Die folgende Regel akzeptiert Pakete aus dem Rest der Welt, wenn sie sich per HTTP an Host C richten.

Fortsetzung folgt

Ein weiterer Prozessor im Compiler kümmert sich um die Continue-Aktion. Je nach Firewall-Implementierung kommen unterschiedliche Mechanismen in Frage. Bei IPtables verwendet FW-Builder eine eigens definierte Chain (Listing 3a), während er für IPfilter das »skip«-Kommando einsetzt (Listing 3b). Schwierig wird es bei Firewalls, die keinen geeigneten Mechanismus mitbringen; dann durchsucht der Compiler alle nachfolgenden Regeln nach einer Aktion, die an dieser Stelle passt.

Listing 3a: Negation in
IPtables

01 iptables -N TMPC
02 iptables -A FORWARD -p tcp -d hostC --dport 80 -j TMPC
03 iptables -A TMPC    -s netA  -j RETURN
04 iptables -A TMPC    -s netB  -j RETURN
05 iptables -A TMPC    -m state --state NEW  -j ACCEPT

Listing 3b: Negation in
IPfilter

01 skip 2 in  proto tcp   from netA to any
02 skip 1 in  proto tcp   from netB to any
03 pass   in  quick proto tcp  from any to hostC port = 80

Listing 4a: Dynamische IP in
PF

01 # Tables:
02 table <id42BF3BFE.1> { le0 , 192.168.1.1 }
03 #
04 # Rule  0 (le0)
05 # anti spoofing rule
06 #
07 block in   log  quick on le0 inet  from <id42BF3BFE.1>  to any
08 block in   log  quick on le0 inet  from 192.168.1.0/24  to any

Listing 4b: Dynamische IP in
IPtables

01 getaddr ppp0  i_ppp0
02 
03 # Rule 0 (ppp0)
04 #
05 echo "Rule 0 (ppp0)"
06 #
07 # anti spoofing rule
08 #
09 $IPTABLES -N ppp0_In_RULE_0
10 test -n "$i_ppp0" && $IPTABLES -A INPUT  -i ppp0  -s $i_ppp0  -j ppp0_In_RULE_0
11 $IPTABLES -A INPUT  -i ppp0  -s 192.168.1.1  -j ppp0_In_RULE_0
12 $IPTABLES -A INPUT  -i ppp0  -s 192.168.1.0/24  -j ppp0_In_RULE_0
13 test -n "$i_ppp0" && $IPTABLES -A FORWARD  -i ppp0  -s $i_ppp0  -j ppp0_In_RULE_0
14 $IPTABLES -A FORWARD  -i ppp0  -s 192.168.1.1  -j ppp0_In_RULE_0
15 $IPTABLES -A FORWARD  -i ppp0  -s 192.168.1.0/24  -j ppp0_In_RULE_0
16 $IPTABLES -A ppp0_In_RULE_0   -j LOG  --log-level info --log-prefix "RULE 0 -- DENY "
17 $IPTABLES -A ppp0_In_RULE_0   -j DROP
Abbildung 7: Diese Firewall verwendet dynamische IP-Adressen an der externen Schnittstelle. Dennoch soll sie gespoofte Pakete erkennen. In FW-Builder genügt es, das Interface-Objekt als Quell-IP-Adresse einzusetzen.

Abbildung 7: Diese Firewall verwendet dynamische IP-Adressen an der externen Schnittstelle. Dennoch soll sie gespoofte Pakete erkennen. In FW-Builder genügt es, das Interface-Objekt als Quell-IP-Adresse einzusetzen.

Abbildung 8: Neben Ethernet und Loopback stecken etliche PPP-Schnittstellen in dieser Firewall.

Abbildung 8: Neben Ethernet und Loopback stecken etliche PPP-Schnittstellen in dieser Firewall.

Dynamische Adressen

Oft ist es auch schwierig, Firewalls mit dynamischen IP-Adressen korrekt zu konfigurieren. Das ist der Fall, wenn der ISP die externe IP-Adresse per PPP oder DHCP vorgibt – häufig anzutreffen bei DSL-Verbindungen. Eine Antispoofing-Regel soll dennoch eintreffende Pakete blockieren, wenn deren Quelladresse aus dem internen Netz stammt oder identisch mit einer Adresse der Firewall ist. Letzteres ist der schwierige Teil: Die externe IP-Adresse der Firewall ist a priori unbekannt. Abbildung 7 zeigt die zugehörige Konfiguration im GUI; die Regel gilt für das externe Interface.

Einige Firewalls bieten für diese Situation spezielle Funktionen, etwa PF: Hier kann der Admin den Namen des Interface verwenden, PF ersetzt ihn durch die IP-Adresse der Karte. Setzt der Admin den Namen in Klammern »(le0)«, hält der Kernel die Regel sogar auf dem Laufenden, wenn sich die dynamische Adresse ändert. FW-Builder verwendet zur besseren Übersicht eine eigene Gruppe (Listing 4a, Zeile 2), die alle IP-Adressen der Firewalls sammelt, inklusive der des Ethernet-Interface »le0«. PF gestattet hier keine Klammersyntax.

Auf anderen Firewalls emuliert der Compiler diese Funktion. Für IPtables produziert er Shellcode, der die IP-Adresse ermittelt, einer Variablen zuweist und diese in »iptables«-Aufrufen verwendet. Listing 4b zeigt einen Ausschnitt: Die Adresse des Interface »ppp0« legt die Funktion »getaddr« in der Variablen »i_ppp0« ab. Die Funktion ist weiter oben im vollständigen Skript definiert. Es prüft zudem, ob »i_ppp0« nicht leer ist. So fängt es den Sonderfall ab, dass das »ppp0«-Interface gerade nicht online ist. Statt die Arbeit abzubrechen installiert das Skript dann alle Regeln für die weiteren Interfaces.

Gelegentlich besitzen Firewalls sehr viele Interfaces mit generischen Namen wie »pppNN«, die ihre Nummer NN dynamisch erhalten. Diese Situation findet sich zum Beispiel in Zugangsservern (Access-Routern), an denen die PPP-Verbindungen vieler User enden. Für jeden User, der gerade online ist, braucht die Firewall ein eigenes PPP-Interface – welche das sind, weiß vorab niemand.

Listing 5: Joker-Zeichen,
IPtables

01 #
02 # Rule 0 (ppp*)
03 #
04 echo "Rule 0 (ppp*)"
05 #
06 # anti spoofing rule
07 #
08 $IPTABLES -N ppp_In_RULE_0
09 getinterfaces ppp | while read I; do
10   ivar=`getInterfaceVarName $I`
11   getaddr $I $ivar
12   cmd="$"$ivar
13   eval "addr=$cmd"
14   test -n "$addr" && $IPTABLES -A INPUT  -i ppp+  -s $addr  -j ppp_In_RULE_0
15 done
16 $IPTABLES -A INPUT  -i ppp+  -s 192.168.1.1  -j ppp_In_RULE_0
17 $IPTABLES -A INPUT  -i ppp+  -s 192.168.1.0/24  -j ppp_In_RULE_0
18 $IPTABLES -A ppp_In_RULE_0   -j LOG  --log-level info --log-prefix "RULE 0 -- DENY "
19 $IPTABLES -A ppp_In_RULE_0   -j DROP

Da es unpraktisch wäre, jedes Interface einzeln zu definieren und dazu die Regeln zu kopieren, erlaubt FW-Builder Joker-Zeichen (Wildcards) in Interface-Namen. Endet ein Name mit »*«, erzeugt der Policy-Compiler Shellcode, der alle darauf passenden Interfaces sucht und die Regeln darauf anwendet. Listing 5 zeigt das Skript: Mit der selbst definierten Funktion »getinterfaces« ermittelt es eine Liste aller vorhandenen PPP-Schnittstellen, fragt deren IP-Adresse ab und erzeugt IPtables-Regeln dafür. Das vollständige Skript enthält zudem Regeln für die »FORWARD«-Chain.

Drum prüfe

Für gestandene Firewall-Administratoren gehört es zum guten Ton, Firewalls manuell zu konfigurieren oder GUI-erzeugte Regelsätze akribisch zu prüfen. Letzteres verbindet die Vorteile einer bequemen und übersichtlichen Konfiguration mit der Gewissheit, jeden Parameter zu kennen. Die kommentierten und optimierten Regelsätze, die der Firewall-Builder erzeugt, wollen diesen Prüfschritt möglichst einfach halten. (fjl)

Infos

[1] FW-Builder: [http://www.fwbuilder.org]

[2] Netfilter: [http://www.netfilter.org]

[3] IPfilter: [http://coombs.anu.edu.au/~avalon/ip-filter.html]

[4] PF: [http://www.benzedrine.cx/pf.html]

[5] IPfw: [http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/firewalls.html]

[6] Cisco PIX: [http://www.cisco.com/go/pix]

[7] Vadim Kurland, “How to use built-in policy installer in Firewall Builder 2.0”: [http://www.fwbuilder.org/archives/cat_howtos.html#000156]

Der Autor

Vadim Kurland arbeitet als Netzwerkingenieur für eine kalifornische Internetfirma. Seine Forschungsinteressen gelten den Bereichen Netzwerk-Sicherheit, -Monitoring und -Management.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben