In order to support anonymous sets, cache them along with their elements. Signed-off-by: Phil Sutter <phil@xxxxxx> --- iptables/nft.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++ iptables/nft.h | 7 ++++ 2 files changed, 115 insertions(+) diff --git a/iptables/nft.c b/iptables/nft.c index 28e63aad15878..633c33ddddb15 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -857,6 +857,14 @@ static int __flush_chain_cache(struct nftnl_chain *c, void *data) return 0; } +static int __flush_set_cache(struct nftnl_set *s, void *data) +{ + nftnl_set_list_del(s); + nftnl_set_free(s); + + return 0; +} + static int flush_cache(struct nft_cache *c, const struct builtin_table *tables, const char *tablename) { @@ -869,6 +877,8 @@ static int flush_cache(struct nft_cache *c, const struct builtin_table *tables, return 0; nftnl_chain_list_foreach(c->table[table->type].chains, __flush_chain_cache, NULL); + nftnl_set_list_foreach(c->table[table->type].sets, + __flush_set_cache, NULL); return 0; } @@ -881,6 +891,8 @@ static int flush_cache(struct nft_cache *c, const struct builtin_table *tables, nftnl_chain_list_free(c->table[i].chains); c->table[i].chains = NULL; + nftnl_set_list_free(c->table[i].sets); + c->table[i].sets = NULL; } nftnl_table_list_free(c->tables); c->tables = NULL; @@ -1414,6 +1426,86 @@ static int fetch_table_cache(struct nft_handle *h) return 1; } +static int nftnl_set_list_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nft_handle *h = data; + const struct builtin_table *t; + struct nftnl_set *s; + + s = nftnl_set_alloc(); + if (s == NULL) + return MNL_CB_OK; + + if (nftnl_set_nlmsg_parse(nlh, s) < 0) + goto out_free; + + t = nft_table_builtin_find(h, nftnl_set_get_str(s, NFTNL_SET_TABLE)); + if (!t) + goto out_free; + + nftnl_set_list_add_tail(s, h->cache->table[t->type].sets); + return MNL_CB_OK; +out_free: + nftnl_set_free(s); + return MNL_CB_OK; +} + +static int set_elem_cb(const struct nlmsghdr *nlh, void *data) +{ + return nftnl_set_elems_nlmsg_parse(nlh, data) ? -1 : MNL_CB_OK; +} + +static int set_list_fetch_elem_cb(struct nftnl_set *s, void *data) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nft_handle *h = data; + struct nlmsghdr *nlh; + + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, h->family, + NLM_F_DUMP, h->seq); + nftnl_set_elems_nlmsg_build_payload(nlh, s); + + return mnl_talk(h, nlh, set_elem_cb, s); +} + +static int fetch_set_cache(struct nft_handle *h) +{ + struct nlmsghdr *nlh; + char buf[16536]; + int i, ret; + + for (i = 0; i < NFT_TABLE_MAX; i++) { + enum nft_table_type type = h->tables[i].type; + + if (!h->tables[i].name) + continue; + + h->cache->table[type].sets = nftnl_set_list_alloc(); + if (!h->cache->table[type].sets) + return -1; + } + + nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, h->family, + NLM_F_DUMP, h->seq); + + ret = mnl_talk(h, nlh, nftnl_set_list_cb, h); + if (ret < 0 && errno == EINTR) { + assert(nft_restart(h) >= 0); + return ret; + } + + for (i = 0; i < NFT_TABLE_MAX; i++) { + enum nft_table_type type = h->tables[i].type; + + if (!h->tables[i].name) + continue; + + nftnl_set_list_foreach(h->cache->table[type].sets, + set_list_fetch_elem_cb, h); + } + return ret; +} + static int fetch_chain_cache(struct nft_handle *h) { char buf[16536]; @@ -1579,6 +1671,8 @@ static int fetch_rule_cache(struct nft_handle *h) { int i; + fetch_set_cache(h); + for (i = 0; i < NFT_TABLE_MAX; i++) { enum nft_table_type type = h->tables[i].type; @@ -1655,6 +1749,20 @@ struct nftnl_chain_list *nft_chain_list_get(struct nft_handle *h, return h->cache->table[t->type].chains; } +struct nftnl_set_list *nft_set_list_get(struct nft_handle *h, + const char *table) +{ + const struct builtin_table *t; + + t = nft_table_builtin_find(h, table); + if (!t) + return NULL; + + nft_build_cache(h); + + return h->cache->table[t->type].sets; +} + static const char *policy_name[NF_ACCEPT+1] = { [NF_DROP] = "DROP", [NF_ACCEPT] = "ACCEPT", diff --git a/iptables/nft.h b/iptables/nft.h index 5e5e765b0d043..2f929a15f98df 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -31,6 +31,7 @@ struct nft_cache { struct nftnl_table_list *tables; struct { struct nftnl_chain_list *chains; + struct nftnl_set_list *sets; bool initialized; } table[NFT_TABLE_MAX]; }; @@ -88,6 +89,12 @@ int nft_table_flush(struct nft_handle *h, const char *table); void nft_table_new(struct nft_handle *h, const char *table); const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table); +/* + * Operations with sets. + */ +struct nftnl_set_list *nft_set_list_get(struct nft_handle *h, + const char *table); + /* * Operations with chains. */ -- 2.22.0