Iptables

Der Paketfilter für Linux heißt netfilter und ist Bestandteil des Linux-Kernels. Das zugehörige Kontrollprogramm heißt iptables. Da man in der täglichen Praxis den Paketfilter durch das Kommando iptables konfiguriert, wird oft nur von iptables gesprochen und der Paketfilter von Linux insgesamt gemeint. Durch netfilter/iptables kann ein Linux-Rechner als Firewall arbeiten.

Zum Verständnis von netfilter/iptables sind Vorkenntnisse in den TCP/IP Netzwerkprotokollen erforderlich, die hier vorrausgesetzt werden. Die TCP/IP Netzwerkprotokolle werden auf einer eigenen Seite besprochen.

Aufbau

Netfilter kennt Tabellen und Ketten. Es existieren 3 Tabellen und 5 vordefinierte Ketten. Es ist auch möglich benutzerspezifische zusätzliche Ketten anzulegen. Die 3 Tabellen sind die Filter-, die NAT- und die Mangle-Tabelle. Die Filter-Tabelle ist wie der Name sagt für das Filtern von Netzwerkverkehr zuständig. In ihr findet die hauptsächliche Arbeit statt und die meisten iptables-Regeln beziehen sich auf diese Tabelle. In der NAT-Tabelle finden Adressumschreibungen statt. Wie der Name bereits sagt umfaßt dies NAT, aber auch andere Adressumschreibungen. In der Mangle-Tabelle finden Veränderungen an Paketen statt. Sie wird nur sehr selten eingesetzt und hier nicht weiter behandelt.

Die vordefinierten Ketten sind die Prerouting-, die Postrouting-, die Input-, die Output- und die Forward-Kette. Jede Kette arbeitet an einer bestimmten Position des Paketflusses. Außerdem hat jede Tabelle nur bestimmte vordefinierte Ketten. Die Filter-Tabelle nutzt nur die Input-, die Forward- und die Output-Ketten, die NAT-Tabelle arbeitet nur mit der Prerouting-, der Postrouting- und der Output-Kette. Die Mangle-Tabelle arbeitet mit der Prerouting-, der Postrouting-, der Input- und der Output-Kette. Die folgende Grafik verdeutlicht die Position der Ketten im Paketfluss durch einen Rechner. Die Mangle-Tabelle wird dabei in folgender Grafik nicht berücksichtigt.

Iptables Ketten

Pakete die von außen in das System kommen, passieren zuerst die Prerouting-Kette. Diese arbeitet nur in der NAT-Tabelle. Sind diese Pakete für das System selbst bestimmt, kommen sie danach in die Input-Kette. Anschließend werden die Pakete an lokale Prozesse weitergereicht. Sollte das Paket hingegen das System nur durchlaufen und für ein anderes System bestimmt sein (was vorraussetzt, das der Rechner mehrere Netzwerkkarten hat), dann gelangt das Paket in die Forward-Kette. Nach der Forward-Kette gelangt das Paket in die Postrouting-Kette und verläßt anschließend das System wieder. Ein Paket das vom lokalen System selbst erzeugt wurde, gelangt zunächst in die Output-Kette. Die Output-Kette existiert sowohl in der NAT-Tabelle, als auch in der Filter-Tabelle. Anschließend gelangen solche Pakete ebenfalls in die Postrouting-Tabelle.

Filterregeln für Pakete die das System durchlaufen werden daher auf die Forward-Kette angewandt. Filterregeln für Pakete die an das System selbst gerichtet sind, werden in der Input-Kette angewandt. Filterregeln die gelten sollen für Pakete die vom System selbst ausgehen, werden in der Output-Kette angewandt. Ein Source-Nat (das heißt eine Umschreibung der Quell-IP-Adresse), erfolgt in der Postrouting-Kette unmittelbar bevor die Pakete den Kernel verlassen. Ein Destination-Nat (das heißt eine Umschreibung der Zieladressen) erfolgt sinnvollerweise unmittelbar nachdem die Pakete den netfilter betreten, also in der Prerouting-Tabelle.

Einsatzmöglichkeiten

Netfilter/iptables kann sowohl auf einem Router genutzt werden, was klassischerweise bei einer Firewall der Fall ist, kann aber auch auf einem Rechner verwendet werden um den Rechner selbst zu schützen. Verschiedene Firewallszenarien mit ihren jeweiligen Vor- und Nachteilen, werden auf einer eigenen Seite besprochen.

Neben dem Filtern von Netzwerkpaketen nach Kriterien wie IP-Adresse oder Portnummer, kann iptables auch eingesetzt werden, um auf einen Router, hinter dem sich ein Netzwerk mit privaten IP-Adressen befindet, diese Adressen in eine öffentliche Adresse umzuschreiben. Dies wird mit Source-NAT (SNAT bezeichnet). Sollen interne Dienste eines solchen Netzes von außen erreichbar sein, muß dieser Router Verbindungen an bestimmte Ports, an den entsprechenden Rechner weiterleiten. Auch dieses Verfahren welches Destination Nat oder manchmal auch Portforwarding genannt wird, kann netfilter/iptables leisten.

Regelsyntax

Teilweise werden in den folgenden Beispielen die iptables-Kommandos aus Platzgründen mit umgebrochenen Zeilen angezeigt. Die Kommandos sollten jedoch immer innerhalb einer Zeile eingegeben werden.

Netfilter ist modular aufgebaut. Es kann sein, das bestimmte Funktionalitäten des Netfilters als separate Kernelmodule vorliegen, die zur Benutzung erst geladen werden müssen. Auf modernen Linuxsystemen geschieht das Laden dieser Module allerdings bei Anforderung der entsprechenden Funktionalität über iptables automatisch.

Die allgemeine Syntax einer iptables Anweisung ist:

iptables -t tabelle optionen

Wird die Angabe für die Tabelle weggelassen wird immer von der Filter-Tabelle ausgegangen. Bei den Optionen wird meist eine Kette definiert werden. Es gibt aber auch einige allgemeine Optionen für alle Ketten einer Tabelle, wie etwa -L, welches alle derzeit gültigen Regeln auflistet:

iptables -L

Dies wird alle derzeit gültigen Regeln der Filter-Tabelle auflisten. Während folgendes alle gültigen Regeln der NAT-Tabelle auflisten wird.

iptables -t nat -L

Soll die Ausgabe ausführlicher werden und zusätzliche Optionen anzeigen, kann noch die Option -v benutzt werden:

iptables -L -v

Mit der Option -F können alle Regeln einer Kette gelöscht werden. Dazu muß nur der Name der Kette angegeben werden:

iptables -F FORWARD
iptables -t nat -F POSTROUTING

Das erste Kommando löscht alle Regeln der Forward-Kette innerhalb der Filter-Tabelle, während das zweite Kommando alle Regeln der Postrouting-Kette innerhalb der Nat-Tabelle löscht.

Trifft auf ein Paket keine definierte Regel zu, gilt eine Policy, die bestimmt ob solche Pakete durchgelassen oder verworfen werden. Dadurch lassen sich sowohl Blacklisting-Konzepte, als auch Whitelisting-Konzepte realisieren. Für das Whitelisting muß nur die Policy auf ablehnen gestellt werden und die weiteren Regeln definieren welche Pakete erlaubt sind. Für das Blacklisting muß die Policy nur auf annehmen gestellt werden und die weiteren Regeln definieren, welche Pakete verboten sind. Für Firewalls ist der Whitelisting-Ansatz immer der sicherere.

Folgende iptables Kommandos definieren für die Ketten der Filter-Tabelle Policys:

iptables -P INPUT -j DROP
iptables -P FORWARD -j DROP
iptables -P OUTPUT -j ACCEPT

Mit der Option -P wird definiert für welche Kette eine Policy gelten soll. Mit der Option -j wird eine Aktion (auch Target genannt) für die Policy festgesetzt, dies kann entweder ACCEPT sein, welches Pakete durchläßt, oder DROP welches Pakete verwirft. In diesem Fall werden Pakete in der Forward- und der Input-Kette verworfen, sofern keine andere Regel zutrifft, während Pakete in der Output-Kette heraus gelassen werden. Diese Einstellung kann auf einer Firewall durchaus sinnvoll sein, da man seiner Firewall selbst im allgemeinen sowieso vertrauen muß und diese daher unbeschränkt Pakete ins Netzwerk senden darf.

Die eigentlichen Regeln, also die Ausnahmen von der Policy haben die allgemeine Syntax iptables -t tabelle Kette Kriterium -j Aktion. Wird die Tabelle weggelassen, gilt auch hier wieder, die Filter-Tabelle als Standard. Aktionen werden auch als Target bezeichnet und beschreiben was mit den Paketen geschehen soll. Je nachdem welcher Parameter mit der Kette angegeben wird, wird die entsprechende Regel angehängt (-A), gelöscht (-D), eingefügt (-I) oder ersetzt (-R). Sollen einfach nur neue Regeln an eine Kette angehängt werden, wird -A verwendet:

iptables -A INPUT -p tcp -s 192.168.0.11 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A FORWARD -s 192.168.0.12 -d 217.11.53.11 -j ACCEPT

Die ersten beiden Regeln werden an die INPUT Kette in der Filter-Tabelle angehängt. Die erste Regel trifft auf alle TCP-Verbindungen (-p tcp) von der Quell-IP 192.168.0.11 (-s 192.168.0.11) zu. Diese werden erlaubt. Die zweite Verbindung betrifft alle TCP-Verbindungen, die an den Zielport 22 (--dport 22) gerichtet sind. Auch hier ist die Aktion wieder erlauben. Wird ein Port angegeben, muß zwangsläufig vorher als Protokoll entweder TCP (-p tcp) oder UDP (-p udp) vorher definiert worden sein. Ein weiterer Möglicher Wert für -p ist ICMP welches jedoch keine Portnummern kennt. Die dritte Regel gilt für die Forward-Kette der Filter-Tabelle. Das Kriterium trifft zu wenn die Quell-IP Adresse 192.168.0.12 (-s 192.168.0.12) und die Ziel-IP Adresse 217.11.53.11 (-d 217.11.53.11) ist. Die Aktion ist wieder das durchlassen der Pakete.

ICMP kennt keine Portnummern sondern ICMP-Typen. Diese können ebenfalls als Filterkriterium dienen:

iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

Dieses Kommando läßt Pings (ICMP-Typ eines Pings ist echo-request) passieren. ICMP-Typen haben sowohl Namen, als auch Nummern. Einige Nummern haben auch Untercodes. Folgende Tabelle gibt einen Überblick über Name, Nummer und Code.

ICMP Typen
NummerCodeName
0echo-reply oder pong
3destination-unreachable
30network-unreachable
31host-unreachable
32protocol-unreachable
33port- unreachable
34fragmentation-needed
35source-route-failed
36network-unknown
37host-unknown
38Source Host Isolated
39network-prohibted
310host-prohibted
311TOS-network-unreachable
312TOS-host-unreachable
313communication-prohibted
314host-precedence-violation
315precedence-cutoff
4source-quench
5redirect
50network-redircet
51host-redirect
52TOS-network-redirect
53TOS-host-redirect
6Alternate Host Address
8echo-request oder ping
9router-advertisement
90Normal router advertisement
916Does not route common traffic
10router-solicitation
11time-exceeded oder ttl-exceeded
110ttl-zero-during-transit
111ttl-zero-during-reassembly
12parameter-problem
120ip-header-bad
121required-option-missing
122Bad Length
13timestamp-request
14timestamp-reply
15Information Request
16Information Reply
17address-mask-request
18address-mask-reply
30Traceroute
31Datagramm Conversion Error
32Mobile Host Redirect
33IPv6 Where-are-you
34IPv6 I-Am-Here
35Mobile Registration Request
36Mobile Regsitration Reply
37Domain Name Request
38Domain Name Reply
39SKIP
40Photuris
400Bad SPI
401Authentication Failed
402Decompression Failed
403Decryption Failed
404Need Authentication
405Need Authorization

Die kursiv geschriebenen Namen lassen sich direkt als Wert für --icmp-type verwenden. Für alle anderen muß die jeweilige Nummern/Code Kombination angegeben werden. Wird ein Code benötigt, sieht die Schreibweise beispielsweise so aus:

iptables -A FORWARD -p icmp --icmp-type 3/7 -j ACCEPT

Dieses Kommando erlaubt den ICMP Typ Host unknown. Einige ICMP-Typen sollten an einer Firewall im allgemeinen gesperrt werden, während andere besser durchgelassen werden. Der ICMP-Typ 3 (destination unreachable) sollte im allgemeinen durchgelassen werden, damit Clients eine Fehlermeldung aus dem Netzwerk bekommen, wenn ihre Pakete nicht zugestellt werden können. Ob auch Pings erlaubt werden oder nicht ist Geschmacksfrage. Für die Fehleranalyse leisten Pings oft gute Dienste und ein bloßer Ping ist an sich keine Sicherheitslücke. Andere ICMP-Nachrichten, wie etwa Redirects lassen sich aber durchaus mißbrauchen und sollten gesperrt werden, sofern man sie nicht benötigt.

Sollte die Policy alle nicht in Regeln erfassten Pakete bereits sperren, kann folgende Regel verwendet werden, um in der Input- und Forward-Kette, Pings und Destination unreachable Meldungen zu erlauben:

iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type 3 -j ACCEPT
iptables -A FORWARD -p icmp --icmp-type 8 -j ACCEPT
iptables -A FORWARD -p icmp --icmp-type 3 -j ACCEPT

Eine Übersicht über die wichtigsten Kriterien für Regeln bietet die folgende Tabelle.

Filter Kriterien
Optionmögliche WerteGültig nur ...Bedeutung
-ptcp, udp, icmpAuswahl des Protokolls
-sIP-Adressen oder Netzwerke in CIDR Schreibweisein der Input- oder Forward-KetteQuell-IP Adresse
-dIP-Adressen oder Netzwerke in CIDR Schreibweisein der Forward- oder Output-KetteZiel-IP Adresse
-iInterface Name (ethX)in der Input- oder Forward-KetteNetzwerkinterface über welches die Pakete ankommen
-oInterface Name (ethX)in der Output- oder Forward-KetteNetzwerkinterface über welches die Pakete das System verlassen
--dportPortnummerin Verbindung mit dem TCP- oder dem UDP-ProtokollPortnummer des Zielports
--sportPortnummerin Verbindung mit dem TCP- oder dem UDP-ProtokollPortnummer des Quellports
--icmp-typeICMP-Typ oder Namein Verbindung mit dem ICMP-ProtokollICMP-Typen
--synkeinein Verbindung mit dem TCP ProtokollPrüft ob von den TCP-Flags SYN,RST und ACK, nur das SYN-Flag vorhanden ist. Kann verwendet werden um einen TCP Verbindungsaufbau zu erkennen.

Durch die Wahl eines Output-Interfaces und eines Input-Interfaces, innerhalb der Forward-Kette, ist es möglich zu bestimmen, ob Regeln für Netzwerkverkehr vom internen Netz nach außen, oder von außen ins interne Netz gelten sollen. Soll zum Beispiel von Innen nach außen alles erlaubt sein, während von Außen nach Innen nur SSH erlaubt ist und das interne Interface ist eth0, während das externe Interface eth1 ist, könnten die Regeln etwa so aussehen:

iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -p tcp --dport 22 -j ACCEPT

Bei der Abarbeitung der Regeln gilt, daß die erste Regel die zutrifft, die Aktion bestimmt. Sollten noch weitere Regeln mit ihren Kriterien zutreffen werden diese nicht beachtet. Die Regelabarbeitung wird bei der ersten passenden Regel gestoppt.

Antwortpakete

Meistens möchte man Antworten auf gesendete Pakete automatisch ebenfalls erlauben. Hierfür kennt netfilter die Möglichkeit des Connection-Trackings, welches aus netfilter/iptables eine sogenannte Stateful Firewall macht. Beim Connection Tracking behält sich netfilter den Status der Verbindung und läßt korrespondierende Antwortpakete ebenfalls durch. Für das Connection Tracking ist ein eigenes Modul zuständig welches durch den Parameter -m state geladen wird:

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Diese Regel läßt sämtlichen Netzwerkverkehr passieren, welcher als Antwort auf vorher ausgesandte Anfragen erkannt wird. Dabei wird neben TCP Verkehr auch UDP- und ICMP-Verkehr berücksichtigt. Während TCP aufgrund des Protokolls explizit einen Status kennt, ist dies bei ICMP und UDP nicht der Fall. Hier wird einfach anhand von Quell- und Ziel-Adresse und einem Timeout abgeglichen, ob es sich um ein Antwortpaket handelt oder nicht. Grundsätzlich lassen sich die States NEW, ESTABLISHED und RELATED angeben. NEW bezieht sich auf Pakete die eine neue Verbindung initiieren. ESTABLISHED bezieht sich auf Pakete die Antworten auf andere Pakete sind.

RELATED bezieht sich ebenfalls auf Antwortpakete betrifft aber Spezialfälle: Manche Protokolle nutzen Verbindungen, die nicht ohne weiteres zueinander zuzuordnen sind. Dies trifft zum Beispiel auf FTP-Verbindungen zu, da FTP ein 2-Port Protokoll ist. Damit netfilter auch solche Verbindungen als zusammengehörig betrachtet wird das Stichwort RELATED benötigt. Solche Verbindungen benötigen oft auch noch ein spezielles netfilter-Modul, welches geladen werden muß. Dies sollte jedoch automatisch erfolgen. Das Modul um den Status einer FTP-Verbindung zu verfolgen ist ip_conntrack_ftp. Sollte dieses Modul nicht automatisch geladen werden, kann dies von Hand durch folgendes Kommando geschehen:

modprobe ip_conntrack_ftp

2 Arten des Blockierens

Die bislang benutzten Aktionen waren immer entweder DROP um Pakete abzuweisen, oder ACCEPT um Pakete durchzulassen. Werden Pakete mit der Aktion DROP verworfen, werden die Netzwerkpakete einfach vernichtet, ohne das der Client jemals eine Antwort bekommt. Meist ist dies genau das, was man auf einer Firewall möchte. Blockiert man aber auf diese Art auch interne Clients, ergibt sich das lästige Phänomen, das diese bei unerlaubten Netzwerkverbindungen erst auf ein Timeout warten und lange blockiert sind. Möchte man internen Clients direkt eine Fehlermeldung zurück schicken, die besagt, das diese Verbindung verboten ist, existiert auch die Aktion REJECT. Mit Reject werden Verbindungen ebenfalls blockiert, aber dem Client wird eine ICMP-Fehlermeldung (Destination unreachable) zurück geschickt, damit dieser sofort weiß, das er keine Antwort bekommen wird. Welche Art von Fehlermeldung zurück geschickt wird ist konfigurierbar mit der zusätzlichen Option --reject-with. Diese Option kennt eine Reihe von ICMP Typen, sowie TCP-Pakete mit gesetzten RST-Flag, welches TCP-Verbindungen zurücksetzt. Wird diese Option nicht angegeben, wird immer ein icmp-port-unreachable Paket als Antwort verwendet. Alternativ kann auch icmp-host-prohibted oder icmp-network-prohibited verwendet werden. Nur bei TCP-Verbindungen kann auch tcp-reset verwendet werden, welches ein TCP Paket mit gesetzten RST Flag zurück schickt. 2 Beispiele:

iptables -A INPUT -p tcp -s 192.168.0.0/24 -j REJECT --reject-with tcp-reset
iptables -A INPUT -s 192.168.0.0/24 -j REJECT --reject-with icmp-host-prohibited

Im ersten Beispiel werden TCP-Pakete aus dem Netzwerk 192.168.0.0/24 mit einem TCP RST Paket beantwortet, welches die Verbindung abbricht. Im zweiten Beispiel werden alle Pakete aus dem Netzwerk 192.168.0.0/24 mit einem ICMP Paket vom Typ Host prohibited abgewiesen.

Da stets die erste zutreffende iptables Regel die Aktion bestimmt die durchgeführt wird, sollten die spezielleren Fälle vor den allgemeinen stehen. Daher ist hier die Regel die speziell für TCP-Pakete gilt, vor der Regel die für alle Pakete aus diesem Netzwerk gilt definiert worden. Diese Regeln müssen daher auch nach eventuellen spezielleren Erlaubnisregeln aufgeführt werden.

Sofern die Policy auf DROP gesetzt wurde (diese kann nur auf den Aktionen DROP oder ACCEPT stehen) und man möchte internen Clients eine Fehlermeldung zurücksenden, wenn diese versuchen nicht erlaubte Verbindungen aufzubauen, kann folgende Regel verwendet werden, die davon ausgeht, daß eth0 die interne und eth1 die externe Schnittstelle ist:

iptables -A FORWARD -i eth0 -o eth1 -j REJECT

Diese Regel muß nach allen Erlaubnisregeln stehen.

NAT

Außer dem Filtern erledigt iptables auch NAT, also Addressumschreibungen. Als Source-NAT wird dabei die Umschreibung einer Quell-IP Adresse bezeichnet. Solch eine Umschreibung ist dann notwendig, wenn Rechner in einem Netzwerk mit privaten IP Adressen, das Internet erreichen sollen. Im Internet werden private IP Adressen gar nicht geroutet, daher müssen diese Adressen beim verlassen der Firewall in eine öffentliche Adresse umgeschrieben werden. Hierzu wird die öffentliche IP-Adresse des Routers, bzw. der Firewall verwendet. Linux unterscheidet hierbei 2 Formen: Sofern die Firewall eine feste öffentliche IP Adresse hat, sollte die SNAT Aktion durchgeführt werden. Dieser Aktion wird die feste IP Adresse übergeben. Sollte die Firewall für ihre öffentliche Adresse eine dynamisch zugewiesene Adresse besitzen, muß die Masquerade Aktion angegeben werden. Masquerade ist ein Source NAT bei dem die IP Adresse jeweils neu aus der IP Adresse eines Interface Namens ermittelt wird. Masquerade ist dadurch aufwändiger als SNAT und sollte nur verwendet werden, wenn die IP Adresse tatsächlich dynamisch vergeben wurde. Da beide Aktionen beim verlassen der Pakete aus der Firewall in der NAT Tabelle durchgeführt werden sollen, müssen sie in der Postrouting Kette angewandt werden. Das folgende Beispiel zeigt die Verwendung von SNAT:

iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to-source 18.1.23.4

Hier wird mit -o eth1 Das Interface bestimmt über welches die Netzwerkpakete die Firewall in Richtung Internet verlassen. Für das SNAT Target wird die Option --to-source benötigt, welche die IP Adresse angibt, welche als neue Quell-IP Adresse benutzt werden soll. Dieser Option können auch mehrere IP Adressen als Bereich übergeben werden. In diesem Fall werden die verwendeten Adressen auf den angegebenen Bereich verteilt, sofern man der Firewall mehrere öffentliche IP Adressen zugewiesen hat.

Folgendes ist ein Beispiel für Masquerade:

iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

Das Masquerade Target benötigt keine Option. Es ermittelt die IP Adresse, die als neue Quell-IP verwendet werden soll, anhand der IP Adresse des angegebenen Output-Interfaces (hier eth1).

Sowohl das SNAT Target, als auch das Masquerade Target kennen seit Linux Kernel 2.6.21 auch die zusätzliche Option --random. Diese sorgt dafür das die gewählten Quellports für das NAT zufällig gewählt werden, was eine zusätzliche Sicherheitsmaßnahme darstellt.

Der umgekehrte Fall ist Destination NAT. Beim Destination NAT werden die Zieladressen umgeschrieben. Dies wird dann benötigt, wenn ein interner Server, der eine private IP Adresse hat, aus dem Internet heraus zugänglich sein soll. Dies wird auch als Portforwarding bezeichnet. In diesem Fall werden die IP Pakete an die Firewall gerichtet und die Firewall schreibt die IP-Adresse um und schickt die Pakete an ihr endgültiges Ziel. Da diese Umschreibung vor allen anderen Aktionen gemacht werden muß, also unmittelbar wenn das Paket ins System eintritt, wird das Destination NAT in der Prerouting Kette umgesetzt. Für das Destination NAT existiert das Target DNAT, welches als Option --to-destination nutzt um festzulegen welche Zieladresse genutzt werden soll. Ein Beispiel:

iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j DNAT --to-destination 192.168.0.30

Dieses Kommando leitet Netzwerkverkehr welcher an die Firewall an Port 80 TCP gerichtet ist, an die interne IP Adresse 192.168.0.30 weiter. Es ist auch möglich außer der Ziel-IP auch den Zielport umzuschreiben. Sollen zum Beispiel Pakete die an die Firewall an Port 443 gerichtet sind an eine interne IP an Port 22 weiter geleitet werden, läßt sich folgende Syntax nutzen:

iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 443 -j DNAT --to-destination 192.168.0.30:22

Soll lediglich eine Verbindung auf einen intern auf der Firewall selbst laufenden Dienst umgeleitet werden, existiert für diesen Zweck das Target REDIRECT. Dies kann zum Beispiel genutzt werden um einen transparenten Proxy auf der Firewall zu betreiben. Das REDIRECT Target hat die Option --to-ports, die bestimmt auf welchen Port, das Paket geleitet wird. Wird die Option nicht angegeben, wird der selbe Port verwendet, der im Paket definiert ist. Auch das REDIRECT Target wird in der Prerouting Kette verwendet. Soll beispielsweise ein lokaler Squid-Proxy der auf Port 3128 lauscht, als transparenter Proxy benutzt werden, können alle Webserververbindungen (die eigentlich an Port 80 gehen) so umgeleitet werden:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-ports 3128

Logging

Auch Logging ist mit netfilter/iptables möglich. Hierzu existiert das Target LOG. Während normalerweise immer die erste zutreffende Regel die Aktion, bzw. das Target bestimmt, welches angewendet wird, ist dies beim LOG-Target eine Ausnahme. Damit Pakete die geloggt werden, auch gleichzeitig gefiltert werden können, bricht die Regelverarbeitung bei einem Treffer mit einem LOG Target nicht ab. Möchte man Pakete die auf ein bestimmtes Kriterium passen gleichzeitig loggen und blockieren, definiert man zuerst eine iptables Regel mit dem Target LOG und anschließend eine iptables Regel mit den selben Kriterien und dem Target DROP (oder REJECT).

Dieses Target kennt als Option --log-level welches angibt, mit welchen Loglevel Meldungen geloggt werden sollen. Logmeldungen werden immer an den Syslog Dienst übergeben. Dieser kennt verschiedene Facilities und Priorities. Facilities beschreiben woher Logmeldungen stammen. Da netfilter ein Bestandteil des Linuxkernels ist, haben Logmeldungen von netfilter/iptables immer die Facility kern welche für Kernelmeldungen bestimmt ist. Priorities bestimmen, die Wichtigkeit von Logmeldungen, also zum Beispiel ob es sich um Fehlermeldungen oder bloße Debugmeldungen handelt. Priorities sind in aufsteigender Reihenfolge: debug, info, notice, warn oder warning, err oder error, crit, alert und emerg. Die Voreingestellte Priority ist warning. Das folgende Beispiel loggt alle Verbindungen an den SSH-Port des Firewall-Rechners selbst, mit der Priority notice:

iptables -A INPUT -p tcp --dport 22 -j LOG --log-level notice

Wo diese Logmeldungen landen hängt von der Konfiguration des Syslog-Dienstes ab. Auf vielen Linuxdistributionen werden Kernelmeldungen als Voreinstellung nach /var/log/messages oder /var/log/kern.log geschrieben. Folgende Zeile ist ein Beispiel für eine Logmeldung von iptables:

Apr 28 10:46:10 gawain kernel: [1787219.136784] IN=eth0 OUT= MAC=00:30:05:e3:44:63:00:30:05:ab:b2:39:08:00 SRC=192.168.0.231 DST=192.168.0.12 LEN=100 TOS=0x10 PREC=0x00 TTL=64 ID=38071 DF PROTO=TCP SPT=47727 DPT=22 WINDOW=16384 RES=0x00 ACK PSH URGP=0

Nach Zeitstempel Hostname und der Angabe der Facility geben die Meldungen (falls möglich) immer das Inputinterface (IN=) und das Outputinterface (OUT=) an. Da in diesem Fall kein Outputinterface beteiligt ist, fehlt diese Angabe. Dahinter kommen die Quelladresse und die Zieladresse. Da dieses Paket aus dem selben Netzwerk stammte, wird auch eine MAC-Adresse angegeben. Danach werden die verwendeten IP-Optionen angegeben, wie etwa TOS (Type of Service) oder DF für das Don't fragment Bit oder die TTL (Time to Live). Anschließend wird das verwendete Protokoll angegeben. In diesem Fall ist es das TCP Protokoll. Für TCP können auch Quellport (SPT) und Zielport (DPT) angegeben werden. Auch die Fenstergröße (WINDOW), sowie eventuelle TCP-Flags (in diesem Fall zum Beispiel ACK und PSH) werden angegeben.

Das LOG Target kennt zusätzlich auch noch die Option --log-prefix welches eine Zeichenkette erwartet und diese als zusätzliche Kennung in die Logmeldungen hinein schreibt.

Anwendung

Das Kommando iptables ist ein Befehl zur Steuerung von netfilter, besitzt jedoch keine Konfigurationsdatei. Aus diesem Grund gibt es zunächst keine Datei aus der Regeln geladen werden. Damit eine Firewall immer wieder die selben Regeln beim starten aus einer Datei anwendet, muß eine Scriptdatei mit iptables Aufrufen geschrieben werden und in den Bootprozess eingebunden werden. Um dies zu erreichen könnte man einfach die Datei /etc/rc.local verwenden, welche auf vielen Linuxdistributionen existiert und am Ende des Bootvorganges ausgeführt wird. Jede Aktion darin, wird daher bei jedem Booten, bzw. jeden ändern des Runlevels in einen Runlevel mit Multiuserunterstützung (also nicht im Runlevel 1) ausgeführt.

Diese Methode hat jedoch einen Nachteil: Da die Aktionen in /etc/rc.local am Ende des Runlevelwechsels ausgeführt werden, werden eventuelle Dienste vorher gestartet. Dies betrifft daher auch Dienste die durch die Firewall geschützt werden sollen. Dadurch entsteht ein kurzer Zeitraum von einigen Sekunden, in dem die Dienste nicht geschützt und dadurch angreifbar sind.

Die sauberste Methode ist das Schreiben eines eigenen Init-Scripts und einfügen des Init-Scripts in die Runlevel des Systems. Die meisten Distributionen besitzen für diesen Zweck eine Vorlage für neue Init-Scripts welche sich abändern läßt. In Debian Squeeze findet sich zum Beispiel eine entsprechende Vorlage unter /etc/init.d/skeleton. Möchte man trotzdem die Datei /etc/rc.local verwenden, sollte als Vorsichtsmassnahme die Weiterleitung von Paketen erst aktiviert werden, wenn auch die Firewallregeln aktiviert werden. Daher kann der Befehl zum Weiterleiten von Paketen zwischen mehreren Netzwerkkarten am besten direkt in das Firewallscript integriert werden. Dies verhindet das Dienste hinter der Firewall erreichbar sind, bevor die Firewall aktiv ist, nützt aber nichts für Dienste die auf der Firewall selbst laufen.

Generell sollte eine Firewall selbst möglichst keine Dienste anbieten. Läßt sich dies nicht vermeiden, sollten diese Dienste so konfiguriert werden, das diese nur auf die interne Schnittstelle lauschen, so das diese nicht von außen erreichbar sind. Mit diesen Vorsichtsmassnahmen ist es auch möglich den Aufruf den Firewallscripts aus der /etc/rc.local heraus vorzunehmen.

Wie sieht nun ein vollständiges Firewallscript aus? Folgendes Beispiel geht davon aus, das die Firewall 2 Netzwerkkarten besitzt: eth0 ist das Interface zum internen Netz, eth1 ist das Interface zum Internet. Auf der Firewall soll Source NAT auf eine dynamisch vergebene IP Adresse durchgeführt werden. Interne Clients dürfen surfen, wozu auch DNS Abfragen gehören. Verbindungen auf Webserver von internen Clients werden mitgeloggt. Das interne Subnetz hat den Adressbereich 192.168.0.0/24. Unter der IP 192.168.0.20 arbeitet ein Mailserver, der Emails an einen anderen Mailserver mit der IP 217.11.53.11 senden darf. Vom gleichen Mailserver werden auch Emails über SSL verschlüsseltes POP3 (Port 995) empfangen. Die DNS Server des Providers die für Namensauflösungen benutzt werden, haben die IP Adressen 8.8.8.8 und 8.8.4.4. Die Firewall selbst soll per SSH erreicht werden und zwar sowohl vom internen Netz, als auch von außen.

#!/bin/sh

# Zuerst werden alle alten Regeln gelöscht
iptables -F INPUT
iptables -F OUTPUT
iptables -F FORWARD
iptables -t nat -F OUTPUT
iptables -t nat -F PREROUTING
iptables -t nat -F POSTROUTING

# Anschließend werden die Policies gesetzt
# Die Standard-Policy ist DROP um einen
# Whitelistingansatz zu realisieren
iptables -P INPUT -j DROP
iptables -P FORWARD -j DROP
# Da der Firewall selbst vertraut wird, wird die Output Policy
# auf Accept gesetzt
iptables -P OUTPUT -j ACCEPT

# Da die Policies für Forward auf DROP gesetzt wurde,
# kann jetzt auch das Routing, also die Weiterleitung von
# Paketen aktiviert werden
echo 1 > /proc/sys/net/ipv4/ip_forward

# Jetzt kommen die NAT Rgeln
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE --random

# Jetzt kommen die Filterregeln

# Die Localhostschnittstelle wird vom Filtern ausgenommen
iptables -A INPUT -i lo -j ACCEPT

# Antwortpakete sollen immer durchgelassen werden
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# Die Firewall selbst soll per SSH erreichbar sein
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Jetzt kommen die Regeln für die internen Clients
# DNS muß funktionieren
iptables -A FORWARD -i eth0 -o eth1 -s 192.168.0.0/24 -d 8.8.8.8 -p udp --dport 53 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -s 192.168.0.0/24 -d 8.8.4.4 -p udp --dport 53 -j ACCEPT
# Die Regeln zum surfen, inklusive Logging
iptables -A FORWARD -i eth0 -o eth1 -s 192.168.0.0/24 -p tcp --dport 80 -j LOG
iptables -A FORWARD -i eth0 -o eth1 -s 192.168.0.0/24 -p tcp --dport 80 -j ACCEPT

# Die Regeln für den Mailserver
iptables -A FORWARD -i eth0 -o eth1 -s 192.168.0.20 -d 217.11.53.11 -p tcp --dport 25 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -s 192-168.0.20 -d 217.11.53.11 -p tcp --dport 995 -j ACCEPT

# Am Schluß werden unerlaubte Verbindungen von internen Clients
# noch mit einer Fehlermeldung quittiert, anstatt das Paket
# einfach nur zu verwerfen
iptables -A FORWARD -i eth0 -o eth1 -s 192.168.0.0/24 -J REJECT

Dieses Script kann in einem Verzeichnis gespeichert werden, welches im Pfad liegt und muß mit chmod ausführbar gemacht werden. Anschließend kann dieses Script entweder durch ein eigenes Startscript oder über /etc/rc.local aufgerufen werden.

Die Zeile: echo 1 > /proc/sys/net/ipv4/ip_forward schreibt eine 1 in die angegebene Datei. Diese Datei bestimmt ob Paketweiterleitung zwischen mehreren Netzwerkarten (Routing) aktiv ist oder nicht. Durch eine 1 wird das Routing aktiviert. Normalerweise steht in dieser Datei eine 0 für deaktiviertes Routing. Solange das Routing nicht aktiviert ist, bleiben Regeln in der Forward Kette ohnehin folgenlos, da gar keine Pakete weitergeleitet werden können.

Alles vorstehende gilt für IPv4 Pakete. Generell ist netfilter auch IPv6 fähig. Für IPv6 existiert das Kommando ip6tables, das im wesentlichen genauso funktioniert wie iptables und die gleichen Optionen kennt.

Literatur

Gregor N. Purdy: Linux iptables - kurz & gut, O'Reilly, 2004.


René Maroufi, dozent (at) maruweb.de
Creative Commons By ND