1

I want to rate limit ssh connections per IP to a server running firewalld.

Suppose my sshd listens on port 2222, and I want to limit ssh connections per IP to 3 per minute. I tried:

sudo firewall-cmd --add-rich-rule \
  'rule port port="2222" protocol="tcp" accept limit value="3/m"'

Then on another machine I ran:

ssh myserver echo hello; \
ssh myserver echo hello; \
ssh myserver echo hello; \
ssh myserver echo hello; \  # should fail, but actually logs in
ssh myserver echo hello     # should fail, but actually logs in
...

It logs in each time. There is no rate limiting.

Where is my mistake?

lonix
  • 896
  • 10
  • 23
  • 1
    Ah about the test in the question anyway: it works 5 times in a row because the default bucket size to the limit match (iptables)/limit statement (nftables) is 5. It would have failed at the 6th. This is also a parameter not available in the rich rules. – A.B May 22 '23 at 12:28

1 Answers1

2

Seems like this is not yet possible using firewalld's "rich rules".

So I'm using regular iptables rules via firewalld's direct feature. (I'm using firewalld's iptables backend because docker doesn't work with nftables, yet.)

sudo firewall-cmd --add-port=2222/tcp   # remember to allow custom ssh port

sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 0 \
  -p tcp --dport 2222 \
  -m state --state NEW \
  -m recent --name ssh --set

sudo firewall-cmd --direct --add-rule ipv4 filter INPUT_direct 1 \
  -p tcp --dport 2222 \
  -m state --state NEW \
  -m recent --name ssh --update --seconds 61 --hitcount 4 --rttl \
  -j REJECT --reject-with tcp-reset

# ...and the same for ipv6

To test:

for i in {1..4}; do
  nc -z myserver 2222
  [ "$?" = 0 ] && echo "$i = success" || echo "$i = fail"
done

# 1 = success
# 2 = success
# 3 = success
# 4 = fail
lonix
  • 896
  • 10
  • 23