PF does pf support port trigger?

You can implement a basic form of port knocking with only pf's stateful firewall rules. For example, here's an example giving you both ratelimiting of connections/connection attempts to the ssh port, plus portknocking by contacting port 2000

Code:
# Have already set internet_if and 'me' macros to identify interfaces i'm restricting and
# interfaces I'm running sshd on (or otherwise protecting)
table <bruteforce> persist
table <portknocked>
block quick from <bruteforce>
block quick on $internet_if inet proto tcp from ! <portknocked> to $me port {22}
pass inet proto tcp from any to $me port {22} flags S/SA keep state   (max-src-conn 20, max-src-conn-rate 3/120,  overload <bruteforce> flush global)
pass inet proto tcp from any to $me port {2000} flags S/SA keep state (max-src-conn 1, max-src-conn-rate 1/120,  overload <portknocked>)
essentially this maintains two tables via stateful inspection - 'bruteforce' which contains hosts which exceed 20 simultaneous or 3 new connections in 120 seconds, and 'portknocked' which contains anyone who has had more than 1 simultaneous connection and/or 1 connection per 120 seconds to port 2000. The 'block quick from ! <portknocked>' rule prevents people who *aren't* in portknocked from reaching the ssh port.

Once you have this in place, the only other software you need is something to do the listening on port 2000; this can be as simple as running 'nc -l 2000' or you can use inetd(8) for this, even (the 'discard' service is one approach....) Then from the client device, you can use anything that will open a tcp connection - should work to try an ssh connection to that port a couple of times within a minute, and then you can reach the ssh port on 22; no special software needed.

You can imagine maintaining multiple tables to implement more complex port knocking schemes such as requiring people to visit ports in a certain order or the like; the stateful primitive is pretty powerful. Note the 'flush global'

If you'd like to see what's in the tables, you can do 'pfctl -T show -t portknocked' or 'pfctl -T show -t bruteforce' - and you can flush them with -T flush and the like. pfctl(8) and pf.conf(4) are your friends.
 
Back
Top