diff options
Diffstat (limited to 'iptables/nft-cache.c')
-rw-r--r-- | iptables/nft-cache.c | 115 |
1 files changed, 85 insertions, 30 deletions
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 2c88301c..91d29670 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -26,6 +26,14 @@ #include "nft-cache.h" #include "nft-chain.h" +/* users may define NDEBUG */ +static void assert_nft_restart(struct nft_handle *h) +{ + int rc = nft_restart(h); + + assert(rc >= 0); +} + static void cache_chain_list_insert(struct list_head *list, const char *name) { struct cache_chain *pos = NULL, *new; @@ -105,7 +113,8 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid) return; xtables_error(RESOURCE_PROBLEM, - "Could not fetch rule set generation id: %s\n", nft_strerror(errno)); + "Could not fetch rule set generation id: %s", + nft_strerror(errno)); } static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data) @@ -141,12 +150,12 @@ static int fetch_table_cache(struct nft_handle *h) char buf[16536]; int i, ret; - nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, - NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family, + NLM_F_DUMP, h->seq); ret = mnl_talk(h, nlh, nftnl_table_list_cb, h); if (ret < 0 && errno == EINTR) - assert(nft_restart(h) >= 0); + assert_nft_restart(h); for (i = 0; i < NFT_TABLE_MAX; i++) { enum nft_table_type type = h->tables[i].type; @@ -202,26 +211,52 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) return NULL; } +static int +nft_cache_add_base_chain(struct nft_handle *h, const struct builtin_table *t, + struct nft_chain *nc) +{ + uint32_t hooknum = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_HOOKNUM); + const char *name = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_NAME); + const char *type = nftnl_chain_get_str(nc->nftnl, NFTNL_CHAIN_TYPE); + uint32_t prio = nftnl_chain_get_u32(nc->nftnl, NFTNL_CHAIN_PRIO); + const struct builtin_chain *bc = NULL; + int i; + + for (i = 0; i < NF_IP_NUMHOOKS && t->chains[i].name != NULL; i++) { + if (hooknum == t->chains[i].hook) { + bc = &t->chains[i]; + break; + } + } + + if (!bc || + prio != bc->prio || + strcmp(name, bc->name) || + strcmp(type, bc->type)) + return -EINVAL; + + nc->base_slot = &h->cache->table[t->type].base_chains[hooknum]; + if (*nc->base_slot) + return -EEXIST; + + *nc->base_slot = nc; + return 0; +} + int nft_cache_add_chain(struct nft_handle *h, const struct builtin_table *t, struct nftnl_chain *c) { const char *cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); struct nft_chain *nc = nft_chain_alloc(c); + int ret; if (nftnl_chain_is_set(c, NFTNL_CHAIN_HOOKNUM)) { - uint32_t hooknum = nftnl_chain_get_u32(c, NFTNL_CHAIN_HOOKNUM); - - if (hooknum >= NF_INET_NUMHOOKS) { - nft_chain_free(nc); - return -EINVAL; - } - - if (h->cache->table[t->type].base_chains[hooknum]) { + ret = nft_cache_add_base_chain(h, t, nc); + if (ret) { + h->cache->table[t->type].tainted = true; nft_chain_free(nc); - return -EEXIST; + return ret; } - - h->cache->table[t->type].base_chains[hooknum] = nc; } else { list_add_tail(&nc->head, &h->cache->table[t->type].chains->list); @@ -314,9 +349,7 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) goto out; } - if (nft_cache_add_chain(h, t, c)) - goto out; - + nft_cache_add_chain(h, t, c); return MNL_CB_OK; out: nftnl_chain_free(c); @@ -392,6 +425,7 @@ static int set_fetch_elem_cb(struct nftnl_set *s, void *data) char buf[MNL_SOCKET_BUFFER_SIZE]; struct nft_handle *h = data; struct nlmsghdr *nlh; + int ret; if (set_has_elements(s)) return 0; @@ -400,7 +434,14 @@ static int set_fetch_elem_cb(struct nftnl_set *s, void *data) NLM_F_DUMP, h->seq); nftnl_set_elems_nlmsg_build_payload(nlh, s); - return mnl_talk(h, nlh, set_elem_cb, s); + ret = mnl_talk(h, nlh, set_elem_cb, s); + + if (!ret && h->verbose > 1) { + fprintf(stdout, "set "); + nftnl_set_fprintf(stdout, s, 0, 0); + fprintf(stdout, "\n"); + } + return ret; } static int fetch_set_cache(struct nft_handle *h, @@ -429,8 +470,8 @@ static int fetch_set_cache(struct nft_handle *h, } } - nlh = nftnl_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, - h->family, flags, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, + h->family, flags, h->seq); if (s) { nftnl_set_nlmsg_build_payload(nlh, s); @@ -439,7 +480,7 @@ static int fetch_set_cache(struct nft_handle *h, ret = mnl_talk(h, nlh, nftnl_set_list_cb, &d); if (ret < 0 && errno == EINTR) { - assert(nft_restart(h) >= 0); + assert_nft_restart(h); return ret; } @@ -472,14 +513,14 @@ static int __fetch_chain_cache(struct nft_handle *h, struct nlmsghdr *nlh; int ret; - nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, - c ? NLM_F_ACK : NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family, + c ? NLM_F_ACK : NLM_F_DUMP, h->seq); if (c) nftnl_chain_nlmsg_build_payload(nlh, c); ret = mnl_talk(h, nlh, nftnl_chain_list_cb, &d); if (ret < 0 && errno == EINTR) - assert(nft_restart(h) >= 0); + assert_nft_restart(h); return ret; } @@ -514,9 +555,15 @@ static int fetch_chain_cache(struct nft_handle *h, return ret; } +struct rule_list_cb_data { + struct nftnl_chain *chain; + int verbose; +}; + static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) { - struct nftnl_chain *c = data; + struct rule_list_cb_data *rld = data; + struct nftnl_chain *c = rld->chain; struct nftnl_rule *r; r = nftnl_rule_alloc(); @@ -528,6 +575,10 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } + if (rld->verbose > 1) { + nftnl_rule_fprintf(stdout, r, 0, 0); + fprintf(stdout, "\n"); + } nftnl_chain_rule_add_tail(r, c); return MNL_CB_OK; } @@ -536,6 +587,10 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) { struct nftnl_chain *c = nc->nftnl; struct nft_handle *h = data; + struct rule_list_cb_data rld = { + .chain = c, + .verbose = h->verbose, + }; char buf[16536]; struct nlmsghdr *nlh; struct nftnl_rule *rule; @@ -553,13 +608,13 @@ static int nft_rule_list_update(struct nft_chain *nc, void *data) nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); - nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family, - NLM_F_DUMP, h->seq); + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family, + NLM_F_DUMP, h->seq); nftnl_rule_nlmsg_build_payload(nlh, rule); - ret = mnl_talk(h, nlh, nftnl_rule_list_cb, c); + ret = mnl_talk(h, nlh, nftnl_rule_list_cb, &rld); if (ret < 0 && errno == EINTR) - assert(nft_restart(h) >= 0); + assert_nft_restart(h); nftnl_rule_free(rule); |