I think your best bet is to use the label option on the rules that create the states (See pf.conf(5) for details). Maybe it's even possible to use label on the entire anchor, but I haven't tested it. Then you could use pfctl(8) to kill all states matching the given label:Is there a way to kill states that created by rules from specified anchor on FreeBSD 12.1?
It is also possible to kill states by rule label or state ID. In
this mode the first -k argument is used to specify the type of
the second argument. The following command would kill all states
that have been created from rules carrying the label “foobar”:
# pfctl -k label -k foobar
I guess if PF's ruleset optimization substantially changes your ruleset then maybe you should reconsider your ruleset design.I've tested using of label on the entire anchor, but killing of states doesn't work. As I understood from documentation, PF's optimization doesn't work on rules with labels so I wouldn't like to use labels.
I'm making a wrapper of PF for customers and I'm not responsible for rules that they'll create, so I rely on PF's optimizations.
Speaking of killing states by anchor, it would be useful for other projects, for example fail2ban https://github.com/fail2ban/fail2ban/issues/1924
pfctl -s states -vv
displays (in numeric form) which anchor and rule within that anchor created the state as well as a unique state ID which can also be used to kill specific state entries by using pfctl -k id -k <StateID>
. You would have to know what number is associated to your anchor though, which could prove somewhat problematic as it might change when the ruleset changes.I thought about this way but I couldn't get id of anchor and it didn't look quite fast. It seems that writing my own PF client in C is only solution.pfctl -s states -vv
displays (in numeric form) which anchor and rule within that anchor created the state as well as a unique state ID which can also be used to kill specific state entries by usingpfctl -k id -k <StateID>
. You would have to know what number is associated to your anchor though, which could prove somewhat problematic as it might change when the ruleset changes.
pfctl -a "anchor_name" -F states
should work. If there is a bug I could fix it in my free time, although it might take a time to dive into pfctl I'd say that's a bit of a grey zone. The documentation states:I thought about this way but I couldn't get id of anchor and it didn't look quite fast. It seems that writing my own PF client in C is only solution.
Anyway I'm still want to know howpfctl -a "anchor_name" -F states
should work. If there is a bug I could fix it in my free time, although it might take a time to dive into pfctl
-a anchor
Apply flags -f, -F, and -s only to the rules in the specified
anchor. In addition to the main ruleset, pfctl can load and
manipulate additional rulesets by name, called anchors. The main
ruleset is the default anchor.
pfctl -a anch -s states
should work, but then again it only mentions rules which states are clearly not.I've looked up in man and C headers but haven't tried to implement yet. I think it won't be so difficult.Using the ioctl interface in C code it should not be that hard to determine the numerical ID for a given anchor name, then search the state table for matching entries that were created by rules within that anchor. and finally kill all states previously matched.
PfAnchor1
PfAnchor1/_1
PfAnchor1/_1/PfAnchor3
rules cleared
nat cleared
pfctl: Anchor or Ruleset does not exist.
Yes, I noticed that anchor numbers are just like rule numbers, i.e. an ascending number within the corresponding context/anchor. As long as you dont nest anchors that should not become a problem however. States on the other hand do have a unique ID that can be used to kill exactly that state that is referenced by it. The following sure aint pretty, can probably be done in a more elegant fashion and most definately will not work with nested anchors but otherwise it should do:1. It's impossible to kill states by anchor's id because anchors don't have unique ids. In fact, anchor's id is an ordinal number in the anchor list of parent anchor. So two states with the same anchor id can relate to different anchors.
#! /bin/sh
if [ $# != 1 ]; then
echo "USAGE $0 <anchor-name>"
exit 1
fi
anchornum=$(pfctl -s rules -vv | grep "anchor \"$1\"" | cut -d " " -f 1 | colrm 1 1)
stateids=$(pfctl -s states -vv | grep -A 1 "anchor ${anchornum}," | grep "id: " | cut -d " " -f 5)
for i in $stateids; do
echo "KILLME: $i"
done
The -F all option includes various things (os fingerprints, states, tables, info) that are global, so effectively you cannot do3. pfctl -F all doesn't delete anchors from PF's memory. If do pfctl -a anchor -F all after, it removes anchor from the memory and displays
Code:rules cleared nat cleared pfctl: Anchor or Ruleset does not exist.
pfctl -a anchor -F all
. Use single options instead like pfctl -a anchor -F rules
or pfctl -a anchor -F nat
. Anchors are deleted when they are flushed of all rules (including nat and rdr rules) and no other rule references them anymore. From my experience this can take some time though.I implemented the same in C#! /bin/sh if [ $# != 1 ]; then echo "USAGE $0 <anchor-name>" exit 1 fi anchornum=$(pfctl -s rules -vv | grep "anchor \"$1\"" | cut -d " " -f 1 | colrm 1 1) stateids=$(pfctl -s states -vv | grep -A 1 "anchor ${anchornum}," | grep "id: " | cut -d " " -f 5) for i in $stateids; do echo "KILLME: $i" done
The -F all option includes various things (os fingerprints, states, tables, info) that are global, so effectively you cannot do pfctl -a anchor -F all. Use single options instead like pfctl -a anchor -F rules or pfctl -a anchor -F nat. Anchors are deleted when they are flushed of all rules (including nat and rdr rules) and no other rule references them anymore. From my experience this can take some time though.
So you got it working then? gzI implemented the same in C
I noticed that anchors stay in memory when experimented with my own PF client. My program extracts list of all anchors recursively, in this way I knew about hidden anchors. Pfctl doesn't show anchors that have been flushed of rules but my program does. Actually, it isn't a problem, just my notices.
I didn't, I extract all of states. It seems there isn't such opportunity.did you find a way to extract only a subset of state table entries matching specified criteria
I'm not sure but I think it can work without filling of all fields.DIOCNATLOOK which looks like it needs a complete src/dst addr/port pair
Then maybe I will take a closer look at DIOCNATLOOK again. The structure of the argument and the name containing NAT suggested it was made for something other than what I have in mind. I only need to check whether certain connections are currently active or not, i.e. TCP to destination port 6112 or UDP to destination ports 4379+4380, then output either "OK" or "ERR" to use it as an external squid ACL. Not sure if it's worth implementing this in C though. For now I replaced my shell script with an awk script that seems to work quite well.I didn't, I extract all of states. It seems there isn't such opportunity.
I'm not sure but I think it can work without filling of all fields.
As I understand DIOCNATLOOK shows NAT table, so you can achieve your goals. Or you can use ssl_bumb in squid (full interception or reading sni) and filter by url.The structure of the argument and the name containing NAT suggested it was made for something other than what I have in mind. I only need to check whether certain connections are currently active or not, i.e. TCP to destination port 6112 or UDP to destination ports 4379+4380, then output either "OK" or "ERR" to use it as an external squid ACL.
Those connections are no web connections and therefore do not pass through squid at all. The goal is to block certain web connections in squid when/while any of those connections is active in the firewall's state table.As I understand DIOCNATLOOK shows NAT table, so you can achieve your goals. Or you can use ssl_bumb in squid (full interception or reading sni) and filter by url.