I've been using nftables for port knocking for a while now. I run an SSH tunnel server that needs to be globally accessible. But I don't want it getting hammered by bots nonstop.
So, I have this nft script which works alongside Firewalld:
$ systemctl enable --now nftables
$ cat /etc/nftables/portknock.nft
table ip portknock {}
delete table ip portknock
table ip portknock {
set knocked {
type ipv4_addr
flags timeout
timeout 6s
gc-interval 2s
}
# Before conntrack: record the knock, then drop the packet.
chain prerouting_knock {
type filter hook prerouting priority raw; policy accept;
tcp dport 12334 fib daddr type local tcp flags syn counter add @knocked { ip saddr } drop
}
# Decision chain for port 41444. Every branch is counted so that
# `nft -a list table ip portknock` shows which path traffic took.
chain gate_41444 {
# Established/related sessions pass unconditionally.
ct state established,related accept
# Host-local. Rarely matches: host-originated traffic is DNATed in
# the output hook before it reaches prerouting. Kept as a safeguard.
iifname "lo" counter accept
# Podman containers reaching the published port (hairpin).
ip saddr 10.88.0.0/16 counter accept
# Trusted subnets.
ip saddr { 10.0.0.0/24, 10.1.0.0/24 } counter accept
# Knocked within the last 6 seconds.
ip saddr @knocked counter accept
# Default deny. If THIS counter is 0 and the accept counters are
# also 0, the chain is not being reached at all -- investigate.
# Do not assume the gate is working just because nothing got in.
counter drop
}
chain prerouting_gate {
type filter hook prerouting priority mangle; policy accept;
tcp dport 41444 fib daddr type local jump gate_41444
}
}
Then on the client side, I can use anything to send the knock, but usually I just script it out with `ssh` like this: $ ssh -p 12334 -o ConnectTimeout=1 "${sServer}" &> /dev/null
$ sleep .5
$ ssh -o 'ExitOnForwardFailure=yes' -o 'StrictHostKeyChecking=no' -o 'LogLevel=ERROR' -fp 41444 -R "${iPort}:localhost:22" -T "${sServer}" "sleep 14d"
The biggest benefit is that it doesn't require any non-standard tooling. If you have an SSH client and know the rules, you can connect.Yeah, it doesn't have all the "cryptographic signatures" of the article; at the same time, it doesn't have some "random" 3rd-party application that faces the internet and directly controls firewall rules that way.
It's still an OpenSSH server with key-auth only. I'm not worried about someone carefully watching my traffic and finding it. I just need Internet bots not connecting to it a million times a second.