Jeder Mac bringt zwei Dinge mit, die Menschen „die Firewall“ nennen. Das eine ist die Programm-Firewall in den Systemeinstellungen, ein Schalter pro App für eingehende Verbindungen. Das andere, leisere ist pf, der BSD-Paketfilter, den macOS aus der FreeBSD/OpenBSD-Linie geerbt hat und den Apple selbst unter der Haube für Internetfreigabe, VPN und NAT nutzt. Power-User und Administratoren können direkt mit pfctl mit ihm sprechen, und viele Anleitungen zeigen einen pf.conf-Schnipsel und lassen es dabei bewenden. Was diese Anleitungen selten erklären, ist, wo pf aufhört, für das nützlich zu sein, was die meisten Menschen eigentlich wollen: zu beobachten und zu kontrollieren, was ihre eigenen Apps hinaussenden. Das hier ist ein Lab, kein Vortrag — wir schalten pf ein, schreiben eine Regel, lesen den Zustand, den es hält, und schauen uns dann genau an, warum dieser Zustand die falsche Form für eine App-Firewall hat.
Was pf tatsächlich ist
pf ist ein Paketfilter auf Kernel-Ebene: Er untersucht Pakete, während sie Netzwerkschnittstellen durchqueren, und entscheidet Regel für Regel, ob sie durchgelassen oder blockiert werden. Er kennt kein Konzept von „Apps“ — er arbeitet rein mit Paket-Headern: Quell- und Zieladresse, Port, Protokoll, Schnittstelle, Richtung. Das ist keine Einschränkung, die jemand zu beheben vergessen hat; es ist das Design. pf wurde gebaut, um Datenverkehr auf der Netzwerkschicht zu filtern, derselben Schicht, auf der Router und Gateways arbeiten, und darin ist er sehr gut.
Man spricht mit ihm über pfctl, das Steuerungswerkzeug. Die Manpage ist unmissverständlich über die Trennung zwischen den zwei Dingen, die es tut: Es lädt Regelwerke aus einer Konfigurationsdatei, und es berichtet über den Zustand, den der Kernel hält. Zwei Optionen zählen am meisten, um den Filter ein- und auszuschalten, in den eigenen Worten der Manpage: -e („Aktiviert den Paketfilter.“) und -d („Deaktiviert den Paketfilter.“). Sonst gibt es an pf nichts, das einzeln an- oder ausgeschaltet werden kann — das gesamte Regelwerk bewegt sich gemeinsam.
Es einschalten und seinen Zustand lesen
Ein kurzes Lab, auf einem Mac, auf dem Sie sich mit sudo wohlfühlen. Prüfen Sie zuerst, ob der Filter bereits aktiviert ist, und sehen Sie sich seine Zähler an:
sudo pfctl -s info
# example output, trimmed — the real thing includes per-rule and per-source-tracking stats with -v
Status: Enabled for 0 days 02:14:07 Debug: err
State Table Total Rate
current entries 42
searches 88213 9.7/s
inserts 611 0.1/s
removals 569 0.1/sListen Sie dann die Regeln auf, die der Kernel derzeit hält. pfctl -s rules tut genau das; die Manpage merkt an, dass es mit -v zusätzlich Auswertungszähler, Pakete und Bytes pro Regel ausgibt:
sudo pfctl -s rules
# example output, trimmed
scrub-anchor "com.apple/*" all fragment reassemble
anchor "com.apple/*" all
block drop in log quick from <blocklist> to anyDiese Zeile com.apple/* ist keine Dekoration. Apple lädt seine eigenen Regeln in benannte Anchors — pfs Begriff für ein in sich geschlossenes Teil-Regelwerk, das ein- und ausgetauscht werden kann, ohne alles andere neu zu laden. Die Option -a von pfctl zielt auf einen bestimmten Anchor, und, laut Manpage, aktiviert die Nutzung mit einem Platzhalter das rekursive Auflisten verschachtelter Anchors — so sehen Sie, was Apple selbst geladen hat, neben allem, was Sie hinzufügen:
sudo pfctl -a '*' -s rules
# example output, trimmed to the anchors that exist on a stock MacEine Testregel schreiben und laden
Eine minimale Anchor-Datei, die eine IP-Adresse ausgehend blockiert, gespeichert als /etc/pf.anchors/test-block:
block drop out quick on en0 proto tcp to 203.0.113.10 port 443Um eine einzelne Anchor-Datei zu laden, liest pfctl -f Regeln aus einer Datei; laut Manpage beschreibt sie die Datei als enthaltend Makros, Tabellen, Optionen und Filterregeln:
sudo pfctl -f /etc/pf.anchors/test-block
sudo pfctl -s rules
block drop out quick on en0 proto tcp from any to 203.0.113.10 port = 443Warum pf nicht Ihre App-Firewall sein kann
Nichts von dem, was folgt, ist ein Fehler. Es ist das, was passiert, wenn man einen Paketfilter auf der Netzwerkschicht auf eine Aufgabe ansetzt, die verlangt zu wissen, welcher Prozess das Paket gesendet hat.
Er hat keine Ahnung, welche App das Paket gesendet hat
pf-Regeln greifen auf IP, Port, Protokoll, Schnittstelle und Richtung. Es gibt kein Feld für „Prozessname“, „Bundle-Identifier“ oder „Code-Signatur“, weil pf auf der Schicht sitzt, auf der Pakete existieren, aber Prozesse nicht. Zwei völlig verschiedene Apps, die TCP-Verbindungen zu derselben IP und demselben Port öffnen, sind für pf nicht zu unterscheiden. Wenn Sie Slack erlauben wollen, einen Host zu erreichen, während Sie jeder anderen App den Zugriff auf denselben Host verwehren, kann pf allein diese Regel nicht ausdrücken.
Eine Regel auf einen Hostnamen ist eine Regel auf die IP, die dieser Hostname beim Laden hatte
pf.conf-Dateien referenzieren zur Lesbarkeit oft einen Hostnamen — block from evil.example.com. Was tatsächlich geladen wird, ist nicht dieser Name; es ist die Adresse, zu der er aufgelöst hat. Die OpenBSD-Manpage zu pf.conf sagt das unumwunden: „Die Auflösung von Hostnamen und die Übersetzung von Schnittstelle zu Adresse erfolgen beim Laden des Regelwerks.“ Es gibt keine DNS-Abfrage zur Laufzeit, während Datenverkehr fließt — die Ersetzung passiert einmal, wenn Sie pfctl -f ausführen, und die Regel trifft weiterhin nur auf diese eine Adresse, bis Sie neu laden. Das ist in Ordnung für einen Server mit statischer IP. Es bricht in dem Moment zusammen, in dem der Name dahinter ein CDN, ein Cloud-Load-Balancer oder irgendein Dienst ist, der über viele Adressen rotiert oder verteilt — was auf die meisten Dienste im Internet von 2026 zutrifft. Eine Regel, die „diesen Dienst“ blockieren soll, verengt sich still auf „welche IP dieses Dienstes auch immer geantwortet hat, als ich die Regel geladen habe“, und Datenverkehr zu jeder anderen Adresse, zu der derselbe Hostname auflöst, geht ungehindert durch.
Keine Abfragen, kein Dialog — nur ein statisches Regelwerk
pf hat kein Interaktionsmodell. Es kann keine Verbindung anhalten und fragen: „Mail möchte zum ersten Mal 51.x.x.x über Port 993 erreichen — zulassen?“ Entweder passt eine Regel, die Sie bereits geschrieben haben, oder es fällt auf den Standard zurück. Jede Entscheidung muss vorab antizipiert und in IP-und-Port-Begriffen niedergeschrieben werden, bevor der Datenverkehr stattfindet. Es gibt kein Äquivalent zu einer Abfrage bei der ersten Verbindung, weil eine Abfrage voraussetzt zu wissen, welche App fragt, und diese Information hat pf von vornherein nicht.
Ihre handgeschriebene Konfiguration übersteht kein Update
Apple behandelt /etc/pf.conf und die davon geladenen Anchors als systemverwaltete Konfiguration, gebunden an macOS-Interna — Internetfreigabe, VPN, die eigenen Anchors der Programm-Firewall hängen alle davon ab. macOS-Updates dürfen diese Datei jederzeit umschreiben oder ersetzen. Haben Sie sie von Hand bearbeitet, um eigene Regeln hinzuzufügen, gibt es keine Garantie, dass diese das nächste Update überleben; man findet es auf die harte Tour heraus, im Nachhinein, dass die eigene Regel still aufgehört hat zu greifen. Eine Konfigurationsdatei, die eine Person von Hand pflegt und die das Betriebssystem regelmäßig überschreibt, ist ein schlechter Ort, um das eine aufzubewahren, worauf es einem ankam — „hat mein Mac diese Adresse wieder kontaktiert“.
Kein Log-Betrachter, keine Historie, keine Karte
pf kann passende Pakete an eine Pseudo-Schnittstelle, pflog0, protokollieren, wenn eine Regel das Schlüsselwort log enthält — oben sichtbar in der Sperrlisten-Regel aus der früheren -s rules-Ausgabe. Aber dieses Protokoll ist ein Paketaufzeichnungs-Stream, lesbar mit tcpdump -i pflog0, keine durchsuchbare Historie. Es gibt keinen eingebauten Betrachter, keine Liste pro App, was wann blockiert wurde, kein Land oder keine Organisation, die an eine Adresse geknüpft ist, nichts, das Sie jemandem zeigen würden, um zu beantworten „was hat dieser Mac letzte Woche versucht zu erreichen“. Sie bekommen rohe Pakete, und den Rest müssen Sie selbst bauen.
Die Schicht, die Apple tatsächlich für diese Aufgabe gebaut hat
Apples eigene Antwort auf „Ich möchte den Datenverkehr meines Mac pro App filtern“ ist nicht pf — es ist das Network-Extension-Framework, genauer seine Content-Filter-Provider. Apples Entwicklerdokumentation beschreibt das Modell direkt: „Ein netzwerkseitiger Inhaltsfilter auf dem Gerät untersucht Netzwerkinhalte des Nutzers, während sie den Netzwerk-Stack durchlaufen, und entscheidet, ob dieser Inhalt blockiert oder zu seinem endgültigen Ziel durchgelassen werden soll“, und ein Filter-Data-Provider — ein NEFilterDataProvider — „empfängt Netzwerkinhalte des Nutzers und untersucht diesen Inhalt, um zu entscheiden, ob er blockiert oder zugelassen wird“. Flows werden als NEFilterFlow-Objekte dargestellt (mit NEFilterBrowserFlow und NEFilterSocketFlow als konkreten Fällen), was das fehlende Puzzleteil ist, das pf nie hatte: ein Flow-Objekt, das eine filternde App untersuchen und auf den Prozess zurückführen kann, der es geöffnet hat, bevor sie über Durchlassen oder Blockieren entscheidet.
Das ist auch, warum die eingebaute Programm-Firewall (der Schalter in den Systemeinstellungen) ein ganz anderes Tier ist als pf, keine Oberfläche dafür. Apples eigener Leitfaden beschreibt sie ausschließlich in eingehenden Begriffen: Sie „kann Ihren Mac vor unerwünschtem Kontakt schützen, der von anderen Computern ausgeht“, und funktioniert, indem sie Sie „Apps und Dienste auswählen und festlegen lässt, ob sie Zugriff durch die Firewall haben dürfen“. Pro App, ja — aber nur für eingehende Verbindungen, und nur über den konkreten Mechanismus, den Apple genau für diese eine Aufgabe gebaut hat. Sie beantwortet eine andere Frage als „was sendet meine App hinaus“.
| Ansatz | Sieht IP/Port | Kennt die App | Kommt mit wechselnden/rotierenden IPs klar | Kann den Nutzer fragen | Richtung |
|---|---|---|---|---|---|
pf (pfctl) | Ja | Nein | Nein — einmal beim Laden aufgelöst | Nein | Beides, je nach Regel |
| Programm-Firewall (Systemeinstellungen) | Nein (Schalter auf App-Ebene) | Ja | Entfällt | Nein | Nur eingehend |
| Network-Extension-Inhaltsfilter | Ja | Ja, über das Flow-Objekt | Ja — pro Live-Flow ausgewertet | Ja, durch die darauf aufgebaute App | Ausgehend und eingehend |
Nichts davon macht pf nutzlos. Wenn Sie einen Mac als leichten Router betreiben, einen bekanntermaßen schlechten Adressbereich auf Kernel-Ebene ablehnen müssen, unabhängig davon, welcher Prozess fragt, oder verstehen wollen, was Apples eigene Internetfreigabe- und VPN-Funktionen unter der Haube tun, ist pf das richtige und einzige Werkzeug für diese Aufgabe, und pfctl -s rules / -s info sind der richtige Weg, es sich anzusehen. Was es nie leisten sollte, ist die Frage zu beantworten, die die meisten Menschen tatsächlich haben: Welche meiner Apps spricht gerade mit wem, und kann ich gefragt werden, bevor eine neue das darf.
Wo FireAI und HisnLabs ins Spiel kommen
pf and the built-in Application Firewall are both worth using — FireAI does not replace either; it fills the specific gap neither one can, by tying outbound decisions to the app’s code signature and asking before an unknown one gets a first connection.
FireAI ist das eigene Produkt von HisnLabs: eine KI-Firewall für den Mac, die direkt auf dem Gerät läuft. Sie zeigt jede Verbindung Ihrer Apps in verständlicher Sprache und lässt Sie entscheiden, was Ihren Mac verlässt — die KI arbeitet lokal, Ihr Datenverkehr wird also nie an uns oder irgendjemand anderen gesendet. Das Sicherheitsforschungsteam von HisnLabs sorgt dafür, dass diese Entscheidungen verlässlich bleiben: Es katalogisiert, welche Domains gewöhnliche Telemetrie und welche ein echter Dienst sind, verfolgt Land und Netzwerk hinter einer Verbindung und trainiert das lokale Modell (die Autopilot-Funktion) mit echten Verkehrsmustern — ohne dass irgendetwas davon Ihren Mac verlässt.
Die technischen Entscheidungen dahinter können Sie nachlesen — oder FireAI 17 Tage lang ausprobieren — unter FireAI, von HisnLabs.
