In computer networking, port knocking is a method of externally opening ports on a firewall by generating a connection attempt on a set of prespecified closed ports. Once a correct sequence of connection attempts is received, the firewall rules are dynamically modified to allow the host which sent the connection attempts to connect over specific port(s).

For example, Using PF on FreeBSD to only open port 22 after X number of attempts to connect on port 1234:

# Table for allowed IPs - gets auto populated via portknocking
table <portknock_ssh> persist

block drop # block policy
# Allow everyone to hit 'any' on port '1234' - pf proxies tcp connection
#  [if not using 'synproxy', the connection is never established to
#    'overload' the rule]
#  5 attempts in 15 seconds
pass in log quick proto tcp from any to any port {1234} synproxy state \
  (max-src-conn-rate 5/15, overload <portknock_ssh>)

#Allow IPs that have been 'overload'ed into the portknock_ssh table
pass in log quick proto tcp from {<portknock_ssh>} to any port {ssh}

# Allow out trafic
pass out all

In case you want to use this on an AWS instance using also VPN (NAT):

table <portknock_ssh> persist

scrub in all
nat on xn0 from !xn0:0 to any -> (xn0)
set skip on {lo0, tun0, ng0}

pass in log quick proto tcp from any to any port {1234} synproxy state \
  (max-src-conn-rate 5/15, overload <portknock_ssh>)
pass in log quick proto tcp from {<portknock_ssh>} to any port {ssh}
block in quick on xn0 proto tcp to port ssh

pass all

An entry in /etc/crontab or a expiretable could be used to expire all IP's in that table that have not been referenced in 60 seconds:

* * * * *       root    /sbin/pfctl -vt portknock_ssh -T expire 60

🔗how to nock

Via terminal:

$ for i in {1..10}
nc -z host.tld 1234
Connection to host.tld port 1234 [tcp/search-agent] succeeded!
Connection to host.tld port 1234 [tcp/search-agent] succeeded!
Connection to host.tld port 1234 [tcp/search-agent] succeeded!
Connection to host.tld port 1234 [tcp/search-agent] succeeded!
Connection to host.tld port 1234 [tcp/search-agent] succeeded!
..

On the server to see the current IP on the portknock_ssh table:

$ pfctl -t portknock_ssh -T show
96.129.22.100
10.0.2.34