summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--iptables/nft.c158
-rw-r--r--iptables/nft.h3
-rw-r--r--iptables/xtables.c29
3 files changed, 144 insertions, 46 deletions
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;