]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft: cache: Annotate faked base chains as such
authorPhil Sutter <phil@nwl.cc>
Sat, 27 Jul 2024 17:13:40 +0000 (19:13 +0200)
committerPhil Sutter <phil@nwl.cc>
Sat, 27 Jul 2024 17:28:52 +0000 (19:28 +0200)
To avoid pointless kernel ruleset modifications without too many
workarounds in user space, code sometimes adds "fake" base chains to
cache. Yet these fake entries happen to prevent base chain creation for
a following command which actually requires them. Fix this by annotating
the fake entries as such so *_builtin_init() functions may convert them
into real ones.

Fixes: fd4b9bf08b9eb ("nft: Avoid pointless table/chain creation")
Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft-cache.c
iptables/nft-cache.h
iptables/nft-chain.c
iptables/nft-chain.h
iptables/nft.c

index 91d296709b9de0e9f335dc22fc7ec58b142d3eb4..da2d4d7fd872c236f48e803a0530af8007658b4f 100644 (file)
@@ -244,10 +244,10 @@ nft_cache_add_base_chain(struct nft_handle *h, const struct builtin_table *t,
 }
 
 int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
-                       struct nftnl_chain *c)
+                       struct nftnl_chain *c, bool fake)
 {
        const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
-       struct nft_chain *nc = nft_chain_alloc(c);
+       struct nft_chain *nc = nft_chain_alloc(c, fake);
        int ret;
 
        if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) {
@@ -349,7 +349,7 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data)
                goto out;
        }
 
-       nft_cache_add_chain(h, t, c);
+       nft_cache_add_chain(h, t, c, false);
        return MNL_CB_OK;
 out:
        nftnl_chain_free(c);
index 29ec6b5c3232bbecbb7c5122254bbd12a13fd065..e9f5755c9561d727ab2e2ac26d3753e9b3bdfb3a 100644 (file)
@@ -17,7 +17,7 @@ int flush_rule_cache(struct nft_handle *h, const char *table,
                     struct nft_chain *c);
 void nft_cache_build(struct nft_handle *h);
 int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t,
-                       struct nftnl_chain *c);
+                       struct nftnl_chain *c, bool fake);
 int nft_cache_sort_chains(struct nft_handle *h, const char *table);
 
 struct nft_chain *
index e954170fa73125717ae75f55fce0063bb40ced58..c24e6c9b346d114149a243510125f80bc2623875 100644 (file)
 
 #include "nft-chain.h"
 
-struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl)
+struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl, bool fake)
 {
        struct nft_chain *c = xtables_malloc(sizeof(*c));
 
        INIT_LIST_HEAD(&c->head);
        c->nftnl = nftnl;
+       c->fake = fake;
 
        return c;
 }
index 9adf173857420f1701c8a42247a9237aa86c0142..166504c0c8f95c31a4b08849ecfd0b2d950b5828 100644 (file)
@@ -11,6 +11,7 @@ struct nft_chain {
        struct hlist_node       hnode;
        struct nft_chain        **base_slot;
        struct nftnl_chain      *nftnl;
+       bool                    fake;
 };
 
 #define CHAIN_NAME_HSIZE       512
@@ -20,7 +21,7 @@ struct nft_chain_list {
        struct hlist_head       names[CHAIN_NAME_HSIZE];
 };
 
-struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl);
+struct nft_chain *nft_chain_alloc(struct nftnl_chain *nftnl, bool fake);
 void nft_chain_free(struct nft_chain *c);
 
 struct nft_chain_list *nft_chain_list_alloc(void);
index a9d97d4cef8e0f695c19bb8a0059cdc1b108ec61..fde3db2a22b79b1d784ce93b3b92295eccb54230 100644 (file)
@@ -721,7 +721,7 @@ static void nft_chain_builtin_add(struct nft_handle *h,
 
        if (!fake)
                batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c);
-       nft_cache_add_chain(h, table, c);
+       nft_cache_add_chain(h, table, c, fake);
 }
 
 /* find if built-in table already exists */
@@ -765,14 +765,19 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
 static void nft_chain_builtin_init(struct nft_handle *h,
                                   const struct builtin_table *table)
 {
+       struct nft_chain *c;
        int i;
 
        /* Initialize built-in chains if they don't exist yet */
        for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
-               if (nft_chain_find(h, table->name, table->chains[i].name))
-                       continue;
-
-               nft_chain_builtin_add(h, table, &table->chains[i], false);
+               c = nft_chain_find(h, table->name, table->chains[i].name);
+               if (!c) {
+                       nft_chain_builtin_add(h, table,
+                                             &table->chains[i], false);
+               } else if (c->fake) {
+                       batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c->nftnl);
+                       c->fake = false;
+               }
        }
 }
 
@@ -799,6 +804,7 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table,
 {
        const struct builtin_table *t;
        const struct builtin_chain *c;
+       struct nft_chain *nc;
 
        if (!h->cache_init)
                return 0;
@@ -819,10 +825,13 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table,
        if (!c)
                return -1;
 
-       if (h->cache->table[t->type].base_chains[c->hook])
-               return 0;
-
-       nft_chain_builtin_add(h, t, c, false);
+       nc = h->cache->table[t->type].base_chains[c->hook];
+       if (!nc) {
+               nft_chain_builtin_add(h, t, c, false);
+       } else if (nc->fake) {
+               batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, nc->nftnl);
+               nc->fake = false;
+       }
        return 0;
 }
 
@@ -2091,7 +2100,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
        if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
                return 0;
 
-       nft_cache_add_chain(h, t, c);
+       nft_cache_add_chain(h, t, c, false);
 
        /* the core expects 1 for success and 0 for error */
        return 1;
@@ -2118,7 +2127,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
                nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
                created = true;
 
-               nft_cache_add_chain(h, t, c);
+               nft_cache_add_chain(h, t, c, false);
        } else {
                c = nc->nftnl;