pfctl - howto add an anchor and make it active / load it

Solution 1:

In my understanding of pf your major anchor is missing. You may either use Apple's anchor(s) or a user defined anchor.

A user defined anchor is preferred:

  1. Modify /private/etc/pf.conf:

    Add two lines to pf.conf like this:

    ...
    load anchor "com.apple" from "/etc/pf.anchors/com.apple"
    
    #
    # usr.home anchor point
    #
    anchor "usr.home/*"
    load anchor "usr.home" from "/etc/pf.anchors/usr.home"
    
  2. Create a file usr.home. In the example below I create an anchor SSH blocking SSH access from a local network to some IPs of the host:

    sudo nano /etc/pf.anchors/usr.home
    

    and add

    #
    # usr.home ruleset, referred to by the modified /etc/pf.conf file.
    # See notes in that file regarding the anchor point in the main ruleset.
    #
    
    #
    # SSH anchor point.
    #
    
    anchor "SSH"
    load anchor "SSH" from "/etc/pf.rules/pfssh.rule"
    
  3. Now create a new directory

    sudo mkdir /etc/pf.rules
    

    and the referenced file with:

    sudo nano /etc/pf.rules/pfssh.rule
    

    and the following content:

    block in quick inet proto { tcp, udp } from 10.0.0.0/8 to { 10.128.8.145, 10.129.8.145 } port 22
    
  4. Parse and test your pf.conf and your anchor file to make sure that they are error-free:

    sudo pfctl -vnf /etc/pf.conf
    sudo pfctl -vnf /etc/pf.anchors/usr.home
    
  5. Reload pf:

    sudo pfctl -d
    sudo pfctl -e -f /etc/pf.conf
    

You can add additional anchors to your major usr.home anchor as demontrated in the major com.apple anchor.

You can also add additional dynamic sub-anchors with the following command (here I add a temporary block HTTP rule similar to the SSH rule - check the creation of a transitory sub-anchor: usr.home/HTTP here!):

echo "block drop in quick proto tcp from 10.0.0.0/8 to any port 80" | sudo pfctl -a usr.home/HTTP -f -

The temporary anchor doesn't survive a reboot!

One possible command to remove the temporary rule immediately is:

echo "" | sudo pfctl -a usr.home/HTTP -f -

A handy script to check all loaded anchors and rules is pfdump:

pfdump.sh:

#!/bin/bash

function pfprint() {
  if [ -n "$1" ];then
    sudo pfctl -a "$2" -s"$1" 2>/dev/null
  else
    sudo pfctl -s"$1" 2>/dev/null
  fi
}

function print_all() {

  local p=$(printf "%-40s" $1)
  (
    pfprint r "$1" | sed "s,^,r     ,"
    pfprint n "$1" | sed "s,^,n     ,"
    pfprint A "$1" | sed "s,^,A     ,"
  ) | sed "s,^,$p,"

  for a in `pfprint A "$1"`; do
    print_all "$a"
  done
}

print_all

All files mentioned require an empty new line at the end!