From cf95f347e52ca8badc6a7149045d9c09f4fa666d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 19 Jul 2013 18:42:30 +0200 Subject: xtables: add -I chain rulenum This patch adds the nft_rule_insert function, which allows us to insert rules at a given position. The function nft_rule_add has been renamed to nft_rule_append. This is possible thanks to Eric Leblond's (netfilter: nf_tables: add insert operation) kernel patch. Signed-off-by: Pablo Neira Ayuso --- iptables/nft.c | 158 ++++++++++++++++++++++++++++++++++++++++------------- iptables/nft.h | 3 +- iptables/xtables.c | 29 +++++++--- 3 files changed, 144 insertions(+), 46 deletions(-) (limited to 'iptables') diff --git a/iptables/nft.c b/iptables/nft.c index d98b4538..c22e6c5b 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -689,30 +689,17 @@ void add_compat(struct nft_rule *r, uint32_t proto, bool inv) inv ? NFT_RULE_COMPAT_F_INV : 0); } -int -nft_rule_add(struct nft_handle *h, const char *chain, const char *table, - struct iptables_command_state *cs, - bool append, uint64_t handle, bool verbose) +static struct nft_rule * +nft_rule_new(struct nft_handle *h, const char *chain, const char *table, + struct iptables_command_state *cs) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - struct xtables_rule_match *matchp; struct nft_rule *r; - int ret = 1; - int flags = append ? NLM_F_APPEND : 0; - int ip_flags = 0; - - /* If built-in chains don't exist for this table, create them */ - if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) - nft_chain_builtin_init(h, table, chain, NF_ACCEPT); - - nft_fn = nft_rule_add; + int ret = 0, ip_flags = 0; + struct xtables_rule_match *matchp; r = nft_rule_alloc(); - if (r == NULL) { - ret = 0; - goto err; - } + if (r == NULL) + return NULL; nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, h->family); nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, (char *)table); @@ -721,19 +708,15 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table, ip_flags = h->ops->add(r, cs); for (matchp = cs->matches; matchp; matchp = matchp->next) { - if (add_match(r, matchp->match->m) < 0) { - ret = 0; + if (add_match(r, matchp->match->m) < 0) goto err; - } } /* Counters need to me added before the target, otherwise they are * increased for each rule because of the way nf_tables works. */ - if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) { - ret = 0; + if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) goto err; - } /* If no target at all, add nothing (default to continue) */ if (cs->target != NULL) { @@ -754,25 +737,50 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table, ret = add_jumpto(r, cs->jumpto, NFT_JUMP); } - if (ret < 0) { + if (ret < 0) + goto err; + + return r; +err: + nft_rule_free(r); + return NULL; +} + +int +nft_rule_append(struct nft_handle *h, const char *chain, const char *table, + struct iptables_command_state *cs, uint64_t handle, + bool verbose) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct nft_rule *r; + uint16_t flags = NLM_F_ACK|NLM_F_CREATE; + int ret = 1; + + /* If built-in chains don't exist for this table, create them */ + if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) + nft_chain_builtin_init(h, table, chain, NF_ACCEPT); + + nft_fn = nft_rule_append; + + r = nft_rule_new(h, chain, table, cs); + if (r == NULL) { ret = 0; goto err; } - /* NLM_F_CREATE autoloads the built-in table if it does not exists */ - flags |= NLM_F_ACK|NLM_F_CREATE; - if (handle > 0) { nft_rule_attr_set(r, NFT_RULE_ATTR_HANDLE, &handle); flags |= NLM_F_REPLACE; - } + } else + flags |= NLM_F_APPEND; if (h->commit) { nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS, NFT_RULE_F_COMMIT); } - nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, - h->family, flags, h->seq); + nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, h->family, + flags, h->seq); nft_rule_nlmsg_build_payload(nlh, r); @@ -782,7 +790,7 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table, ret = mnl_talk(h, nlh, NULL, NULL); if (ret < 0) - perror("mnl_talk:nft_rule_add"); + perror("mnl_talk:nft_rule_append"); err: /* the core expects 1 for success and 0 for error */ @@ -2139,6 +2147,82 @@ int nft_rule_delete(struct nft_handle *h, const char *chain, return ret; } +static int +nft_rule_add(struct nft_handle *h, const char *chain, + const char *table, struct iptables_command_state *cs, + uint64_t handle, bool verbose) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct nft_rule *r; + int ret = 1; + + r = nft_rule_new(h, chain, table, cs); + if (r == NULL) { + ret = 0; + goto err; + } + nft_rule_attr_set_u64(r, NFT_RULE_ATTR_POSITION, handle); + + if (h->commit) { + nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS, + NFT_RULE_F_COMMIT); + } + nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, h->family, + NLM_F_ACK|NLM_F_CREATE, h->seq); + nft_rule_nlmsg_build_payload(nlh, r); + nft_rule_print_debug(r, nlh); + nft_rule_free(r); + + ret = mnl_talk(h, nlh, NULL, NULL); + if (ret < 0) + perror("mnl_talk:nft_rule_add_num"); + +err: + /* the core expects 1 for success and 0 for error */ + return ret == 0 ? 1 : 0; +} + +int nft_rule_insert(struct nft_handle *h, const char *chain, + const char *table, struct iptables_command_state *cs, + int rulenum, bool verbose) +{ + struct nft_rule_list *list; + struct nft_rule *r; + uint64_t handle; + + /* If built-in chains don't exist for this table, create them */ + if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) + nft_chain_builtin_init(h, table, chain, NF_ACCEPT); + + nft_fn = nft_rule_insert; + + list = nft_rule_list_create(h); + if (list == NULL) + goto err; + + r = nft_rule_find(list, chain, table, cs, rulenum); + if (r == NULL) { + errno = ENOENT; + goto err; + } + + handle = nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE); + DEBUGP("adding after rule handle %"PRIu64"\n", handle); + + if (h->commit) { + nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS, + NFT_RULE_F_COMMIT); + } + + nft_rule_list_destroy(list); + + return nft_rule_add(h, chain, table, cs, handle, verbose); +err: + nft_rule_list_destroy(list); + return 0; +} + int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose) { @@ -2194,9 +2278,9 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS, NFT_RULE_F_COMMIT); } - ret = nft_rule_add(h, chain, table, cs, true, - nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE), - verbose); + ret = nft_rule_append(h, chain, table, cs, + nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE), + verbose); } else errno = ENOENT; diff --git a/iptables/nft.h b/iptables/nft.h index a6476714..7a6351b7 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -49,7 +49,8 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char */ struct nft_rule; -int nft_rule_add(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, bool append, uint64_t handle, bool verbose); +int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, uint64_t handle, bool verbose); +int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, int rulenum, bool verbose); int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, bool verbose); int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, bool verbose); int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose); diff --git a/iptables/xtables.c b/iptables/xtables.c index a5a83c24..41a7f716 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -404,7 +404,7 @@ static int add_entry(const char *chain, const char *table, struct iptables_command_state *cs, - int family, + int rulenum, int family, const struct addr_mask s, const struct addr_mask d, bool verbose, struct nft_handle *h, bool append) @@ -420,8 +420,15 @@ add_entry(const char *chain, cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr; cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr; - ret = nft_rule_add(h, chain, table, - cs, append, 0, verbose); + if (append) { + ret = nft_rule_append(h, chain, table, + cs, 0, + verbose); + } else { + ret = nft_rule_insert(h, chain, table, + cs, rulenum, + verbose); + } } } else if (family == AF_INET6) { memcpy(&cs->fw6.ipv6.src, @@ -433,8 +440,15 @@ add_entry(const char *chain, &d.addr.v6[j], sizeof(struct in6_addr)); memcpy(&cs->fw6.ipv6.dmsk, &d.mask.v6[j], sizeof(struct in6_addr)); - ret = nft_rule_add(h, chain, table, - cs, append, 0, verbose); + if (append) { + ret = nft_rule_append(h, chain, table, + cs, append, + verbose); + } else { + ret = nft_rule_insert(h, chain, table, + cs, rulenum, + verbose); + } } } } @@ -1148,7 +1162,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table) switch (command) { case CMD_APPEND: - ret = add_entry(chain, *table, &cs, h->family, + ret = add_entry(chain, *table, &cs, 0, h->family, args.s, args.d, cs.options&OPT_VERBOSE, h, true); break; @@ -1170,8 +1184,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table) cs.options&OPT_VERBOSE, h); break; case CMD_INSERT: - /* FIXME insert at rulenum */ - ret = add_entry(chain, *table, &cs, h->family, + ret = add_entry(chain, *table, &cs, rulenum - 1, h->family, args.s, args.d, cs.options&OPT_VERBOSE, h, false); break; -- cgit v1.2.3