Credit where it's due: Keith Stattenfeld confirmed my hunch independently, and Scott Lowe actually had the problem solved, though I didn't realize it until later.
When you use
pfctl
with the
-f
flag, you get an output message warning that using
-f
with a filename other than
/etc/pf.conf
can result in rules and anchors and such getting overwritten (because you're starting it with a file other than the default file). This isn't a problem when using
-f /etc/pf.conf
, but
pfctl
doesn't know that, so it tries to print this "helpful" message before exiting normally with status 0.
This all works fine when you're doing it from the command line. But when you ask
launchd
to do it for you, there is no output set up for
stdout
or
stderr
, and this causes
pfctl
to exit abnormally with status 1, not starting the packet filter.
launchd
unhelpfully reports only that it exited with status 1 and didn't start, and you're left to puzzle out why.
You could probably add a "quiet" flag to
pfctl
to suppress this, but having less information is what got us into this mess in the first place. As noted at the top, Scott Lowe
figured this out for Mountain Lion and it still works. The link goes to a launchd item you can add to do the trick. Notice how it sets up standard out and standard error with log files, so when there are errors, they actually get written somewhere you can read! His login item does
not set the working directory to
/var/run
, but you can add that.
You can just drop this in a new
launchd
plist, and leave the system one as it is. The system one exits because it can't write the message it wants to write, and then your new launchd item will try again and get it right. Alternatively, if Apple fixes the
pfctl
item for
launchd
, it will start correctly and then yours will exit (with proper logging!) because the packet filter is already running. Either way, the answer is "
pfctl
wants to write text, so set up standard output and error channels so it can write text."