logoalt Hacker News

mmh0000today at 5:27 AM0 repliesview on HN

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.