]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: set NFT_SET_EVAL flag if dynamic set already exists
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 18 May 2023 12:40:38 +0000 (14:40 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 18 May 2023 15:02:28 +0000 (17:02 +0200)
nft reports EEXIST when reading an existing set whose NFT_SET_EVAL has
been previously inferred from the ruleset.

 # cat test.nft
 table ip test {
        set dlist {
                type ipv4_addr
                size 65535
        }

        chain output {
                type filter hook output priority filter; policy accept;
                udp dport 1234 update @dlist { ip daddr } counter packets 0 bytes 0
        }
 }
 # nft -f test.nft
 # nft -f test.nft
 test.nft:2:6-10: Error: Could not process rule: File exists
         set dlist {
             ^^^^^

Phil Sutter says:

In the first call, the set lacking 'dynamic' flag does not exist
and is therefore added to the cache. Consequently, both the 'add set'
command and the set statement point at the same set object. In the
second call, a set with same name exists already, so the object created
for 'add set' command is not added to cache and consequently not updated
with the missing flag. The kernel thus rejects the NEWSET request as the
existing set differs from the new one.

Set on the NFT_SET_EVAL flag if the existing set sets it on.

Fixes: 8d443adfcc8c1 ("evaluate: attempt to set_eval flag if dynamic updates requested")
Tested-by: Eric Garver <eric@garver.life>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c

index 08243220f15943bb2cb9726f3dc43bd1dc4cf5da..17a437bd653078fffa25a1ff048df73a50256385 100644 (file)
@@ -4516,6 +4516,14 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
                existing_set = set_cache_find(table, set->handle.set.name);
                if (!existing_set)
                        set_cache_add(set_get(set), table);
+
+               if (existing_set && existing_set->flags & NFT_SET_EVAL) {
+                       uint32_t existing_flags = existing_set->flags & ~NFT_SET_EVAL;
+                       uint32_t new_flags = set->flags & ~NFT_SET_EVAL;
+
+                       if (existing_flags == new_flags)
+                               set->flags |= NFT_SET_EVAL;
+               }
        }
 
        if (!(set->flags & NFT_SET_INTERVAL) && set->automerge)