You can make a difference in the Apple Support Community!

When you sign up with your Apple Account, you can provide valuable feedback to other community members by upvoting helpful replies and User Tips.

Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Pfctl launch daemon does not seem to process program arguments

I have been trying to make a change (for port forwarding/redirecting) to the pfctl.conf file and have it loaded from the /etc/pfctl.conf file at startup. The pfctl.conf has been been confirmed to be working as expected because issuing sudo pfctl -ef /etc/pfctl.conf leads to the desired behavior (requests to one port get forwarded to the other).


That pfctl itself is actually loaded at startup is also confirmed because doing launchctl list | grep pf shows com.apple.pfctl in the output. However, the desired forwarding behavior is not achieved directly after startup. It happens only on doing pfctl -f /etc/pfctl.conf after startup. Oddly enough, the output of pfctl -ef /etc/pfctl.conf after startup still says pf already enabled.


Therefore, I concluded that while pfctl is loaded at startup, the daemon seems to not load from the conf file. The body of the launch daemon com.apple.pfctl.plist now looks like:


    <plist version="1.0">
    <dict>
         <key>Disabled</key>
         <false/>
         <key>Label</key>
         <string>com.apple.pfctl</string>
         <key>WorkingDirectory</key>
         <string>/var/run</string>
         <key>Program</key>
         <string>/sbin/pfctl</string>
         <key>ProgramArguments</key>
         <array>
             <string>/sbin/pfctl</string>
             <string>-e</string>
             <string>-f</string>
             <string>/etc/pf.conf</string>
         </array>
         <key>RunAtLoad</key>
         <true/>
    </dict>
    </plist>


Having checked this discussion at Apple.stackexchange was informative but not practically helpful in this instance - I have already tried editing the ProgramArguments array of the plist file to include the full path to the pfctl executable (as can be seen in the code above - first line of the arguments array) but to no avail. I have also added an argument (second line of arguments array) to actually launch pfctl based on the discussion at this gist. I have tried editing the plist file in different ways: removing the Program tag and its string because the ProgramArguments tag already existed, and according to the developer docs, one need not be specified if the other is present.


So now I am completely at a loss. Any help would be most appreciated!


Additional info:

Not sure this is relevant, but just in case it is: the anchor file which is referenced by pf.conf looks like:

rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port =80 -> 127.0.0.1 port 8888


So is there a possibility that the network interface is not yet active and addresses have not been assigned at the time the daemon runs? If so, how can it be fixed?

MacBook Pro, OS X El Capitan (10.11.5)

Posted on Jul 3, 2016 3:19 AM

Reply
Question marked as Top-ranking reply

Posted on Jan 5, 2017 5:06 AM

And just to make things interesting, things have changed ever so slightly on macOS Sierra, in 10.12.2

I've put together a pretty comprehensive HowTo here.

I have no doubt that it has holes in it, pf is very very complex in places. However - it is working on my Mac Mini, and along with postfix. dovecot, spamassassin, amavis, ssl and who knows what else, it's working pretty well. This is after having it all wiped out completly when I updated to macOS Sierra from the previous version what ever that was. I NEVER do clean installs thank you very much.:-)


Things to watch out for. Some Old, and New FreeBSD, and OpenBSD pf commands do not work on Mac. Always try them first if unsure.

9 replies
Question marked as Top-ranking reply

Jan 5, 2017 5:06 AM in response to aruhn

And just to make things interesting, things have changed ever so slightly on macOS Sierra, in 10.12.2

I've put together a pretty comprehensive HowTo here.

I have no doubt that it has holes in it, pf is very very complex in places. However - it is working on my Mac Mini, and along with postfix. dovecot, spamassassin, amavis, ssl and who knows what else, it's working pretty well. This is after having it all wiped out completly when I updated to macOS Sierra from the previous version what ever that was. I NEVER do clean installs thank you very much.:-)


Things to watch out for. Some Old, and New FreeBSD, and OpenBSD pf commands do not work on Mac. Always try them first if unsure.

Jul 3, 2016 6:26 AM in response to aruhn

If you want to load additional anchors, you have to modify the pf.conf file according to the syntax in the comments it contains. That is not a job for beginners. If you really have a use for the packet filter, I suggest you look for a third-party graphical interface. I don't have a specific recommendation, but I know there is at least one, named "IceFloor."

Jul 3, 2016 11:36 AM in response to aruhn

Hello aruhn,

I think you are going about this all wrong. This is a bit tricky, so here are some important plot points:


1) Don't mess with Apple's stuff. That launchd config file should be protected by SIP (System Integrity Protection), AKA "rootless", so you shouldn't be able to edit it at all. Did you turn SIP off? If so, turn it back on. You don't need to turn it off.

2) Don't mess with Apple's stuff. pfctl is a special case. Normally, if you wanted to override the way Apple was running some system utility, you would use "sudo launchtl unload -w" to turn off the system version. Then copy the launchctl plist file to /Library/Launch(Agents|Daemons), rename it, change the label to one of your own, and load it from there.

3) pfctl is a special case. You should leave the system version running. Go ahead and copy the system launchctl plist file from /System/Library/LaunchDaemons/com.apple.pfctl.plist to /Library/LaunchDaemons and give it a meaningful name. I named mine "com.etresoft.pfctl.plist". Change the label too. Again, I used "com.etresoft.pfctl.plist". Now when I type "sudo launchctl list | grep pfctl" I can see exactly what is going on. And again, this is because pfctl is a special case. See point 2) for most other things.

4) There are some additional tricky bits to running pfctl from launchd. This thread was very helpful (where to put pfctl rules to make them persistent). It points to this gist which explains about a potential stderr issue (https://gist.github.com/lowescott/5581726). I'm not sure if this is really necessary or not. Add this logic and get it working, then try to remove it. I'm just to lazy to do that and restart again because I've already got half this response typed out . Finally, I'm not really a pfctl expert. This page was very helpful for debugging techniques (https://salferrarello.com/mac-pfctl-port-forwarding/). Update: curiosity got the better of me. Ignore that gist and read below.

5) There is some discrepancy between the files you are referencing. /etc/pf.conf is the system file, not /etc/pfctl.conf.

6) Regardless, you don't want to modify /etc/pf.conf. Important plot point: never modify Apple's system files in /etc is there is any way around it. If you absolutely must modify one, use the "ditto" command to make a backup and try real hard to restore the original (in content and date) once you have it figured out. Otherwise, if Apple issues a software update and changes one of these files, say for a security issue, you may be left with your old, modified version forever.

7) You also seem to be talking about loading that anchor file the same way Apple is doing it. These config files support complex structures for complex situations. This is a simple situation. Just add your rules to a file in /etc or /etc/pf.anchors and reference the file directly.

8) Regarding point 4) above. The author of that gist was wrong about the stderr issue. This is a complicated topic and it doesn't surprise me that someone might misunderstand something, get it wrong, and think something like this is required. In fact, even Apple might be getting this wrong. The stderr issue is a convenient side effect that seems to be preventing an infinite loop. I'll explain this interesting part at the end.

9) If you've read all of these points and still haven't lost interest entirely, congratulations! I'll reward you with a working launchd config file. Save this file to /Library/LaunchDaemons and give it a name and label that is meaningful to you:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE plist PUBLIC "-//Apple Computer/DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>Label</key>

<string>com.etresoft.pfctl.plist</string>

<key>Program</key>

<string>/sbin/pfctl</string>

<key>ProgramArguments</key>

<array>

<string>/sbin/pfctl</string>

<string>-e</string>

<string>-f</string>

<string>/etc/pf.anchors/com.etresoft</string>

</array>

<key>RunAtLoad</key>

<true/>

<key>LaunchOnlyOnce</key>

<true/>

</dict>

</plist>

and here is my /etc/pf.anchors/com.etresoft file:

rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 8888 -> 127.0.0.1 port 80

rdr pass on lo0 inet6 proto tcp from any to fe80::1%lo0 port 8888 -> fe80::1%lo0 port 80

In my case, I'm redirecting 8888 to port 80 just to test. Note that I included IPv6. That part was tricky. I'm not an ethernet expert either. ::1 caused strange localhost issues. This versions works after a restart.


That bit about the stderr is interesting. If you investigate launchctl list, you will see that Apple's task exits with a status code 1. launchctl considers anything not 0 to be failure. At that point, it gets complicated about whether or not to restart. In my launchd file, I explicitly added the LaunchOnlyOnce key. Now I don't need to bother to study the details about how launchd might or might now respawn failed jobs. I've set the script to be run only once regardless. Because pfctl is special, this is all I need.


Technically speaking, adding those stderr and stdout redirects are correct. That would prevent pfctl from exiting with 1. But, pfctl still works regardless. That is how it launches to begin with. Maybe I will file a bug report about this. I don't know. I kind of like seeing the output from launchctl list. When I had my script configured to map stderr and return 0, after it runs once and exits, it no longer shows up in launchctl list. That's very curious for other reasons.


So, to recap. Undo whatever you have done to hack up your system. Restore these config files to their default values. Ideally, restore them from backup so the dates and times are correct too. Restore your system security. Turn SIP back on. Tturn GateKeeper back on too if you have turned that off like everyone else on the internet seems to have done. Then add your own pfctl anchor file. Add your own launchd config script, and start redirecting some packets.


PS: And thanks for an interesting question. It made me think. I haven't seen a good one like this in a long time.

Jul 5, 2016 8:45 PM in response to Linc Davis

You're absolutely right. There's no such thing as pfctl.conf even in my own command history, it is indeed pf.conf. I have no idea how/why I wrote that here - most likely some form of delirium induced by trying to hack at the same thing from different angles for almost a full day and with no results. I wasn't even looking at my terminal when I typed out that post.

Jul 5, 2016 8:52 PM in response to etresoft

Many thanks for the feedback, and the informative post. Quite educative.


I have reversed ALL the changed to my system - ditto'ed them from the backup and got SIP back on, and then used the plist code from you, with the names modified appropriately. Sadly, however, this launchd file does not work. I am not sure if it is idiosyncratic.

Jul 6, 2016 7:18 AM in response to aruhn

Hello again aruhn,

Have you tried just running the command from the Terminal, resetting, and trying again, as instructed by the tutorial (https://salferrarello.com/mac-pfctl-port-forwarding/) I posted above? Did you try manually loading the launchd script with "sudo launchctl load -w" and then unloading it for subsequent attempts? It is still going to take a few tries to get it working.

Pfctl launch daemon does not seem to process program arguments

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.