Configuring the OSX firewall to block specific ports in 10.8+ using pf
Apple changed the firewall from ipfw to pf sometime around 10.8. Sometimes, one must block specific ports or perform more advanced firewalling than ApplicationFirewall allows. For example, I sought to block portmap reflection attacks on UDP 111, which cannot be done using ApplicationFirewall or the Security system preference.
I found this discussion of pf on OSX very helpful in building these rules: http://blog.scottlowe.org/2013/05/15/using-pf-on-os-x-mountain-lion/
The steps:
1) Create your own pf.conf file. We create a different pf.conf file rather than modifying the system one because Apple has a habit of overwriting system files in updates.
sudo cp /etc/pf.conf /etc/my.pf.conf sudo nano /etc/my.pf.conf
2) Add these lines to the bottom:
anchor "myrules" load anchor "myrules" from "/etc/pf.anchors/my.rules"
3) Then save and exit. Note that OSX has a tendency to replace " with â which will cause issues. Quotes must be regular quotes and not the fancy OSX ones.
4) Now, create your ruleset. This is a basic set that allows SSH, HTTPD and AFP only. Create this file in /etc/pf.anchors/my.rules
sudo nano /etc/pf.anchors/my.rules
set block-policy drop set fingerprints "/etc/pf.os" set ruleset-optimization basic set skip on lo0 # Scrub incoming packets scrub in all no-df # Antispoof antispoof log quick for { lo0 en0 en2 }
# Block to/from illegal destinations or sources block in log quick from no-route to any
# Block by default block in log
# Block to/from illegal destinations or sources block in log quick from no-route to any
# Block portmap reflection attacks block in quick proto udp from any to port 111
# Allow critical system traffic pass in quick inet proto udp from any port 67 to any port 68
# allow ssh, http, AFP pass in quick inet proto tcp from any to port 22 pass in quick inet proto tcp from any to port 80 pass in quick inet proto tcp from any to port 548
# Allow outgoing traffic pass out inet proto tcp from any to any keep state pass out inet proto udp from any to any keep state
5) Test the ruleset. You should see your rules printed. If there are any syntax errors or etc here, fix them.
sudo pfctl -vnf /etc/my.pf.conf
6) Create a new LaunchDaemon plist file for the firewall to load on boot
sudo nano /Library/LaunchDaemons/my.pf.plist
7) Fill the file with this XML, and note you may have to modify the location of your custom pf config file generated in step 1 if you used something other than /etc/my.pf.conf
<?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>my.pf</string> Â Â Â Â <key>Program</key> Â Â Â Â <string>/sbin/pfctl</string> Â Â Â Â <key>ProgramArguments</key> Â Â Â Â <array> Â Â Â Â Â Â Â Â <string>/sbin/pfctl</string> Â Â Â Â Â Â Â Â <string>-e</string> Â Â Â Â Â Â Â Â <string>-f</string> Â Â Â Â Â Â Â Â <string>/etc/my.pf.conf</string> Â Â Â Â </array> Â Â Â Â <key>RunAtLoad</key> Â Â Â Â <true/> Â Â Â Â <key>ServiceDescription</key> Â Â Â Â <string>FreeBSD Packet Filter (pf) daemon</string> Â Â <key>StandardErrorPath</key> Â Â Â Â <string>/var/log/pf.log</string> Â Â Â Â <key>StandardOutPath</key> Â Â Â Â <string>/var/log/pf.log</string> </dict> </plist>
8) Change ownership of the file to root
sudo chown root /Library/LaunchDaemons/my.pf.plist
9) Fire it up with launchctl!
sudo launchctl load /Library/LaunchDaemons/my.pf.plist
10) And verify itâs loaded:
launchctl list | grep my
All done!















