diff options
Diffstat (limited to 'iptables/nft.c')
-rw-r--r-- | iptables/nft.c | 474 |
1 files changed, 359 insertions, 115 deletions
diff --git a/iptables/nft.c b/iptables/nft.c index 3f2a62ae..0c5a74fc 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -256,24 +256,6 @@ static int mnl_batch_talk(struct nft_handle *h, int numcmds) return err; } -enum obj_update_type { - NFT_COMPAT_TABLE_ADD, - NFT_COMPAT_TABLE_FLUSH, - NFT_COMPAT_CHAIN_ADD, - NFT_COMPAT_CHAIN_USER_ADD, - NFT_COMPAT_CHAIN_USER_DEL, - NFT_COMPAT_CHAIN_USER_FLUSH, - NFT_COMPAT_CHAIN_UPDATE, - NFT_COMPAT_CHAIN_RENAME, - NFT_COMPAT_CHAIN_ZERO, - NFT_COMPAT_RULE_APPEND, - NFT_COMPAT_RULE_INSERT, - NFT_COMPAT_RULE_REPLACE, - NFT_COMPAT_RULE_DELETE, - NFT_COMPAT_RULE_FLUSH, - NFT_COMPAT_SET_ADD, -}; - enum obj_action { NFT_COMPAT_COMMIT, NFT_COMPAT_ABORT, @@ -362,6 +344,15 @@ static int mnl_append_error(const struct nft_handle *h, snprintf(tcr, sizeof(tcr), "set %s", nftnl_set_get_str(o->set, NFTNL_SET_NAME)); break; + case NFT_COMPAT_RULE_LIST: + case NFT_COMPAT_RULE_CHECK: + case NFT_COMPAT_CHAIN_RESTORE: + case NFT_COMPAT_RULE_SAVE: + case NFT_COMPAT_RULE_ZERO: + case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: + case NFT_COMPAT_TABLE_NEW: + assert(0); + break; } return snprintf(buf, len, "%s: %s", errmsg, tcr); @@ -411,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", @@ -746,6 +769,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table) { const struct builtin_table *t; + if (!h->cache_init) + return 0; + t = nft_table_builtin_find(h, table); if (t == NULL) return -1; @@ -756,6 +782,9 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table) if (nft_table_builtin_add(h, t) < 0) return -1; + if (h->cache_req.level < NFT_CL_CHAINS) + return 0; + nft_chain_builtin_init(h, t); h->cache->table[t->type].initialized = true; @@ -789,8 +818,10 @@ int nft_restart(struct nft_handle *h) return 0; } -int nft_init(struct nft_handle *h, const struct builtin_table *t) +int nft_init(struct nft_handle *h, int family, const struct builtin_table *t) { + memset(h, 0, sizeof(*h)); + h->nl = mnl_socket_open(NETLINK_NETFILTER); if (h->nl == NULL) return -1; @@ -800,19 +831,37 @@ int nft_init(struct nft_handle *h, const struct builtin_table *t) return -1; } + h->ops = nft_family_ops_lookup(family); + if (!h->ops) + xtables_error(PARAMETER_PROBLEM, "Unknown family"); + h->portid = mnl_socket_get_portid(h->nl); h->tables = t; h->cache = &h->__cache[0]; + h->family = family; INIT_LIST_HEAD(&h->obj_list); INIT_LIST_HEAD(&h->err_list); + INIT_LIST_HEAD(&h->cmd_list); + INIT_LIST_HEAD(&h->cache_req.chain_list); return 0; } void nft_fini(struct nft_handle *h) { - flush_chain_cache(h, NULL); + struct list_head *pos, *n; + + list_for_each_safe(pos, n, &h->cmd_list) + nft_cmd_free(list_entry(pos, struct nft_cmd, head)); + + list_for_each_safe(pos, n, &h->obj_list) + batch_obj_del(h, list_entry(pos, struct obj_update, head)); + + list_for_each_safe(pos, n, &h->err_list) + mnl_err_list_free(list_entry(pos, struct mnl_err, head)); + + nft_release_cache(h); mnl_socket_close(h->nl); } @@ -950,6 +999,7 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table, { static uint32_t set_id = 0; struct nftnl_set *s; + struct nft_cmd *cmd; s = nftnl_set_alloc(); if (!s) @@ -965,7 +1015,14 @@ static struct nftnl_set *add_anon_set(struct nft_handle *h, const char *table, nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, key_len); nftnl_set_set_u32(s, NFTNL_SET_DESC_SIZE, size); - return batch_set_add(h, NFT_COMPAT_SET_ADD, s) ? s : NULL; + cmd = nft_cmd_new(h, NFT_COMPAT_SET_ADD, table, NULL, NULL, -1, false); + if (!cmd) { + nftnl_set_free(s); + return NULL; + } + cmd->obj.set = s; + + return s; } static struct nftnl_expr * @@ -1022,19 +1079,28 @@ static int __add_nft_among(struct nft_handle *h, const char *table, }; struct nftnl_expr *e; struct nftnl_set *s; + uint32_t flags = 0; int idx = 0; if (ip) { type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR; len += sizeof(struct in_addr) + NETLINK_ALIGN - 1; len &= ~(NETLINK_ALIGN - 1); + flags = NFT_SET_INTERVAL; } - s = add_anon_set(h, table, 0, type, len, cnt); + s = add_anon_set(h, table, flags, type, len, cnt); if (!s) return -ENOMEM; set_id = nftnl_set_get_u32(s, NFTNL_SET_ID); + if (ip) { + uint8_t field_len[2] = { ETH_ALEN, sizeof(struct in_addr) }; + + nftnl_set_set_data(s, NFTNL_SET_DESC_CONCAT, + field_len, sizeof(field_len)); + } + for (idx = 0; idx < cnt; idx++) { struct nftnl_set_elem *elem = nftnl_set_elem_alloc(); @@ -1042,6 +1108,15 @@ static int __add_nft_among(struct nft_handle *h, const char *table, return -ENOMEM; nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY, &pairs[idx], len); + if (ip) { + struct in_addr tmp = pairs[idx].in; + + if (tmp.s_addr == INADDR_ANY) + pairs[idx].in.s_addr = INADDR_BROADCAST; + nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY_END, + &pairs[idx], len); + pairs[idx].in = tmp; + } nftnl_set_elem_add(s, elem); } @@ -1302,7 +1377,7 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv) inv ? NFT_RULE_COMPAT_F_INV : 0); } -static struct nftnl_rule * +struct nftnl_rule * nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data) { @@ -1330,28 +1405,15 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain); int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, - void *data, struct nftnl_rule *ref, bool verbose) + struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose) { struct nftnl_chain *c; - struct nftnl_rule *r; int type; nft_xt_builtin_init(h, table); - /* Since ebtables user-defined chain policies are implemented as last - * rule in nftables, rule cache is required here to treat them right. */ - if (h->family == NFPROTO_BRIDGE) { - c = nft_chain_find(h, table, chain); - if (c && !nft_chain_builtin(c)) - nft_build_cache(h, c); - } - nft_fn = nft_rule_append; - r = nft_rule_new(h, chain, table, data); - if (r == NULL) - return 0; - if (ref) { nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE)); @@ -1359,17 +1421,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, } else type = NFT_COMPAT_RULE_APPEND; - if (batch_rule_add(h, type, r) == NULL) { - nftnl_rule_free(r); + if (batch_rule_add(h, type, r) == NULL) return 0; - } if (verbose) h->ops->print_rule(h, r, 0, FMT_PRINT_RULE); if (ref) { nftnl_chain_rule_insert_at(r, ref); - nftnl_chain_rule_del(r); + nftnl_chain_rule_del(ref); + nftnl_rule_free(ref); } else { c = nft_chain_find(h, table, chain); if (!c) { @@ -1392,8 +1453,9 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, ops->rule_to_cs(h, r, &cs); - if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS)) && ops->save_counters) - ops->save_counters(&cs); + if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS))) + printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt, + (unsigned long long)cs.counters.bcnt); /* print chain name */ switch(type) { @@ -1576,7 +1638,6 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) c = nftnl_chain_list_iter_next(iter); while (c) { - nft_build_cache(h, c); ret = nft_chain_save_rules(h, c, format); if (ret != 0) break; @@ -1590,6 +1651,20 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) return ret == 0 ? 1 : 0; } +struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h, + uint32_t set_id) +{ + struct obj_update *n; + + list_for_each_entry(n, &h->obj_list, head) { + if (n->type == NFT_COMPAT_SET_ADD && + nftnl_set_get_u32(n->set, NFTNL_SET_ID) == set_id) + return n->set; + } + + return NULL; +} + static void __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain, bool verbose, bool implicit) @@ -1646,6 +1721,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; @@ -1661,6 +1737,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); @@ -1722,7 +1799,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table } else { c = nftnl_chain_alloc(); if (!c) - return -1; + return 0; nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table); nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain); @@ -1733,7 +1810,7 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT); if (!created) - return 0; + return 1; ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); @@ -1741,7 +1818,8 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table if (list) nftnl_chain_list_add(c, list); - return ret; + /* the core expects 1 for success and 0 for error */ + return ret == 0 ? 1 : 0; } /* From linux/netlink.h */ @@ -1769,10 +1847,6 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data) fprintf(stdout, "Deleting chain `%s'\n", nftnl_chain_get_str(c, NFTNL_CHAIN_NAME)); - /* This triggers required policy rule deletion. */ - if (h->family == NFPROTO_BRIDGE) - nft_build_cache(h, c); - /* XXX This triggers a fast lookup from the kernel. */ nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE); ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c); @@ -2047,15 +2121,53 @@ static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) return 1; } +static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r, + struct nftnl_rule *rule) +{ + struct iptables_command_state _cs = {}, this = {}, *cs = &_cs; + bool ret = false; + + h->ops->rule_to_cs(h, r, &this); + h->ops->rule_to_cs(h, rule, cs); + + DEBUGP("comparing with... "); +#ifdef DEBUG_DEL + nft_rule_print_save(h, r, NFT_RULE_APPEND, 0); +#endif + if (!h->ops->is_same(cs, &this)) + goto out; + + if (!compare_matches(cs->matches, this.matches)) { + DEBUGP("Different matches\n"); + goto out; + } + + if (!compare_targets(cs->target, this.target)) { + DEBUGP("Different target\n"); + goto out; + } + + if ((!cs->target || !this.target) && + strcmp(cs->jumpto, this.jumpto) != 0) { + DEBUGP("Different verdict\n"); + goto out; + } + + ret = true; +out: + h->ops->clear_cs(&this); + h->ops->clear_cs(cs); + return ret; +} + static struct nftnl_rule * -nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulenum) +nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, + struct nftnl_rule *rule, int rulenum) { struct nftnl_rule *r; struct nftnl_rule_iter *iter; bool found = false; - nft_build_cache(h, c); - if (rulenum >= 0) /* Delete by rule number case */ return nftnl_rule_lookup_byindex(c, rulenum); @@ -2066,7 +2178,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen r = nftnl_rule_iter_next(iter); while (r != NULL) { - found = h->ops->rule_find(h, r, data); + found = nft_rule_cmp(h, r, rule); if (found) break; r = nftnl_rule_iter_next(iter); @@ -2078,7 +2190,7 @@ nft_rule_find(struct nft_handle *h, struct nftnl_chain *c, void *data, int rulen } int nft_rule_check(struct nft_handle *h, const char *chain, - const char *table, void *data, bool verbose) + const char *table, struct nftnl_rule *rule, bool verbose) { struct nftnl_chain *c; struct nftnl_rule *r; @@ -2089,7 +2201,7 @@ int nft_rule_check(struct nft_handle *h, const char *chain, if (!c) goto fail_enoent; - r = nft_rule_find(h, c, data, -1); + r = nft_rule_find(h, c, rule, -1); if (r == NULL) goto fail_enoent; @@ -2103,7 +2215,7 @@ fail_enoent: } int nft_rule_delete(struct nft_handle *h, const char *chain, - const char *table, void *data, bool verbose) + const char *table, struct nftnl_rule *rule, bool verbose) { int ret = 0; struct nftnl_chain *c; @@ -2117,7 +2229,7 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, return 0; } - r = nft_rule_find(h, c, data, -1); + r = nft_rule_find(h, c, rule, -1); if (r != NULL) { ret =__nft_rule_del(h, r); if (ret < 0) @@ -2132,16 +2244,11 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, static struct nftnl_rule * nft_rule_add(struct nft_handle *h, const char *chain, - const char *table, struct iptables_command_state *cs, + const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose) { - struct nftnl_rule *r; uint64_t ref_id; - r = nft_rule_new(h, chain, table, cs); - if (r == NULL) - return NULL; - if (ref) { ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE); if (ref_id > 0) { @@ -2158,10 +2265,8 @@ nft_rule_add(struct nft_handle *h, const char *chain, } } - if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) { - nftnl_rule_free(r); + if (!batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r)) return NULL; - } if (verbose) h->ops->print_rule(h, r, 0, FMT_PRINT_RULE); @@ -2170,9 +2275,10 @@ nft_rule_add(struct nft_handle *h, const char *chain, } int nft_rule_insert(struct nft_handle *h, const char *chain, - const char *table, void *data, int rulenum, bool verbose) + const char *table, struct nftnl_rule *new_rule, int rulenum, + bool verbose) { - struct nftnl_rule *r = NULL, *new_rule; + struct nftnl_rule *r = NULL; struct nftnl_chain *c; nft_xt_builtin_init(h, table); @@ -2186,22 +2292,22 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, } if (rulenum > 0) { - r = nft_rule_find(h, c, data, rulenum); + r = nft_rule_find(h, c, new_rule, rulenum); if (r == NULL) { /* special case: iptables allows to insert into * rule_count + 1 position. */ - r = nft_rule_find(h, c, data, rulenum - 1); + r = nft_rule_find(h, c, new_rule, rulenum - 1); if (r != NULL) - return nft_rule_append(h, chain, table, data, - NULL, verbose); + return nft_rule_append(h, chain, table, + new_rule, NULL, verbose); errno = E2BIG; goto err; } } - new_rule = nft_rule_add(h, chain, table, data, r, verbose); + new_rule = nft_rule_add(h, chain, table, new_rule, r, verbose); if (!new_rule) goto err; @@ -2243,7 +2349,8 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain, } int nft_rule_replace(struct nft_handle *h, const char *chain, - const char *table, void *data, int rulenum, bool verbose) + const char *table, struct nftnl_rule *rule, + int rulenum, bool verbose) { int ret = 0; struct nftnl_chain *c; @@ -2257,13 +2364,13 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, return 0; } - r = nft_rule_find(h, c, data, rulenum); + r = nft_rule_find(h, c, rule, rulenum); if (r != NULL) { DEBUGP("replacing rule with handle=%llu\n", (unsigned long long) nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE)); - ret = nft_rule_append(h, chain, table, data, r, verbose); + ret = nft_rule_append(h, chain, table, rule, r, verbose); } else errno = E2BIG; @@ -2496,8 +2603,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char *table, int rulenum) { struct iptables_command_state cs = {}; + struct nftnl_rule *r, *new_rule; struct nftnl_chain *c; - struct nftnl_rule *r; int ret = 0; nft_fn = nft_rule_delete; @@ -2516,8 +2623,11 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, nft_rule_to_iptables_command_state(h, r, &cs); cs.counters.pcnt = cs.counters.bcnt = 0; + new_rule = nft_rule_new(h, chain, table, &cs); + if (!new_rule) + return 1; - ret = nft_rule_append(h, chain, table, &cs, r, false); + ret = nft_rule_append(h, chain, table, new_rule, r, false); error: return ret; @@ -2611,14 +2721,23 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) case NFT_COMPAT_RULE_APPEND: case NFT_COMPAT_RULE_INSERT: case NFT_COMPAT_RULE_REPLACE: - case NFT_COMPAT_RULE_DELETE: break; + case NFT_COMPAT_RULE_DELETE: case NFT_COMPAT_RULE_FLUSH: nftnl_rule_free(o->rule); break; case NFT_COMPAT_SET_ADD: nftnl_set_free(o->set); break; + case NFT_COMPAT_RULE_LIST: + case NFT_COMPAT_RULE_CHECK: + case NFT_COMPAT_CHAIN_RESTORE: + case NFT_COMPAT_RULE_SAVE: + case NFT_COMPAT_RULE_ZERO: + case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: + case NFT_COMPAT_TABLE_NEW: + assert(0); + break; } h->obj_list_num--; list_del(&o->head); @@ -2686,6 +2805,13 @@ static void nft_refresh_transaction(struct nft_handle *h) case NFT_COMPAT_RULE_DELETE: case NFT_COMPAT_RULE_FLUSH: case NFT_COMPAT_SET_ADD: + case NFT_COMPAT_RULE_LIST: + case NFT_COMPAT_RULE_CHECK: + case NFT_COMPAT_CHAIN_RESTORE: + case NFT_COMPAT_RULE_SAVE: + case NFT_COMPAT_RULE_ZERO: + case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: + case NFT_COMPAT_TABLE_NEW: break; } } @@ -2783,6 +2909,14 @@ retry: NLM_F_CREATE, &n->seq, n->set); seq = n->seq; break; + case NFT_COMPAT_RULE_LIST: + case NFT_COMPAT_RULE_CHECK: + case NFT_COMPAT_CHAIN_RESTORE: + case NFT_COMPAT_RULE_SAVE: + case NFT_COMPAT_RULE_ZERO: + case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: + case NFT_COMPAT_TABLE_NEW: + assert(0); } mnl_nft_batch_continue(h->batch); @@ -2803,7 +2937,6 @@ retry: nft_refresh_transaction(h); - i=0; list_for_each_entry_safe(err, ne, &h->err_list, head) mnl_err_list_free(err); @@ -2878,27 +3011,33 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data) r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME), nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs); + ebt_cs_clean(&cs); + if (!r) return -1; udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN); if (!udata) - return -1; + goto err_free_rule; if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1)) - return -1; + goto err_free_rule; nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, nftnl_udata_buf_data(udata), nftnl_udata_buf_len(udata)); nftnl_udata_buf_free(udata); - if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) { - nftnl_rule_free(r); - return -1; - } + if (!batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r)) + goto err_free_rule; + + /* add the rule to chain so it is freed later */ + nftnl_chain_rule_add_tail(r, c); return 0; +err_free_rule: + nftnl_rule_free(r); + return -1; } int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, @@ -2919,8 +3058,6 @@ int ebt_set_user_chain_policy(struct nft_handle *h, const char *table, else return 0; - nft_build_cache(h, c); - nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval); return 1; } @@ -2945,41 +3082,152 @@ static void nft_bridge_commit_prepare(struct nft_handle *h) } } -int nft_commit(struct nft_handle *h) +static void assert_chain_exists(struct nft_handle *h, + const char *table, const char *chain) { - return nft_action(h, NFT_COMPAT_COMMIT); + if (chain && !nft_chain_exists(h, table, chain)) + xtables_error(PARAMETER_PROBLEM, + "Chain '%s' does not exist", chain); } -int nft_bridge_commit(struct nft_handle *h) +static int nft_prepare(struct nft_handle *h) { - nft_bridge_commit_prepare(h); - return nft_commit(h); + struct nft_cmd *cmd, *next; + int ret = 1; + + nft_cache_build(h); + + list_for_each_entry_safe(cmd, next, &h->cmd_list, head) { + switch (cmd->command) { + case NFT_COMPAT_TABLE_FLUSH: + ret = nft_table_flush(h, cmd->table); + break; + case NFT_COMPAT_CHAIN_USER_ADD: + ret = nft_chain_user_add(h, cmd->chain, cmd->table); + break; + case NFT_COMPAT_CHAIN_USER_DEL: + ret = nft_chain_user_del(h, cmd->chain, cmd->table, + cmd->verbose); + break; + case NFT_COMPAT_CHAIN_RESTORE: + ret = nft_chain_restore(h, cmd->chain, cmd->table); + break; + case NFT_COMPAT_CHAIN_UPDATE: + ret = nft_chain_set(h, cmd->table, cmd->chain, + cmd->policy, &cmd->counters); + break; + case NFT_COMPAT_CHAIN_RENAME: + ret = nft_chain_user_rename(h, cmd->chain, cmd->table, + cmd->rename); + break; + case NFT_COMPAT_CHAIN_ZERO: + ret = nft_chain_zero_counters(h, cmd->chain, cmd->table, + cmd->verbose); + break; + case NFT_COMPAT_RULE_APPEND: + assert_chain_exists(h, cmd->table, cmd->jumpto); + ret = nft_rule_append(h, cmd->chain, cmd->table, + cmd->obj.rule, NULL, cmd->verbose); + break; + case NFT_COMPAT_RULE_INSERT: + assert_chain_exists(h, cmd->table, cmd->jumpto); + ret = nft_rule_insert(h, cmd->chain, cmd->table, + cmd->obj.rule, cmd->rulenum, + cmd->verbose); + break; + case NFT_COMPAT_RULE_REPLACE: + assert_chain_exists(h, cmd->table, cmd->jumpto); + ret = nft_rule_replace(h, cmd->chain, cmd->table, + cmd->obj.rule, cmd->rulenum, + cmd->verbose); + break; + case NFT_COMPAT_RULE_DELETE: + assert_chain_exists(h, cmd->table, cmd->jumpto); + if (cmd->rulenum >= 0) + ret = nft_rule_delete_num(h, cmd->chain, + cmd->table, + cmd->rulenum, + cmd->verbose); + else + ret = nft_rule_delete(h, cmd->chain, cmd->table, + cmd->obj.rule, cmd->verbose); + break; + case NFT_COMPAT_RULE_FLUSH: + ret = nft_rule_flush(h, cmd->chain, cmd->table, + cmd->verbose); + break; + case NFT_COMPAT_RULE_LIST: + ret = nft_rule_list(h, cmd->chain, cmd->table, + cmd->rulenum, cmd->format); + break; + case NFT_COMPAT_RULE_CHECK: + assert_chain_exists(h, cmd->table, cmd->jumpto); + ret = nft_rule_check(h, cmd->chain, cmd->table, + cmd->obj.rule, cmd->rulenum); + break; + case NFT_COMPAT_RULE_ZERO: + ret = nft_rule_zero_counters(h, cmd->chain, cmd->table, + cmd->rulenum); + break; + case NFT_COMPAT_RULE_SAVE: + ret = nft_rule_list_save(h, cmd->chain, cmd->table, + cmd->rulenum, + cmd->counters_save); + break; + case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: + ret = ebt_set_user_chain_policy(h, cmd->table, + cmd->chain, cmd->policy); + break; + case NFT_COMPAT_TABLE_NEW: + nft_xt_builtin_init(h, cmd->table); + ret = 1; + break; + case NFT_COMPAT_SET_ADD: + nft_xt_builtin_init(h, cmd->table); + batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set); + ret = 1; + break; + case NFT_COMPAT_TABLE_ADD: + case NFT_COMPAT_CHAIN_ADD: + assert(0); + break; + } + + nft_cmd_free(cmd); + + if (ret == 0) + return 0; + } + + return 1; } -int nft_abort(struct nft_handle *h) +int nft_commit(struct nft_handle *h) { - return nft_action(h, NFT_COMPAT_ABORT); + if (!nft_prepare(h)) + return 0; + + return nft_action(h, NFT_COMPAT_COMMIT); } -int nft_abort_policy_rule(struct nft_handle *h, const char *table) +int nft_bridge_commit(struct nft_handle *h) { - struct obj_update *n, *tmp; + if (!nft_prepare(h)) + return 0; - list_for_each_entry_safe(n, tmp, &h->obj_list, head) { - if (n->type != NFT_COMPAT_RULE_APPEND && - n->type != NFT_COMPAT_RULE_DELETE) - continue; + nft_bridge_commit_prepare(h); - if (strcmp(table, - nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE))) - continue; + return nft_action(h, NFT_COMPAT_COMMIT); +} - if (!nft_rule_is_policy_rule(n->rule)) - continue; +int nft_abort(struct nft_handle *h) +{ + struct nft_cmd *cmd, *next; - batch_obj_del(h, n); - } - return 0; + list_for_each_entry_safe(cmd, next, &h->cmd_list, head) + nft_cmd_free(cmd); + + return nft_action(h, NFT_COMPAT_ABORT); } int nft_compatible_revision(const char *name, uint8_t rev, int opt) @@ -3162,8 +3410,6 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data) return -1; } - nft_build_cache(h, c); - iter = nftnl_rule_iter_create(c); if (iter == NULL) return -1; @@ -3300,8 +3546,6 @@ static int nft_is_chain_compatible(struct nftnl_chain *c, void *data) enum nf_inet_hooks hook; int prio; - nft_build_cache(h, c); - if (nftnl_rule_foreach(c, nft_is_rule_compatible, NULL)) return -1; |