According to the documentation, pfctl is supposed to remove all anchors if there are no rules beneath them. This behavior aligns with the specifications up to Big Sur. However, starting from Ventura and onward, pfctl retains anchors even after flushing out all rules, states, tables, etc. I think this is a huge leaking issue. The only way to remove all the zombie anchors are reboot the system.
Repro steps.
Setup.
/etc/pf.confg
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"
anchor "com.foo/*"
load anchor "com.foo" from "/etc/pf.anchors/com.foo"
/etc/pf.anchors/com.foo
anchor "sub_foo" in inet all {
block drop out all
pass out log (user) quick inet from any to any flags any keep state
pass out log (user) quick inet from any to any no state
}
Now here is the repro steps.
1. Load rules pfctl -f /etc/pf.conf
2. Check anchors pfctl -sA
com.apple
com.foo
3. Check subanchors of com.foo
pfctl -a "com.foo" -sA
com.foo/sub_foo
4. Check rules of subanchors sub_foo
pfctl -a "com.foo" -sr
anchor "com.foo/sub_foo" in inet all
5. Remove all rules, and states whatever
pfctl -a "com.foo" -Fa
rules cleared
nat cleared
dummynet cleared
0 tables deleted.
6. Check if the anchors is gone
pfctl -a "com.foo" -sA
com.foo/sub_foo
7. Since #6 anchor didn’t go check and see if the rules underneath it.
pfctl -a "com.foo" -sr
No rules.