Das Firewall-Tool pf in Mac OS X 10.7 Lion
Mac OS X 10.7 kommt mit gleich drei Firewall-Systemen, die alle IPv6-fähig sind: die Anwendungs-Firewall, das Firewall-Utility ip6fw und das neue Tool "pf". Über das sehr mächtige Werkzeug "pf" könnte man ganze Bücher schreiben. Aber die wesentlichen Merkmale lassen sich natürlich kompakt zusammenfassen.
- Carsten Strotmann
Ein Wort zur Vorsicht: Bei unseren Versuchen haben wir festgestellt, das Apples Implementierung auf Mac OS X 10.7.1 die Stabilität des Betriebssystems beeinträchtigen kann. Von Kernel-Abstürzen über "hängende" Anwendungen bis zu "eingefrorenen" Systemen haben wir alles erlebt. Derzeit hat "pf" in Mac OS X den Status "produktionsreif" nicht erreicht.
Die Haupt-Konfigurationsdatei "/etc/pf.conf" wird beim Start des Betriebssystems ausgelesen und die dort definierten Regeln werden in die "pf"-Firewall eingetragen. Diesen Vorgang löst der LaunchDaemon com.apple.pfctl.plist aus, den man in /System/Library/LaunchDaemons/ findet. Allerdings wird damit die "pf"-Firewall nicht aktiviert. Das müssen Anwendungen oder ein eigener LaunchDaemon übernehmen.
Die Firewall lässt sich mit dem Kommandozeilen-Programm pfctl
steuern. Der Befehl pfctl -E
aktiviert die Firewall mit dem aktuell geladenen Regelsatz. pfctl -X <referenztoken>
deaktiviert die Firewall, oder besser gesagt, verringert einen Referenzzähler um eins. Dieser Referenzzähler wird bei jedem Aufruf von pfctl -E
erhöht, und mittels pfctl -X <referenztoken>
verringert. Ist der Referenzzähler bei Null angekommen, wird die Firewall ausgeschaltet. Auf diese Weise können mehrere Anwendungen die Firewall kontrollieren, aber erst wenn die letze ihren Bedarf abmeldet, wird die pf-Firewall auch tatsächlich abgeschaltet. pfctl -X
benötigt ein Referenztoken. Dieses Referenztoken wird beim Einschalten der Firewall mittels pfctl -E
erzeugt und kann mit pfctl -s References
ausgelesen werden.
# sudo pfctl -s References
No ALTQ support in kernel
ALTQ related functions disabled
TOKENS:
PID Process Name TOKEN TIMESTAMP
671 pfctl 18446743524369253512 0 days 00:00:02
# sudo pfctl -X 18446743524369253512
No ALTQ support in kernel
ALTQ related functions disabled
pf disabled
pfctl -s info
gibt den aktuellen Statusbericht zur Firewall, inklusive der Angabe, ob die Firewall aktiviert ist:
# sudo pfctl -s info
No ALTQ support in kernel
ALTQ related functions disabled
Status: Disabled for 0 days 00:02:44 Debug: Urgent
[...]
Beim Logging beschreitet "pf" einen ungewöhnlichen Weg: Die Logausgaben werden an eine virtuelle Netzwerkschnitstelle gesendet. Von dort lassen sich die Daten mit einem beliebigen Programm auslesen, welches das Logging-Paket-Format versteht. Das geht beispielsweise mit tcpdump oder Wireshark.
Um das Logging einzuschalten, definiert man am Anfang der Konfigurationsdatei den Namen der virtuellen Netzwerkschnittstelle:
set loginterface pflog0
Diese Netzwerkschnittstelle erzeugt man per ifconfig
– und zwar nach jedem Neustart. Dann kann man sie mittels tcpdump abfragen:
# sudo ifconfig pflog0 create
# sudo tcpdump tcpdump -n -e -ttt -i pflog0
Die Syntax für die Firewall-Regeln erscheint ähnlich gut lesbar wie die des ip6fw-Utilities. Zum besseren Vergleich haben wir die ip6fw-Regeln, die im Artikel "Vorsorgliches Umtopfen" aufgeführt sind, in das "pf"-Format übersetzt. Das IPv6-Regelwerk wird per "include" in die Hauptdatei eingebunden:
Datei "/etc/pf.conf":
--------
#
set loginterface pflog0
scrub in all fragment reassemble
#
# com.apple anchor point
#
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
include "/etc/pf-ipv6rules.conf"
--------
Datei "/etc/pf-ipv6rules.conf":
--------
#
# Macros
#
lan_if="en0"
wifi_if="en1"
ip6linklocal="fe80::/10"
ip6linklocalmc="ff02::/16"
# no rules on loopback and interface traffic
set skip on lo0
# Duplicate Address detection (DAD)
pass in inet6 proto ipv6-icmp from any to $ip6linklocalmc
# Neighbor discovery solicitation out
pass out on {$lan_if, $wifi_if} inet6 proto ipv6-icmp all icmp6-type {neighbradv, neighbrsol}
# Neighbor discovery advertisement in
pass in on {$lan_if, $wifi_if} inet6 proto ipv6-icmp all icmp6-type {neighbradv, neighbrsol}
# ICMPv6 Pakete aus dem Netzwerk kommend erlauben
pass in on {$lan_if, $wifi_if} inet6 proto ipv6-icmp all icmp6-type {unreach, toobig, timex, paramprob, echoreq, echorep}
# Router solicitation kommend
pass in on {$lan_if, $wifi_if} inet6 proto ipv6-icmp all icmp6-type routersol
# NTP multicast
pass in on {$lan_if, $wifi_if} inet6 proto udp from any to ff02::1010 port 123 keep state
# mDNS (Rendezvous/Bonjour)
pass in on {$lan_if, $wifi_if} inet6 proto udp from any to ff02::fb port 5353 keep state
pass out on {$lan_if, $wifi_if} inet6 proto udp from any to ff02::fb port 5353 keep state
# DHCPv6
pass out on {$lan_if, $wifi_if} inet6 proto udp from any to ff02::1:2 port 547 keep state
pass in on {$lan_if, $wifi_if} inet6 proto udp from any to any port 546 keep state
# ausgehende IPv6 Verbindungen (UDP/TCP)
pass out on {$lan_if, $wifi_if} inet6 proto tcp all keep state
pass out on {$lan_if, $wifi_if} inet6 proto udp all keep state
#
# alles was nicht erlaubt wurde blocken und in das log schreiben
#
block return log on {$lan_if, $wifi_if} inet6 all
--------
(dz)