SSH port knocking with OpenBSD 7.9

jandeboevrie1 pts0 comments

SSH port knocking with OpenBSD 7.9

SSH port knocking with OpenBSD 7.9

Port knocking is mostly a bad<br>idea. But people keep wanting to do it, for some false sense of security. If<br>you don't consider it a security control but a way to keep garbage out of your<br>logs, it might be valid. In my case I'm using an old USG Pro<br>4 running OpenBSD as my firewall and I'd<br>prefer to avoid writing stuff to the logs, as I'd prefer the flash not to wear<br>out sooner than needed, definitely not thanks to background radiation on the<br>internet.

Here is a pf.conf fragment using the OpenBSD<br>7.9 source<br>limiter<br>feature:

# Chosen by fair dice roll<br>knock1 = "24601"<br>knock2 = "29202"

# no need for knocking for these hosts<br>table persist {<br>192.0.2.0/24 # replace with whatever you trust

table persist {}<br>table persist {}<br>table persist {}

source limiter "stage1" id 1 entries 1000 \<br>limit 2 rate 10/100 \<br>table above 1

source limiter "stage2" id 2 entries 1000 \<br>limit 2 rate 10/100 \<br>table above 1

source limiter "bad" id 3 entries 10000 \<br>limit 2 rate 10/100 \<br>table above 1

# ssh port knocking<br>anchor to self {<br>pass in quick proto tcp from { } to port {>= 1024, 22}<br>block return-rst in quick proto tcp from<br>block return-rst in quick proto tcp to port 22<br>pass in quick proto tcp to port $knock1 source limiter "stage1" (no-match)<br>pass in quick proto tcp from to port $knock2 source limiter "stage2" (no-match)<br># source limiter needs a "pass" rule, ensure you have rules to block access<br># to ports >= 1024 you need to protect.<br>pass in proto tcp to port >= 1024 source limiter "bad" (no-match)<br>block return-rst proto tcp to port >= 1024

Once this was configured, I had no more ssh brute force attempts in the logs:

$ zgrep 'Jun 2' /var/log/* 2>/dev/null

Ah, peaceful 🧘‍♂️

Using return-rst means that it is harder to observe when the host has been<br>blocked, essentially turning the source limiter into a thing which does not<br>block anything but instead sets state.

Configuring the ssh client

To get into this you need to hit the source limiter twice, for each port. We<br>can use OpenSSH's Match tagged<br>keyword to make this nicer.

Add something like this to the end of ~/.ssh/config:

Match Final Tagged knock Exec "telnet %h 24601; telnet %h 24601; telnet %h 29202; telnet %h 29202; true"

Then use it with ssh -P knock your-host. You should see 4 connection refused<br>lines from telnet, then your SSH connection.

Alternatively rather than using -P knock, you can use the LocalNetwork<br>match to make this happen automatically depending which network you are on.

Match Final LocalNetwork !10.x.y.0/24 Host *.domain Exec "telnet %h 24601; telnet %h 24601; telnet %h 29202; telnet %h 29202; true"

(Unfortunately because of the ssh config parser that has to be on one line.)

The limits are arranged so a host is more likely to get blocked than<br>accidentally find the ports, even via scanning. However this shouldn't be<br>treated as a security control, it's mostly a way to stop clogging the logs with<br>scans, without having to run yet another daemon to do it.

18th June 2026

port source limiter telnet table proto

Related Articles