4

I'm looking to limit the number of concurrent connections to a given service running on a Linux server. My understanding is that this can be done in iptables using the connlimit module. So for example, if I wanted to limit concurrent connections to my SSH server (and assuming the default policy is reject), then this should allow 10 concurrent connections, with the 11th being rejected (written from memory):

iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-upto 10 -j ACCEPT

The thing is on the new servers I'm building I want to implement the firewall using nftables. Although I can find connlimit mentioned in the man page, it simply states consider native interface. Refer to Meters. Having searched around about Meters, although it looks awesome for rate limiting, I can't find anything that suggests I can do the equivilant of connlimit.

So, given I want to use nftables, how to I create a rule that will only match up to X concurrent connections?

PeterM
  • 113
  • 1
  • 5

1 Answers1

2

There is a new extension nft_connlimit that was added since Linux kernel 4.18, providing a ct count expression.

For this case, the equivalent rules (from scratch) would be:

nft flush ruleset
nft add table ip filter
nft add chain ip filter input '{ type filter hook input priority 0; }'
nft add rule ip filter input tcp dport 22 ct count 10 counter accept
# nft add rule ip filter input tcp dport 22 counter reject with tcp reset

Some remarks:

  • As usual counter is optional and is used to get a counter with nft list ruleset to know how many times the rule triggered.

  • Replacing above all occurences of ip with ip6 will get the equivalent for IPv6. Now what's more interesting is using inet to get a combined count of IPv4 and IPv6 SSH connections together since they are accounted together by conntrack.

  • Kernels between 4.19.0 and 4.19.9 must be avoided, because using this feature will likely crash the host. (Upcoming) kernel 4.20 and kernel 4.19.10 include several patches related to conncount, fixing crashes and wrong count. Status unknown for kernel 4.18.x.


UPDATE: limit per network instead of just per IP, equivalent to iptables' --connlimit-mask

Rereading scarce documentation from the initial patch in netfilter-devel mailing list, ct count isn't limited to be used just standalone (or would be limited to the example above). It can be used within a meter expression/list for any more complex usage.

Should one want to reject connections to port 2222 (where some process is listening) above 3 connection counts per any random /24 network source IP, this rule should be used (as of nft 0.9.0 / kernel 4.19.10):

nft add rule ip filter input tcp dport 2222 meter test-2222-count-meter '{ ip saddr & 255.255.255.0 ct count over 3 }' counter reject with tcp reset

This will create a meter list named test-2222-count-meter which will dynamically add the relevant "map" data (for every different /24 network having matched a connection). I'm not sure if stale data (ie /24 networks not having any connection anymore) is ever removed via garbage collection or not.

The meter's contents can be listed (it won't show the count reached, just the dynamically added "maps" when new networks are seen). Eg after some connections from 10.0.3.1, 10.0.3.66, 10.0.4.5 and 172.31.4.5:

# nft list meter ip filter test-2222-count-meter
table ip filter {
    meter test-2222-count-meter {
        type ipv4_addr
        size 65535
        elements = { 10.0.3.0 : ct count over 3 , 10.0.4.0 : ct count over 3 , 172.31.4.0 : ct count over 3  }
    }
}
A.B
  • 9,037
  • 2
  • 19
  • 37
  • Thanks for the detailed answer, that's exactly what I needed! Do you happen to know how to limit this to say a source subnet? So if I had `192.168.1.0` and `192.168.2.0`, how would I limit it to 10 connections for each? In `iptables` I think it used `connlimit-mask`. Thanks again! – PeterM Nov 14 '18 at 10:02
  • 1
    Completed with an example equivalent to using `--connlimit-mask 24` – A.B Nov 14 '18 at 22:12