3

In setting up dynamic blacklists for nftables, per A.B.'s excellent answer, I'm encountering an error when duplicating the blacklist for both ipv4 and ipv6. I perform the following command-line operation (debian nftables) (EDIT: The original question was for a prior version, 0.9.0; during the back-and-forth comment process, it was upgraded to the more current version 0.9.3, so the accepted answer below is valid for the version 0.9.3 API):

nft flush ruleset && nft -f /etc/nftables.conf

for a config file including:

tcp flags syn tcp dport 8000 meter flood size 128000 { ip  saddr timeout 20s limit rate over 1/second } add @blackhole_4 { ip  saddr timeout 1m } drop
tcp flags syn tcp dport 8000 meter flood size 128000 { ip6 saddr timeout 20s limit rate over 1/second } add @blackhole_6 { ip6 saddr timeout 1m } drop
tcp flags syn tcp dport 8000 meter greed size 128000 { ip  saddr ct count over 3 } add @blackhole_4 { ip  saddr timeout 1m } drop                                                         
tcp flags syn tcp dport 8000 meter greed size 128000 { ip6 saddr ct count over 3 } add @blackhole_6 { ip6 saddr timeout 1m } drop

and get the following error response:

/etc/nftables.conf:130:17-166: Error: Could not process rule: Device or resource busy
                tcp flags syn tcp dport 8000 meter flood size 128000 { ip6 saddr timeout 20s limit rate over 1/second } add @blackhole_6 { ip6 saddr timeout 1m } drop
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/etc/nftables.conf:132:17-145: Error: Could not process rule: Device or resource busy
                tcp flags syn tcp dport 8000 meter greed size 128000 { ip6 saddr ct count over 3 } add @blackhole_6 { ip6 saddr timeout 1m } drop
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Also, I'm not sure what the size is a measure of; it's set to 128000 because that's what I saw somewhere authoritative.

EDIT: Okay. I decided to continue playing, and see that creating separate meters for each ipv6 rule causes the error message to go away, but I don't understand why, so instead of answering my own question, I'll leave it open for someone who has a knowledgeable explanation why the meters can't be shared. The following produces no errors:

tcp flags syn tcp dport 8000 meter flood_4 size 128000 { ip  saddr timeout 20s limit rate over 1/second } add @blackhole_4 { ip  saddr timeout 1m } drop
tcp flags syn tcp dport 8000 meter flood_6 size 128000 { ip6 saddr timeout 20s limit rate over 1/second } add @blackhole_6 { ip6 saddr timeout 1m } drop
tcp flags syn tcp dport 8000 meter greed_4 size 128000 { ip  saddr ct count over 3 } add @blackhole_4 { ip  saddr timeout 1m } drop                                                         
tcp flags syn tcp dport 8000 meter greed_6 size 128000 { ip6 saddr ct count over 3 } add @blackhole_6 { ip6 saddr timeout 1m } drop

EDIT: At the time of this writing, the man pages for nftables use the term meter, but according to the nftables wiki, the term has been deprecated in favor of set, which requires a definition including a specific protocol type (eg. ipv4_addr), so if nftables is currently mapping the term meter to the newer set, that would explain why a single meter can't currently be shared between ipv4_addr and ipv6_addr. However, the example given in the nftables wiki itself is also not up-to-date: it generates an error because dynamic is not currently (nftables v0.9.0) a valid flag type. Back to the man pages, and we can see that set has flags of either type constant, interval, or timeout, and I'm uncertain which would be appropriate for this purpose.

EDIT: The "count" form of metering seems to have moved to a separate part of nftables: ct (connection tracking). It seems that one should now create defintions such as:

    set greed_4 {                                                                                                                                                                                 
        type ipv4_addr                                                                                                                                                                            
        flags constant                                                                                                                                                                            
        size 128000                                                                                                                                                                               
        }                                                                                                                                                                                         

    set greed_6 {                                                                                                                                                                                 
        type ipv6_addr                                                                                                                                                                            
        flags constant                                                                                                                                                                            
        size 128000                                                                                                                                                                               
        }                                                                                                                                                                                         

and then the following rules may be close, but still generate errors:

ct state new add @greed_4 { tcp flags syn tcp dport 8000 ip saddr ct count over 3 } add @blackhole_4 { ip saddr timeout 1m } drop
ct state new add @greed_6 { tcp flags syn tcp dport 8000 ip6 saddr ct count over 3 } add @blackhole_6 { ip6 saddr timeout 1m } drop
5
  • You made a few illogical syntax mistakes (why add a tcp port test (ie: type boolean) inside the braces that expect only an ip address? why expecting "constant" to appease the lack of "dynamic" keyword will still allow the kernel to do dynamic updates from the packet path?) but that's not the point: even if corrected it won't work. The solution is simple: either stick to the meter syntax, or upgrade nftables to current version 0.9.4 or at least 0.9.3. Don't try and use right new features with not-right-new tools
    – A.B
    Commented May 15, 2020 at 14:13
  • The simple solutions don't actually work, if you try them, even after upgrading. Part of the problem and frustration is that the project ships documentation incompitable with the version of software being distributed, and the project wiki and other on-line documentation don't explicitly say what features exist for which version. For a project with a 'developing' api, this is important. I intend to post further edits as I continue testing, but will likely consider a wholesale edit of the question from scratch in order for it to be of most use to others. Commented May 17, 2020 at 4:12
  • @A.B. User dbjam-plus posted an answer that seems to work. Commented May 28, 2020 at 14:37
  • doesn't work with nftables 0.9.0 which your question states is to be used (else it works except you forgot a 6 in the edited part that was missing). So I'm wondering if you really tried it
    – A.B
    Commented May 28, 2020 at 14:44
  • @A.B After you discussed the differences between versions in you first comment, I mentioned in my first response that I reacted by upgrading to 0.9.3. I'll update the question so it will be clear to others. I tested under IPv4, so your point about the missing 6 is also noted, and I'll edit that also. Commented May 28, 2020 at 14:58

1 Answer 1

2

try this one

table inet filter {
  set blackhole_4 {
    type ipv4_addr
    flags timeout
  }
  set blackhole_6 {
    type ipv6_addr
    flags timeout
  }
  set greed_4 {
    type ipv4_addr
    flags dynamic
    size 128000
  }
  set greed_6 {
    type ipv6_addr
    flags dynamic
    size 128000
  }
  chain input {
    type filter hook input priority 0;
    ct state new tcp flags syn tcp dport 8000 add @greed_4 { ip saddr ct count over 3 } add @blackhole_4 { ip  saddr timeout 1m } drop
    ct state new tcp flags syn tcp dport 8000 add @greed_6 { ip6 saddr ct count over 3 } add @blackhole_6 { ip6  saddr timeout 1m } drop
  }
}

EDIT: Explanation from @User1404316: Since @Zip May (correctly) asked for some explanation. As I understand it: ct introduces a connection tracking rule, in this case for new tcp connections, that if they are heading for port 8000 (dport is destination port), add the source IPv4 to the pre-defined collection set greed_4. If that happens, the rule continues with the first bracket condition, that if the source address has more than three active connections, add the source IPv4 to the second predefined set blackhole_4, but only keep it there for one minute, and if we have gotten this far along in the rule, then drop the connection.

The original posted answer had two of its long lines truncated, but I figured out what I think they should be and inserted them above. The good news is that my testing indicates that this answer works!

A remaining curiousity for me is how to decide when to set sizes for the collection sets, and how large to make them, so I just left things the way they are for now.

5
  • Welcome @dbjam. In order for your answer to be more helpful to others, try describing more thoroughly the changes you're suggesting. Giving some background on what it does and why also goes a long way!
    – Zip
    Commented May 21, 2020 at 15:17
  • 1
    @Zip I've attempted to explain the answer Commented May 28, 2020 at 14:33
  • @dbjam-plus You had two lines of your answer truncated. I edited them to what I think they should be; let me know if I missed something or omitted some feature. Commented May 28, 2020 at 14:35
  • 1
    Sort of sad that at all other levels nftables promises to unify the rules, but for sets it's not possible to have one set across IPv6 and IPv4. With ipset this was (and still is) possible. Perhaps typeof ip saddr and similar (introduced with nftables 0.9.4) will fix it, but it takes time to trickle down to the individual distros ... Commented May 1, 2021 at 22:50
  • @0xC0000022L did you by any chance look into unifying the rules when using newer nftables versions? it would be nice if this answer was updated to something recent. Commented Nov 21, 2023 at 12:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .