Add support for timeouts of elements within a set (nftables)


I would like to request the ability to make use of dynamic ban lists and timeouts within the firewall.

Use case: I create a rule where if a source IP attempts to connect to the ssh port more than 5 times in a second then the offending packets are dropped but then have the option to have that element expire within nftables after some time.

Example (EDIT - I know dynamic ssh protection exists, this is just one of many ports that could be used):

 ipv6-name TEST {
     default-action drop
     description "Block new inbound SSH hits from a source greater than 5/sec for 30 min"
     rule 10 {
         action reject
         destination {
             port 22
         log enable
         protocol tcp
         recent {
             count 5
             time second
         state {
             new enable
         timeout 30 minutes

The resulting nftable set entry could appear something like:

table ip6 vyos_filter {
        set RECENT6_TEST_10 {
                type ipv6_addr
                size 65535
                flags dynamic, timeout
                elements = { ssh expires 9s}       # This part may be inaccurate, it was mostly copied from the wiki
        chain NAME6_TEST {
                ct state new tcp dport 22 log prefix "[TEST-10-R]" update @RECENT6_TEST_10 { ip6 saddr limit rate over 5/second timeout 30m} counter packets 0 bytes 0 reject comment "TEST-10"
                counter packets 0 bytes 0 drop comment "TEST default-action drop"

Another plus would be the ability to somehow refer to the resulting set RECENT6_TEST_10 which could then be used in other subsequent rules to deny connectivity altogether.

Thanks for your consideration.

Why not use
set service ssh dynamic-protection?

I was just using SSH as an example service. I would like to use this for anything: HTTP, DNS, MS – SQL, or any other port/service that may see shenanigans

vyos 1.3.3 not support this feature? is that feature implemented with nftable ?

Im not sure that the resulting nftable rule example is correct but I like the idea (I think you are missing a newline and are you sure about 9s in the example?).

In the logging it might be prefered, if possible, to get the actual timestamp (in ISO-format) of when the rule would not trigger any logger (at least make that an option).

Something like:

[TEST-10-R] trigger 5/s until 2023-07-13 17:45:06

Another thing when it comes to logging is a possibility to throttle it like every nth hit would be logged (should be optional).

This would basically be a way to do something like Fail2Ban but for all kinds of services and probably the most efficient way is by doing so with nftables (least amount of cpu cycles spent) and not involving an application.

One risk is of course that this should (generally speaking) only apply to new sessions but it would be optional if you want to do this on only new sessions or for all packets going on in a flow.

set firewall ipv6-name TEST state new enable

The logic in this case is that you first configure this drop rule that triggers on “count 5, time second” and the next rule would be the actual allow for the same service.

This way since nftable is top-down if the “count 5, time second” triggers then the packet(s) are dropped and if they are not dropped the rule following this timeout rule would allow the traffic.

This could also be reversed (for fun?) so the first rule allows for 5 packets/second and the 2nd one drops the packets. The result would then be that if there are fewer than 5 packets per second the flow is dropped but once the client exceed this threshold then the flow is allowed for 30 minutes (dont ask why one would like to have it in reverse mode but the option is there :slight_smile:

1 Like

It uses sshguard

1 Like

Any plan to backport this feature to vyos 1.3.x ? Currently, vyos1.3.3 didn’t have this feature.

Sure, I have created a feature request T5354

1 Like

There is some kind of this task T4839
Feel free to add a new one with timeout option

1 Like

Yeh the nftable part I stuck in is most likely incorrect, I’ll edit the post to reflect.

I do have have the example rule above tagged only for new sessions (as I would use it :slight_smile: )