Die Netfilter-Schicht im Linux-Kernel ist in die Jahre gekommen und IPtables besticht nicht gerade durch Bedienfreundlichkeit. Mit Bpfilter soll Linux einen Paketfilter auf der Höhe der Zeit erhalten.
Netfilter [1], das wichtigste Werkzeug unter Linux, um Pakete aus dem Netzwerk zu prüfen und gegebenenfalls auszusortieren, genießt keinen sonderlich guten Ruf. Es gilt als altbacken und ineffizient und das zugehörige Userland-Werkzeug IPtables als sperrig, zumindest was den Bedienkomfort angeht. Wer kann, beschäftigt sich erst gar nicht mit dem Thema Firewalls unter Linux.
Wer sich aber doch damit auseinandersetzen muss, der greift zu Dritthersteller-Lösungen, die IPtables dann mit einem recht ansprechenden GUI verschönern und darüber hinaus auch noch den größten Teil des älteren Netfilter vor den Augen des Admin verbergen helfen.
Doch jetzt ist die Rettung nahe: Mit Bpfilter [2] haben Entwickler vor ein paar Wochen das Fundament für einen weiteren Paketfilter in Linux gelegt, der die Wende bringen und IPtables endlich überflüssig machen soll. Was unterscheidet den neuen Filter von IPtables? Und was ist eigentlich aus NFtables geworden, das zwischenzeitlich ja auch schon als IPtables-Nachfolger in den Startlöchern stand?
Die Wurzeln von IPtables reichen bis ins Jahr 1999 zurück. Ab Linux 2.4 ersetzte IPtables damals endgültig IPchains, das seinerseits das altbackene IPfwadmin wenige Jahre zuvor abgelöst hatte. Nicht wenigen ging das Kommen und Gehen der Netzwerkfilter in Linux auf die Nerven. Auch das ist wohl einer der Gründe dafür, dass IPtables sich so lange halten konnte. Der Hauptgrund aber, der IPtables bis heute Standard in Sachen Paketfilterung in Linux sein lässt, sind der Mangel an besseren Alternativen und die Tatsache, dass später aufgekommene Software mit IPtables nicht kompatibel war.
Technische Defizite
Allerdings bekommt IPtables auch Schelte ab, die gar nicht ihm gelten sollte, sondern dem Netfilter-Stack, der mit IPtables nicht (mehr) völlig deckungsgleich ist. Als die Entwicklung von Netfilter Ende der 90er Jahre begann, gingen die meisten Haushalte noch per 56k-Modem ins Netz – wer zu eben dieser Generation der Internetnutzer gehört, erinnert sich sicher noch an deren charakteristische Geräuschkulisse.
Der seinerzeit für Linux bereits zur Verfügung stehende Paketfilter »ipchains« war einerseits schwer zu warten und auf der anderen Seite langsam und ineffizient. Rusty Russell, der maßgeblich an der Entwicklung von IPchains beteiligt gewesen war, erkannte das Problem und gelobte Besserung. IPtables sollte das neue Allheilmittel in Sachen Paketfilter für Linux heißen. Und anders als sein eher wenig geliebter Vorgänger sollte es auch viel schneller und noch effizienter werden. So weit, so gut.
Doch leider unterliefen Russel und seinem Team bei der Entwicklung von IPtables ähnliche Fehler wie bei der von IPchains schon Jahre zuvor. Natürlich muss man zugeben, dass 1998 nicht absehbar war, dass im Jahr 2018 Rechner nicht mehr mit 100 MBit, sondern mit 100 GBit pro Sekunde ins Netz gehen würden. Jedenfalls versäumten es die Linux-Entwickler, IPtables mit einer Architektur zu versehen, die sich einer enorm steigenden Paketmenge gut hätte anpassen können.
Zum Zweiten: Als die IPtables-Entwicklung begann, gab es einen großen Teil der Design-Prinzipien und Mantras moderner Kernelentwicklung schlicht noch nicht. Ein eherner Grundsatz ist es heute beispielsweise, Code so generisch wie möglich zu bauen, damit andere ihn bei Bedarf ebenfalls verwenden können. Meist geschieht das in Form von Frameworks, bei denen die Funktionalität allgemein implementiert ist, sodass andere Komponenten sie in ihrem Sinne nutzen können.
Ein gutes Beispiel dafür ist die Virtualisierung im Linux-Kernel: Als Xen und KVM seinerzeit den Einzug in den Kernel anstrebten, war es kein geringerer als Linus Torvalds selbst, der erst mal ein virtuelles Stoppschild aufstellte. Er forcierte die Entwicklung einer generischen Virtualisierungsschicht im Kernel (PVops), die Xen wie KVM heute nutzen. Das alles geschah allerdings lange nach IPtables, und so wundert es nicht, dass IPtables dem Framework-Ansatz nicht folgt.
Funktionen – tief vergraben im Code
Prinzipiell muss sich Netfilter mit vier Arten von Datenverkehr auseinandersetzen: In seine Zuständigkeit fallen IPv4, IPv6, ARP sowie die weniger bekannten Ethernet-Pakete. Wer eine Lösung wie Netfilter heute implementieren wollte, der würde wohl eine generische Filtervorrichtung auf der einen Seite bauen und sich auf der anderen Seite mit den einzelnen Netzwerkprotokollen in Form spezialisierter Module auseinandersetzen. IPtables hat im Gegensatz zu dieser Herangehensweise weite Teile der Filterfunktionalität so tief in den Modulen für die einzelnen Protokolle vergraben, dass sie sich kaum sinnvoll an anderer Stelle recyceln lassen.
Das führt allerdings einerseits zu jeder Menge Redundanz im Code des Kernels und andererseits dazu, dass der Netfilter-Programmtext ziemlich schwierig zu warten ist. Wann immer die Kernelentwickler in den vergangenen Jahren Änderungen am Netfilter-Code vorgenommen haben, dienten ihre Eingriffe der Performanceverbesserung. Trotz allem lag ein grundlegendes Redesign schon seit längerer Zeit in der Luft.
An dieser Stelle sind noch kurz einige Begrifflichkeiten zu klären, mit denen es der Anwender im Paketfilter-Kontext unter Linux immer wieder zu tun bekommt. IPtables und Netfilter werden regelmäßig als praktisch deckungsgleich betrachtet, was allerdings nur die halbe Wahrheit ist. Nach der IPtables-Einführung waren die Begriffe zwar wirklich noch synonym, doch mittlerweile gibt es kleine und feine Unterschiede.
Was ist was?
Netfilter bezeichnet zunächst den Kernel-Teil, also jene Module im Linux-Kernel, die an den Netzwerkschnittstellen andocken. Der Kernel leitet ein- wie ausgehenden Datenverkehr durch den Netfilter-Layer, wo für die einzelnen Module dann die Möglichkeit besteht, diesen zu manipulieren. Das Verwerfen oder Zurückweisen von Paketen ist dabei nicht die einzige Funktion von Netfilter: Erinnert sei etwa an NAT (Masquerading), das ebenfalls über den Netfilter-Layer im Kernel realisiert ist. Genau hier findet sich auch der zuvor erwähnte Wust verschiedener Codes, der Netfilter ineffizient und langsam macht.
Komplementär dazu existiert IPtables als Kommandozeilen-Werkzeug. Mit »iptables« bearbeitet der Admin das Regelwerk der verschiedenen Module des Netfilter-Layers im Kernel. Denn ab Werk liefern die Netfilter-Module nur die benötigten Funktionen – das Regelwerk muss der Admin selbst hinzuerfinden.
Übersetzt bedeutet IPtables ja zunächst mal “IP-Tabellen”, hinter dem Namen versteckt sich ein Verweis auf die Art und Weise, wie IPtables das Regelwerk im Kernel hinterlegt: In Form von Tabellen. Netfilter geht die in Tabellen abgelegten Regeln für die durchlaufenden Pakete durch, es gilt dabei das Prinzip, dass die erste Regel, die greift, zum Zuge kommt (First match wins). Das ist bei den Performance-Anforderungen auch gar nicht anders zu machen. Der Kernel kann in vertretbarer Zeit nicht für jedes Paket ein riesiges Regelwerk von Anfang bis Ende durchlaufen.
IPtables haftet nicht der Ruf an, besonders benutzerfreundlich und gut bedienbar zu sein. Das Ausmaß der Katastrophe erschließt sich demjenigen schnell, der auf einem Linux-System »iptables-save« eingibt: Dann bekommt er alle im Kernel aktuell hinterlegten Regeln auf der Konsole ausgegeben. Nicht selten geht die Zahl der komplexen Regeln mit vielen Parametern in die Tausende, und so wundert es nicht, dass viele Admins ihre Firewallregeln nicht über »iptables« selbst verwalten, sondern dafür grafische Werkzeuge wie »ufw« (Abbildung 1) oder den Firewall-Manager von Yast 2 (Abbildung 2) nutzen.

Abbildung 1: Um das Problem zu umschiffen, dass IPtables so benutzerfreundlich ist wie ein rostiger Nagel, setzen die Distributionen auf GUIs wie UFW oder …

Abbildung 2: … das Firewall-Modul von Yast. Ihr geliebtes IPtables-Regelwerk zugunsten von NFtables aufgeben wollen viele Admins dann aber doch nicht.
Auch an der Art und Weise, wie IPtables Regeln im Kernel hinterlegt, lässt sich übrigens ablesen, dass die Lösung nicht unbedingt die effizienteste ist: Verändert der Admin im laufenden Betrieb eine Regel oder fügt eine neue hinzu, kann IPtables nicht einfach die Änderung in Netfilter übernehmen. Stattdessen lädt es zunächst das gesamte aktuelle Regelwerk aus dem Kernel einmal herunter, nimmt die Veränderung vor und spielt alle Regeln dann neu ein. Und das kann je nach Menge der Regeln durchaus eine Weile dauern.
Dabei hat hier bereits Optimierung ihren Weg in den Kernel gefunden: Am Anfang der IPtables-Entwicklung waren die Regeln im Kernel gewissermaßen im Klartext abgelegt. Mittlerweile stehen sie in IP-Sets, also in Hashtabellen, die der Kernel beim Prüfen immerhin deutlich schneller verarbeiten kann. Mit den Traffic-Mengen moderner Systeme nimmt Netfilter es trotzdem nur schwer auf.
Was ist eigentlich mit NFtables?
Aufmerksame Linux-Magazin-Leser werden sich daran erinnern, dass IPtables im Grunde bereits einen Nachfolger hatte, nämlich NFtables. Der Autor dieses Artikels beschäftigte sich im Linux-Magazin seinerzeit ausgiebig damit [3] – das war Anfang 2014. Seither hat sich NFtables allerdings in eher enttäuschender Art und Weise entwickelt.
NFtables führte damals eine Art virtuelle Maschine im Kernel ein, die sich um die Überprüfung des Traffic kümmert. Jene VM ist also der eigentliche Filter auf Basis der vom Admin festgelegten Regeln, und jene Regeln nutzen bei NFtables ein anderes Format als bei IPtables. Das hat bei vielen Admins aber den Widerstand signifikant erhöht, sich mit NFtables überhaupt zu beschäftigen. Wer sich mühsam ein kompliziertes Regelwerk für IPtables gebaut hat, wird das nicht einfach verwerfen und mit einem anderen Werkzeug von vorne beginnen wollen. Eine Kompatibilitätsschicht für IPtables hatte NFtables aber lange Zeit nicht; ebenso wenig gab es funktionale GUIs, die NFtables-Regeln generieren konnten.
Das Ganze entwickelte sich in gewisser Weise zum Treppenwitz: Die Werkzeuge, die anfangs eigentlich die Unbedienbarkeit von IPtables hätten ausgleichen sollen, sorgen nun dafür, dass sich der deutlich potentere Nachfolger nur im Schneckentempo verbreitet. Immerhin: Mittlerweile kann NFtables IPtables-Regeln interpretieren und adäquat umsetzen. Ein Hindernis ist also aus dem Weg – doch im selben Moment erwächst NFtables Konkurrenz aus unerwarteter Richtung – willkommen bei BPF und Bpfilter.
Neid mit Tradition
Seit jeher werfen Linux-Admins den einen oder anderen neidischen Blick jenen Kollegen zu, die sich mit BSD und den dort verfügbaren Paketfiltern beschäftigen. In Free BSD war das lange das recht bekannte IPfilter, in Open BSD steht PF zur Verfügung und Net BSD hat NPF. Aber anders als unter Linux ist insbesondere das Festlegen von Regeln bei den verschiedenen PF-Implementierungen in BSD deutlich komfortabler. Meist genügt eine einzelne Datei namens »pf.conf«, in der alle zentralen Parameter vom Admin festzulegen sind.
Fast allen BSD-Varianten ist zudem gemein, dass sie den BPF unterstützen. Dessen Konzept ist keineswegs neu: Ursprünglich entstand die Idee bereits im Jahre 1992 in Berkeley, und obgleich die Technik “Berkeley Paket Filter” heißt, ist Paketfilter eigentlich eine irreführende Bezeichnung. Denn BPF ist zunächst gar kein typischer Paketfilter. Mit IPtables etwa hat die Lösung sehr wenig gemein. Das Produkt ähnelt eher NFtables und ist zunächst eine virtuelle Maschine im Linux-Kernel, die Code in Maschinensprache interpretiert und ausführt.
Die von BPF dabei genutzte Maschinensprache wurde speziell für das Tool entwickelt. Der Begriff virtuelle Maschine erinnert zwar an KVM & Co., doch das ist im BPF-Kontext nur bedingt gemeint. Tatsächlich bildet BPF im Kernel nach der klassischen Definition eine virtuelle Maschine, die jedoch kein gängiges Betriebssystem enthält, sondern ein spezielles Betriebssystem, das im Kernel eine Art Sandbox für verschiedene Aufgaben bereitstellt. Der dafür nötige Code existiert übrigens bereits seit Jahren im Kernel – blieb aber lange Zeit im Dunkel.
Ursprünglich nur ein Helferlein
Am Anfang seiner Entwicklung war BPF lediglich als kleines Helferlein für Werkzeuge wie »tcpdump« gedacht. Die haben traditionell ein Problem: Will »tcpdump« etwa bestimmte Traffic-Pakete auf einem System filtern, schaltet es dazu die Netzwerkkarte üblicherweise in den Promiscious-Modus und müsste im dann folgenden Schritt alle eingehenden Pakete im Hinblick auf die vom Admin bestimmten Kriterien hin untersuchen.
Das kann nicht sonderlich effizient sein, auf Linux-Systemen steht »tcpdump« daher seit Linux 2.5 der Berkeley Paket Filter im Kernel zur Seite. BPF wurde für genau diesen Zweck erfunden: Er heftet sich an geöffnete Netzwerksockets im OSI-Layer 2 an und kann von Programmen wie »tcpdump« Codeschnipsel in BPF-Maschinensprache erhalten, um bestimmte Pakete zu suchen.
Wichtig ist das Verständnis, dass es tatsächlich um den OSI-Layer 2 geht: BPF ist im Kernel an einer Stelle eingebaut, an der er die Pakete sieht, noch bevor das jeweilige Programm sie zu Gesicht bekommt, zu dem der Socket gehört. Nur so kann BPF im Kernel etwa für »tcpdump« seine Arbeit verrichten und entsprechend vorsortieren.
Lange Zeit war Ruhe
Weil BPF eher eine Art virtuelle Maschine denn eine ganz konkrete Umsetzung eines bestimmten Regelwerks ist, passt er perfekt zum weiter oben beschriebenen Framework-Ansatz. Nach der Einführung von BPF wurde es aber eine ganze Weile lang ziemlich still um das Tool: Für jene Aufgabe, für die es von den Entwicklern ursprünglich konzipiert worden war, kam es zwar zur Anwendung. Doch obgleich das Werkzeug “Paketfilter” sogar im Namen trägt, dachte in der Riege der Kernel-Maintainer kaum jemand daran, dass BPF dereinst eine Alternative zu Netfilter sein könnte.
Das änderte sich im Jahre 2011, nachdem ein Patch von Eric Dumazet den Weg in den Kernel gefunden hatte. Dumazets Patch hatte Sprengkraft: Es erweiterte den Kernel um einen Just-in-Time-Compiler und sorgte damit dafür, dass BPF seinen Programmcode auf unterstützten Architekturen unmittelbar in den dortigen nativen Assembler-Code übersetzen konnte. Das brachte gerade mit Blick auf die erreichbare Performance massive Vorteile gegenüber BPF ohne Just-in-Time-Kompilierung und holte BPF zurück ins Bewusstsein der Entwickler.
Zumal sich hier wie im Vorübergehen so etwas wie eine kleine Revolution ihren Weg bahnte: Programme, die der Kernel per JIT-Compiler zur Laufzeit übersetzt, laufen hinterher im User- statt im Kernelspace. Das Schema bietet also für den Betriebssystemkernel eine bequeme Variante, Aufgaben in den Userspace und damit aus seiner Ressourcen-Domäne auszulagern.
Ob man das gut findet oder nicht, hängt auch von der eigenen Religion ab: De facto ist JIT in BPF nichts anderes als das Einführen einer Microkernel-Architektur durch die Hintertür – Tanenbaum lässt grüßen. Microkernel wie Hurd agieren letztlich genau so, um den Kernelspace so sauber wie möglich zu halten.
Viele prominente Befürworter
Seither haben diverse Unternehmen die schnelle BPF-VM im Kernel für diverse Funktionen auf der Netzwerkebene aufgebohrt. Oft ersetzt BGP dabei die etwas altbackenen Standardkomponenten wie Bridges, wie man sie etwa beim Thema Virtualisierung findet.
Cilium etwa nutzt BPF-Programme, um direkt auf der L2-Ebene die virtuellen Netzwerkschnittstellen für Container zu erstellen, und stellt dabei nebenbei unter Beweis, dass BPF im Gegensatz zu klassischen Ansätzen noch weitere Vorteile hat: Unterstützt die eingesetzte Netzwerkkarte per Netzwerkchip XDP-Offloading, lässt sich das BPF-Programm komplett auf der Netzwerkkarte ausführen und fällt nicht der Haupt-CPU des Systems zur Last (Abbildung 3).

Abbildung 3: Bpfilter kann theoretisch sehr viel mehr Pakete verarbeiten als IPtables – wenn es denn mal in die Gänge kommt.
Auch andere Branchenriesen wie Facebook oder Google beschäftigen sich heute intensiv mit BPF unter Linux. Facebook etwa hat eine Möglichkeit entwickelt, per BPF Load Balancing nach Round-Robin-Manier durchzuführen, ohne dabei auf das merklich in die Jahre gekommene IPVS zu setzen. Bei Netflix nutzt man BPF radikal, um schwächelnde Netzwerkpfade per Trace zu erkennen (Abbildung 4).

Abbildung 4: Netflix nutzt den BPF im Kernel, um detailliertes und genaues Tracing von Netzwerkaktionen im Kernel zu ermöglichen.
Google arbeitet am »bpfd«, der das Tracing von entfernten Zielen auf Linux zuverlässiger und verlässlicher machen soll, als simple Tools wie »traceroute« das heute zu tun vermögen.
Bei Cloudflare setzt man auf selbst gebaute Filter-Apps für BPF, um DDoS-Angriffen entgegenzuwirken. Und selbst bei der SDN-Lösung, die den Ruf als Klassenprimus genießt – Open Vswitch –, arbeitet man daran, einen auf BPF basierten Datenpfad zu ermöglichen, der die zumeist etwas holprigen Bridge-Konstrukte ersetzen könnte. Schnell wird klar: BPF ist beliebt.
Nicht zuletzt deshalb haben die Kernelentwickler BPF in den vergangenen Jahren auch kontinuierlich ausgebaut. In Form von Extended BPF steht nun eine BPF-Variante zur Verfügung, die zwar nicht mehr vollständig der originalen Spezifikation entspricht, aber deutlich mehr Funktionalität in Linux bietet (Abbildung 5). Weil sich die BPF-Implementierung von Linux ohnehin sukzessive von der Originalvorlage entfernt hat, ist das aber kein Beinbruch. Und EBPF nutzen die oben genannten Unternehmen exzessiv für ihre Projekte.

Abbildung 5: Der Linux-Kernel verfügt mittlerweile über einen Extended BPF, der JIT-Kompilation und diverse andere Features bietet.
Nur die naheliegendste Funktionalität haben die Linux-Entwickler erst vor ein paar Wochen umgesetzt: BPF als Firewall, als potenzieller Ersatz für Netfilter.
Kinderschuhe
Vorweg: Das von Daniel Borkmann im Februar 2018 vorgestellte und seither kontinuierlich weiterentwickelte Patch liefert noch keinen vollständigen Ersatz für Netfilter – auch wenn es mit dem Namen Bpfilter entsprechende Ambitionen unterstreicht. Zunächst ging es Borkmann sowie Alexei Starovoitov allerdings darum, ein Proof of Concept zu schaffen. Ihr Mantra: Weil BPF im Kernel quasi beliebigen Code ausführen darf, kann es auch echte Filterfunktionen ausführen und damit als vollwertiger Ersatz für IPtables dienen.
Offensichtlich haben Borkmann und Starovoitov gut hingeschaut, was bei der Einführung von NFtables schiefgelaufen ist – für ihren Schützling versprechen sie jedenfalls von Anfang an volle Kompatibilität mit IPtables. Hinterlegt der Admin im Kernel mit Hilfe von IPtables Firewallregeln, sollen BPF-Miniprogramme sich automatisch um deren Umsetzung durch Bpfilter kümmern. Das Ganze soll aus Sicht des Administrators transparent sein – im Hintergrund wird jedoch später einmal die potente Bpfilter-Implementierung anstelle der langsameren Netfilter-Variante tätig.
Daran, dass das so ohne Weiteres möglich ist, hat mancher alte Haudegen aus der Riege der Kernelentwickler allerdings seine Zweifel. Harald Welte, der gerade auch im deutschsprachigen Raum viel Ansehen genießt, warf etwa ein, dass durch die verschiedenen Funktionserweiterungen in den vergangenen Jahren IPtables-Regelwerke heute sehr komplex sein können. Die Gefahr, bei der Reimplementierung in Bpfilter etwas zu übersehen, sei entsprechend groß. Nicht hundertprozentig übereinstimmende Funktionen in Bpfilter einer- und Netfilter andererseits würden jedoch langfristig mehr Probleme schaffen, als sie lösen.
Viel getan, noch viel mehr bleibt zu tun
Dass BPF in Linux nun endlich auch für die Aufgabe zum Einsatz kommen soll, für die er dereinst erfunden wurde, ist für Linux-Admins eine gute Nachricht. Noch ist Bpfilter allerdings kaum mehr als ein Proof of Concept, das in den vergangenen Monaten eine ganze Reihe von Feedback-Schleifen auf der Kernel-Mailingliste gedreht hat.
Man darf davon ausgehen, dass die Admins sich auf Bpfilter wie auf geschnitten Brot stürzen werden, wenn es tatsächlich den Einzug in den Kernel schafft. Denn im Gegensatz zum angestaubten Netfilter stößt Bpfilter auf Basis seiner modernen Architektur erst viel später auf Performance-Probleme.
Die eigentliche Revolution ist ohnehin viel weniger Bpfilter, denn es nutzt lediglich eine schon im Kernel vorhandene Funktion. Revolutionär ist, dass Bpfilter fast unbemerkt die Möglichkeit geschaffen hat, aus dem Kernel heraus Microservices zu betreiben – die Just-in-Time-Kompilation macht es in Verbindung mit der BPF-VM möglich.
Genau diese Funktionalität ist es auch, die BPF in Linux zunehmend stärker aus dem Netzwerkkontext löst und zu einer Art perfekter generischer VM macht, eben für solche Dienste wie Cilium oder »bpfd«. BPF unter Linux wird deshalb in Zukunft ganz zweifellos noch von sich hören lassen.
Infos
-
Netfilter: https://www.netfilter.org
-
BPF comes to firewalls: https://lwn.net/Articles/747551
-
NFtables im Linux-Magazin: https://www.linux-magazin.de/ausgaben/2014/01/nftables







