A simple guild to the Mac PF Firewall
Update 2: If you block the UDP 3283 port on your own management ARD system then you will not be able to see the status of machines that are not in allow range of IPs. For example a client machine is on subnet 10.0.2.0/24 and allows ARD connections to it from 10.0.1.0/24. If you are blocking the UDP port on your management machine you will not see the status of the machines on the 10.0.2 subnet. Your management machine needs to allow the udp traffic from your client machines in to it.
UPDATE: With further testing this isn’t working as expected. I’ll leave it up as a starting place and update later when I’ve got it working right.
This is a very simplified explanation of Mac Firewalls and using the PF (packet filter) to allow certain IP address to access specific services on your Mac, like SSH and Apple Remote Desktop.
A Mac has two firewall systems, the Application Firewall (ALF) and the Packet Filter firewall (PF)
ALF can be tuned on in the GUI in System Preferences > Security & Privacy or from the command line. When ALF is on connections to the Mac from outside systems are blocked by default unless an application has told ALF to allow the connection. When you turn on Remote Login this allows incoming connections to SSH, port 22. There is no GUI to limit SSH access to a particular IP range. PF is the tool needed to limit connections to a particular port from an IP range.
PF can manipulate virtually any packet data. Tools like Host files and TCP Wrappers are not effective on modern macOS systems. Using PF to allow connections from a small range of IPs to a few ports on your Mac is about like using a freight company to deliver pizza. It’s fairly complicated but can be done. PF has the ability to turn a system into a router and is a very very powerful tool. It even has the ability to limit access to your system by connecting OS type.
Some guides you will want to review
- Command Line Firewall Management In OS X 10.10
- A Cheat Sheet For Using pf in OS X Lion and Up
- A Beginner’s Guide To Firewalling with pf
- OpenBSD PF – Shortcuts For Creating Rulesets
- PF on Mac OS X
- OS X Fortress
You will likely find other references. Also check out the GUI apps Murus and IceFloor. I find both of these tools to be overly complex for the rather simple firewall tasks I need to do. If you have more complex needs these tools are very useful and they can help you figure out how the firewall system works.
The file structure
/etc/pf.conf – this is the main rule file which can reference other files or you can load it up with all the setting you need.
/etc/pf.anchors/ – files in this directory are referenced from pf.conf. Anchor files appear to follow the naming convention of “com.companyname”.
You can put reference files anywhere in the system that PF has access to read. Your custom lists could be in /Library/Preferences//pf/. This follows Apple conventions for 3rd party additions to the system.
Simple example
This simple example will limit access to SSH and Apple Remote Desktop from a range of IP addresses. This may help you get started. Most examples I’ve found on line assume you are using PF for a server not a desktop system.
The following is the default pf.conf file with the custom additions.
#
# Default PF configuration file.
#
# 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.
#
# Care must be taken to ensure that the main ruleset does not get flushed,
# as the nested anchors rely on the anchor point defined here. In addition,
# to the anchors loaded by this file, some system services would dynamically
# insert anchors into the main ruleset. These anchors will be added only when
# the system service is used and would removed on termination of the service.
#
# See pf.conf(5) for syntax.
#
#
# com.apple anchor point
#
pflog_logfile="/var/log/pflog"
scrub-anchor "com.apple/*"
nat-anchor "com.apple/*"
rdr-anchor "com.apple/*"
dummynet-anchor "com.apple/*"
anchor "com.apple/*"
load anchor "com.apple" from "/etc/pf.anchors/com.apple"
### START Custom Rules ###
ARD_tcp = "{ 3283 5900 5988 }"
ARD_udp = "{ 3283 }"
AllowedIn = "{ 192.168.0.0/24, 192.168.1.0/24 }"
block return in proto tcp from any to any port 22
block return in proto tcp from any to any port \$ARD_tcp
block return in proto udp from any to any port \$ARD_udp
pass in inet proto tcp from <AllowedIn> to any port 22 no state
pass in inet proto tcp from <AllowedIn> to any port \$ARD_tcp no state
pass in inet proto udp from <AllowedIn> to any port \$ARD_udp no state
### END Custom Rules ###