Today's the first day that my new laptop, which runs OS X 10.7 (Lion), will sit on an untrusted network so I figured it was time to port my firewall rules across from the old one, that ran OS X 10.6 (Snow Leopard).
I cut my UNIX teeth at a cryptoanarchist shop whose culture of paranoia makes me wary of Apple's own firewall with its emphasis on letting all the hot shinyness Just Work rather than being overly fussy about inbound connections. Furthermore, with IPv6 tunnels like aiccu, you aren't behind the warm fuzzy comfort of NAT, you're just there on the net with all the fun that entails. So, worth having some extra protection I reckon.
10.6 (and earlier) came with ipfw, a packet filter that's knocked around the BSD world for some time. It works but isn't overly featuresome (for example, it doesn't support NAT in-kernel, so you monkey about passing packets to an external daemon). But it was Good Enough for an end system so I supplemented the system's "Application Firewall" with an additional ipfw ruleset to give an approximation of safety when out and about, and way more permissive when on networks I trust.
On 10.6 I used WaterRoof to sort-of manage the ipfw rules: in that I only really used its launchd loader and would hack on the rules by hand. In the spirit of decrufting I figured I'd sort that myself and went to remind myself how to load ipfw rules enmasse. I noticed at the top of man page:
NAME
ipfw -- IP firewall and traffic shaper control program (DEPRECATED)
...
DESCRIPTION
Note that use of this utility is DEPRECATED. Please use pfctl(8) instead
Deprecated? Use pfctl instead? Good news everyone - OS X 10.7 now comes with pf, another BSD packet filter that I've chosen of ipfw on BSD hosts for years off the back of its featureset (native NAT, state syncing between failover firewall pairs, traffic queing...).
Anyway, the point of this post is to point out a few things I noticed which are intriguing. Firstly, pf is not enabled by default. Further, Apple have added some moving parts around how it is enabled. From /etc/pf.conf:
# This file contains the main ruleset, which gets automatically loaded
# at startup. PF will not be automatically enabled, however. Instead,
# each component which utilizes PF is responsible for enabling and disabling
# PF via -E and -X as documented in pfctl(8). That will ensure that PF
# is disabled only when the last enable reference is released.
These two flags, -E and -X, are absent from pf on BSD. Here's how they're documented on OS X:
-E Enable the packet filter and increment the pf enable reference count.
-X token
Release the pf enable reference represented by the token passed.
This suggests that different system components might choose to enable and disable pf, and this is the mechanism to coordinate that. There's a clue about which components in /etc/pf.anchors/com.apple, which is loaded by the main /etc/pf.conf. It defines additional rule anchors:
anchor "100.InternetSharing/*"
anchor "200.AirDrop/*"
anchor "250.ApplicationFirewall/*"
Interestingly, this host's ApplicationFirewall has a bunch of entries in when viewed in the Preferences GUI, yet the pf anchor of the same name is empty (and pf was disabled when I started out):
$ sudo pfctl -a com.apple/250.ApplicationFirewall -s rules
Password:
No ALTQ support in kernel
ALTQ related functions disabled
so I'm unsure what the status of this mechanism is. I've not had occasion to use AirDrop or connection sharing, but would be curious to see if either use these anchors and enable pf temporarily.
Finally, what's the token that's passed to -X? You can ask pfctl for the current tokens:
$ sudo pfctl -s References
No ALTQ support in kernel
ALTQ related functions disabled
TOKENS:
PID Process Name TOKEN TIMESTAMP
17013 pfctl 18446743524308110600 0 days 01:05:50
I enabled pf with pfctl, so that makes sense. When I did so it didn't inform me of the token, but I suppose an enabling process would spelunk the token shortly after enabling pf by merit of its name and PID and pass it back when it's finished with pf.
Now, on with the actual job of ruleset writing and puzzling out the launchd voodoo required to enable it at boot.
Minor whinge: Apple could do with updating /etc/protocols:
# $FreeBSD: src/etc/protocols,v 1.14 2000/09/24 11:20:27 asmodai Exp $
Why whinge? It doesn't know icmp6 is a valid alias for ipv6-icmp. Yep, minor.