惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
Last Week in AI
Last Week in AI
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
博客园 - 叶小钗
IT之家
IT之家
Google DeepMind News
Google DeepMind News
D
Docker
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 【当耐特】
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
博客园 - Franky
月光博客
月光博客
宝玉的分享
宝玉的分享
酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

dgl.cx

SSH port knocking with OpenBSD 7.9 Bash a newline: Exploiting SSH via ProxyCommand, again (CVE-2025-61984) Switchable dark mode with 5 lines of JavaScript Images over DNS CVE-2025-48384: Breaking Git with a carriage return and cloning RCE Can your terminal do emojis? How big? Blink and you'll miss it — a URL handler surprise Using HAProxy to protect me from scrapers Déjà vu: Ghostly CVEs in my terminal title Restrict sftp with Linux user namespaces ""?! ANSI Terminal security in 2023 and finding 10 CVEs NAT-Again: IRC NAT helper flaws ip.wtf and showing you your actual HTTP request
SSH port knocking with OpenBSD 7.9
2026-06-18 · via dgl.cx

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

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

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

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

table <stage1-passed> persist {}
table <stage2-passed> persist {}
table <bad-hosts> persist {}

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

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

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

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

Ah, peaceful 🧘‍♂️

Using return-rst means that it is harder to observe when the host has been blocked, essentially turning the source limiter into a thing which does not 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 can use OpenSSH's Match tagged 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 lines from telnet, then your SSH connection.

Alternatively rather than using -P knock, you can use the LocalNetwork 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 accidentally find the ports, even via scanning. However this shouldn't be treated as a security control, it's mostly a way to stop clogging the logs with scans, without having to run yet another daemon to do it.

18th June 2026