Paketfilterregeln

Das Programm iptables ist die Benutzerschnittstelle zum Paketfilter im Kern. Je Aufruf des Programms wird eine Regel für IP-Pakete angegeben, andere Protokolle (z.B IPX oder NetBEUI) können nicht behandelt werden. Eine Regel gibt die Eigenschaften eines Paketes an und definiert eine Aktion, wenn das Paket allen angegebenen Eigenschaften entspricht. Die Eigenschaften sind u.a. Auf die Angabe der Eigenschaften folgt eine Aktion : Zusätzlich kann ein Paket, das alle angegebenen Eigenschaften erfüllt, an das Kernel-Logging übergeben und/oder an das Netlink-Gerät (s.u.) weitergereicht werden.

Durch eine Verknüpfung von Eigenschaften und Aktion lassen sich einzelne Regeln angeben, z.B. akzeptiere ein eingehendes Paket an Schnittstelle eth0 von beliebigem Rechner und beliebigem Port zum Rechner 123.234.1.2 Zielport 80; als Befehl iptables -A INPUT -p tcp -i eth0 -d 123.234.1.2 --dport 80 -j ACCEPT

Für eine normal geroutete TCP-Verbindung über den Firewall sind zwei FORWARD Regeln notwendig, jeweils eine für den Hin- und eine für den Rückweg. Wenn wir z.B. Web-Zugriffe aus dem lokalen Netz ins Internet zulassen wollen, so lauten diese Regeln mit dem lokalen Netz 212.212.212.0/24 an eth0 und dem Internet an eth1 :

 LAN=212.212.212.0/24
 
iptables -A FORWARD -i eth0 -o eth1 -p tcp -s $LAN -d 0.0.0.0/0 --dport 80 -j ACCEPT        (http-Anfrage ins Internet)
 
iptables -A FORWARD -i eth1 -o eth0 -p tcp -s 0.0.0.0/0 --sport 80 -d $LAN -j ACCEPT        (Antwort des Webservers)

Eine typische Paketfilterschicht eines Firewall besteht aus hunderten von Regeln. Die erste passende Regel mit einer echten Aktion wird ausgeführt. Eine einzige Regel, die falsch angegeben ist, kann zu einem fatalen Sicherheitsloch führen. Es ist deshalb immer anzuraten, die Regeln so eng wie möglich anzugeben und erst bei Bedarf zu erweitern. Als letzte Regel für die drei Ketten (ip
tables) INPUT, FORWARD und OUTPUT wird deshalb immer eine "Log-Regel" angegeben. Die gilt für alle Pakete, die bis zum Ende der Ketten gelangt sind und bislang noch nicht paßten. Sie werden abgelehnt und gleichzeitig im syslog ausgegeben, so daß dann eine passende Regel angegeben werden kann.

Nehmen wir nun den Fall, daß wir nur eine einzige echte (feste) Internet-Adresse benutzen. Dann wird das interne Netzwerk "maskiert", d.h. auf dem Firewall werden die Netzwerkverbindungen umgesetzt. Ein Beobachter im Internet sieht einen einzigen Rechner, der viele Verbindungen zu verschiedenen Zielen hat, ein Beobachter im lokalen Netzwerk sieht direkte Verbindungen zu den Zielrechnern. Die Verallgemeinerung der Maskierung (masquerading), bei der eine n:1-Beziehung realisiert wird, heißt NAT (Network Address Translation). Bei NAT wird eine m:n-Zuordnung gemacht. Im Firewall wird eine Tabelle geführt mit der Zuordnung von vermeintlichen Verbindungen zwischen Client und Server, Verbindungen zwischen Client und Firewall sowie maskierten Verbindungen zwischen Firewall und Server. Für den Client ist bei Masquerading der Firewall transparent, der Server hingegen sieht eine Verbindung zum Firewall. Die zu maskierenden Pakete werden so im Firewall verändert, so daß den beiden anderen beteiligten Rechner präsentiert wird, was sie sehen sollen.

Deshalb werden unsere Regeln auch wie folgt ergänzt :

 LAN=10.1.2.0/24    # privater Adressraum nach RFC1918
 
FWADDR=212.212.212.212
 
iptables -t nat -I POSTROUTING -o eth 1 -s $LAN -d 0.0.0.0/0 -j MASQUERADE
 

Bei dynamischer IP-Adressenzuweisung, die man bei Einwählverbindungen normalerweise hat, kann man diese Regeln nicht statisch angeben. Im Skript ip-up müssen diese Regeln (mit -I statt -A) und der  zugewiesenen IP-Adresse eingefügt und im Skript ip-down (mit -D statt -A) wieder entfernt werden.

In vielen Veröffentlichungen wird über die Probleme berichtet, die bei FTP und Paketfilterung entstehen. Aus diesem Grund wurde das passive FTP erfunden, das standardmäßig von Browsern, aber nicht von Online-Sitzungen, benutzt wird. Generell haben Paketfilter dann potentielle Sicherheitsprobleme, wenn eine Sitzung mehrere Verbindungen benötigt, oft auch im UDP-Bereich. Bekannte Kandidaten sind z.B. FTP, IRC, pcAnywhere. Um statisch diese Verbindungen zuzulassen, müssen die Regeln weiter gefaßt werden als eigentlich beabsichtigt. Nur ein sogenannter Proxy-Prozeß kann Regeln dynamisch ein- und ausfügen, indem er das zugrunde liegende Protokoll (z.B. FTP) interpretiert und die nötigen Aktionen vornimmt.

 


Proxy
Wie man am Beispiel FTP sieht, reicht ein Paketfilter alleine für eine akzeptable Sicherheit im LAN nicht aus. Proxy heißt nichts anderes als Stellvertreter, ein Proxy im Firewall vertritt den eigentlichen Dienst, den er verbirgt, ein FTP-Proxy also den FTP-Server, ein HTTP-Proxy den Web-Server, usw. .

Ein Proxy-Prozeß kann viele Aufgaben haben :

Proxies können geschachtel sein, etwa bei einem HTTP-Zugriff. Der Proxy, der dem Client zugewandt ist, prüft z.B. Berechtigungen und gibt die Anfrage an einen speziellen HTTP-Proxy, z.B. Squid oder Apache, weiter.

Wenn ein Proxy benutzt wird, entfallen die FORWARD-Regeln. Ein Masquerading ist unnötig, da die Pakete aus den Netzen jeweils am Proxy enden und somit für en Client die Zieladresse und den Server die Quelladresse sind. Das Problem dieser Art von Proxies ist damit aber auch, daß der Benutzer den Proxy wahrnimmt und zusätzliche Aktionen, z.B. Einstellungen im Browser, vornehmen muß.

Transparentes Proxy
Ein echtes Highlight im Kern - wenn auch nicht neu - ist die Möglichkeit für transparente Proxies. Dazu kann mit der iptables-Option "-j REDIRECT" ein ankommendes Paket auf den Firewall umgeleitet werden. Der Linux-Kern stellt dann Mechanismen bereit, die das ursprüngliche Ziel wieder erkennen lassen. Transparente Proxies maskieren die Quell-Adresse automatisch, alle Verbindungen scheinen von einem Rechner zu kommen.
TCP
Bei TCP-Verbindungen setzt man einen Proxy auf, der diese Verbindung annimmt. Mit dem Prozessaufruf getsockname(), der bei einer redirektionierten Verbindung nicht die eigene Adresse zurückliefert, läßt sich feststellen, welcher Rechner ursprünglich erreicht werden sollte. Zu diesem Rechner baut man den zweiten Socket auf. Der Rest ist dann simples Hin- und Herkopieren. Client und Server nehmen den Firewall nicht wahr, q.e.d. .

Es lassen sich auch geschachtelte Proxies realisieren. Interessant wird das z.B. für Proxy-Web-Caches wie Squid oder Apache. Bei diesem seltenen aber interessanten Spezialfall konfiguriert man den HTTP-Proxy-Server so, daß er auf die Adresse 127.0.0.1 statt 0.0.0.0 gebunden wird. Die bedienenden äußeren Proxies wiederum werden auf die Adressen der Netzwerkschnittstellen gebunden, je Netzwerkschnittstelle ein Prozeß. Ein Verbindungswunsch läuft zur Netzwerkschnittstelle, wird dort redirektioniert auf die Adresse dieser Netzwerkschnittstelle, damit vom äußeren Proxy-Prozeß empfangen und akzeptiert. Eine zweite Verbindung wird zum HTTP-Proxy-Prozeß (Squid oder Apache) aufgebaut und dieser erst baut die eigentliche Verbindung zum Zielrechner auf. Damit nun HTTP-Requests auf den Firewall selbst keine rekursiven Prozesse aufbauen (leidvolle eigene Erfahrung), muß der HTTP-Header in diesem Fall umgeschrieben werden, also "http://localhost/..." statt "http://firewall/...".  Dazu wird die Zieladresse des eigentlichen Ziels gegen alle Adressen der Netzwerkschnittstellen geprüft. Der Nachteil bei dieser Konstruktion ist, daß im Browser kein Proxy eingestellt sein darf. Alle Requests landen sonst auf dem lokalen Web-Server. Der Rest ist dann wieder simples hin- und herkopieren.

UDP
Bei UDP liegt der Fall komplizierter als bei TCP, man hat keine Verbindung. Jedes Paket kann für sich alleine stehen oder auch die Antwort auf ein anderes Paket sein. Es gibt viele Applikationen, angefangen bei DNS und traceroute, die UDP benutzen. Da man nicht weiß, ob ein bestimmtes Paket die Antwort auf ein anderes Paket ist, bleibt keine andere Möglichkeit, als sich alle UDP-Pakete zu merken und Verfallsdaten für Quasi-UDP-Verbindungen zu definieren (z.B. DNS-Request und DNS-Reply). Beim Eintreffen eines Antwort-Pakets wird die Zeitschranke wieder auf den Maximalwert gesetzt. Je beobachtetem UDP-Port (und ggf. Netzwerkschnittstelle) wird wie bei TCP ein Prozeß benötigt. Der Proxy-Prozeß hat eine Tabelle, die Originalquelle und -ziel, die beteiligten UDP-Ports, Zeitschranke und den Filedeskriptor des Antwort-Sockets enthält. Trifft nun ein UDP-Paket mittels select() auf dem gebundenen UDP-Port ein, wird die Tabelle nach der echten Zieladresse (der Trick hier ist das undokumentierte recvfrom(...,MSG_PROXY,...) und das Lesen der Kernel-Sourcen) durchforstet. Wenn der Eintrag nicht gefunden wird, ein Antwort-Socket eröffnet, und dann wird das Paket über diesen Antwort-Socket ausgeliefert. Ein ankommendes Paket auf diesem Socket wird mit Hilfe der Informationen der Tabelle mit einem neuen Header versehen und an die ursprüngliche Quelle ausgeliefert.

Das hier beschriebene Verfahren ist nicht der Weisheit letzter Schluß und hat eine Reihe von Schwachstellen, unter anderem die vielen Prozesse und Dateien (traceroute !), aber es läuft in der Praxis sehr zuverlässig. Verbesserungsvorschläge und Geistesblitze sind trotzdem jederzeit herzlich willkommen.

ICMP
Ein transparenter Proxy wie bei TCP und UDP läßt sich mit den bis jetzt beschriebenen Mitteln nicht bauen, es fehlt nämlich die dafür notwendige Kernel-Unterstützung. Deshalb muß man sich hier etwas Neues einfallen lassen, wenn man mit dem ping-Kommando, das von allen erwartet wird, arbeiten will. Glücklicherweise gibt es im iptables-Kommando die Option -o, die Pakete an das  Netlink-Gerät 36,3 ausliefert. Da auch in den Standard-Dokumenten kein Name für dieses Gerät existiert, habe ich es der Einfachheit halber /dev/firewall genannt. Auf dieses Gerät greift unser Proxy-Prozeß zu. Zunächst werden anders als bei TCP und UDP die Pakete nicht redirektioniert, sondern verworfen und gleichzeitig an /dev/firewall geschickt, also "-o -j DENY". Der Proxy-Prozeß öffnet dieses Gerät und liest. Alle Pakete werden so wie sie ankommen, vorneweg ein Header mit Angaben zur Gesamtlänge dorthin geschrieben. Das weitere Vorgehen ist wieder wie beim transparenten UDP-Proxy : eine Tabelle wird gehalten und Quelle, Ziel, Typ, Code und ID verglichen. Im Falle einer Übereinstimmung wird ein neues ICMP-Paket mit angepaßter Quelle und Ziel vom Proxy losgeschickt. Da es möglicherweise mehrere Routen gibt, muß für sendto() vorher ermittelt werden, welches der richtige Gateway ist.

 


Web- und FTP-Caching

Auch wenn fast jeder Browser heutzutage einen integrierten Cache hat, kann damit der Mehrfachaufruf einer Web-Seite von verschiedenen Clients nicht bedient werden. Ein häufiger Anwendungsfall für geschachtelte transparente Proxies sind Anwendungen wie z.B. Squid oder Apache, die als Web-Cache und -Proxy konfigurierbar sind. Apache hat dabei noch den Vorteil, daß ein HTTP-Server integriert ist und mit Zusatzmodulen zu einem HTTPS-Server aufgemotzt werden kann. Dadurch ist zusätzlich - die entsprechenden Web-Seiten vorausgesetzt - eine verschlüsselte Fernkonfiguration per Browser möglich.

 

Rechner A ruft eine eine Internet-Webseite von Rechner B  über den Firewall auf. Die Anforderung (Port 80/www) wird per REDIRECT auf den Proxy-Prozeß (A) umgeleitet. Dieser schreibt den HTTP-Header um und addressiert den Firewall-HTTP-Proxy (B) (Squid oder Apache). Der HTTP-Proxy (B) holt die Web-Seite, leitet sie an den Proxy-Prozeß (A) weiter und legt sie zusätzlich im lokalen Cache ab. Der Proxy-Prozeß (A) nimmt zusätzliche Prüfungen vor. Beispielweise werden beim sogenannten Content Filtering Viren gesucht, JavaScript, Java- oder DCOM(ActiveX)-Objekte ausgeblendet, Cookies nicht durchgelassen, usf.. Anschließend wird diese (oder im Falle eines Virus eine Ersatzseite) an den Client (Rechner A)zurückgeleitet.

Die Benutzung als FTP-Cache ist auch einfach : als URL ist der FTP-Zugriff ftp:://der.server/pfad.zur.datei. Man schreibt einen transparenten FTP-Proxy, der das FTP-Protokoll bis zu dem Zeitpunkt bedient, an dem eine Datei angefordert wird. Statt nun die Datei per FTP zu holen, wird ein HTTP-Request an den Firewall-HTTP-Proxy abgesetzt. Damit wird auch automatisch dessen Cache benutzt. Damit sind mehrfache Downloads großer Dateien möglich, ohne die Internet-Bandbreite tatsächlich zu beanspruchen.