]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft: Fix for '-F' in iptables dumps
authorPhil Sutter <phil@nwl.cc>
Fri, 24 Apr 2020 09:32:08 +0000 (11:32 +0200)
committerPhil Sutter <phil@nwl.cc>
Mon, 11 May 2020 12:28:29 +0000 (14:28 +0200)
When restoring a dump which contains an explicit flush command,
previously added rules are removed from cache and the following commit
will try to create netlink messages based on freed memory.

Fix this by weeding any rule-based commands from obj_list if they
address the same chain.

Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft.c

index b505d70a03331ad6eec6e429921e4331ebdd5b5b..6503259eb443e180dabd769e0736b4ba372bdce5 100644 (file)
@@ -402,6 +402,38 @@ batch_rule_add(struct nft_handle *h, enum obj_update_type type,
        return batch_add(h, type, r);
 }
 
+static void batch_obj_del(struct nft_handle *h, struct obj_update *o);
+
+static void batch_chain_flush(struct nft_handle *h,
+                             const char *table, const char *chain)
+{
+       struct obj_update *obj, *tmp;
+
+       list_for_each_entry_safe(obj, tmp, &h->obj_list, head) {
+               struct nftnl_rule *r = obj->ptr;
+
+               switch (obj->type) {
+               case NFT_COMPAT_RULE_APPEND:
+               case NFT_COMPAT_RULE_INSERT:
+               case NFT_COMPAT_RULE_REPLACE:
+               case NFT_COMPAT_RULE_DELETE:
+                       break;
+               default:
+                       continue;
+               }
+
+               if (table &&
+                   strcmp(table, nftnl_rule_get_str(r, NFTNL_RULE_TABLE)))
+                       continue;
+
+               if (chain &&
+                   strcmp(chain, nftnl_rule_get_str(r, NFTNL_RULE_CHAIN)))
+                       continue;
+
+               batch_obj_del(h, obj);
+       }
+}
+
 const struct builtin_table xtables_ipv4[NFT_TABLE_MAX] = {
        [NFT_TABLE_RAW] = {
                .name   = "raw",
@@ -1681,6 +1713,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
        }
 
        if (chain || !verbose) {
+               batch_chain_flush(h, table, chain);
                __nft_rule_flush(h, table, chain, verbose, false);
                flush_rule_cache(h, table, c);
                return 1;
@@ -1696,6 +1729,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
        while (c != NULL) {
                chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
 
+               batch_chain_flush(h, table, chain);
                __nft_rule_flush(h, table, chain, verbose, false);
                flush_rule_cache(h, table, c);
                c = nftnl_chain_list_iter_next(iter);