summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/nf_tables.h8
-rw-r--r--iptables/nft.c56
-rw-r--r--iptables/nft.h7
-rw-r--r--iptables/xtables-restore.c22
-rw-r--r--iptables/xtables-standalone.c2
5 files changed, 90 insertions, 5 deletions
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index bdab3f2e..5385bf32 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -35,6 +35,8 @@ enum nf_tables_msg_types {
NFT_MSG_NEWSETELEM,
NFT_MSG_GETSETELEM,
NFT_MSG_DELSETELEM,
+ NFT_MSG_COMMIT,
+ NFT_MSG_ABORT,
NFT_MSG_MAX,
};
@@ -83,12 +85,18 @@ enum nft_chain_attributes {
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
+enum {
+ NFT_RULE_F_COMMIT = (1 << 0),
+ NFT_RULE_F_MASK = NFT_RULE_F_COMMIT,
+};
+
enum nft_rule_attributes {
NFTA_RULE_UNSPEC,
NFTA_RULE_TABLE,
NFTA_RULE_CHAIN,
NFTA_RULE_HANDLE,
NFTA_RULE_EXPRESSIONS,
+ NFTA_RULE_FLAGS,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
diff --git a/iptables/nft.c b/iptables/nft.c
index fd19ff55..f42e4377 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -946,6 +946,10 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
flags |= NLM_F_REPLACE;
}
+ 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);
@@ -1626,6 +1630,11 @@ __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, (char *)table);
nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, (char *)chain);
+ if (h->commit) {
+ nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+ NFT_RULE_F_COMMIT);
+ }
+
/* Delete all rules in this table + chain */
nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_DELRULE, h->family,
NLM_F_ACK, h->seq);
@@ -2773,6 +2782,10 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
if (r != NULL) {
ret = 1;
+ if (h->commit) {
+ nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+ NFT_RULE_F_COMMIT);
+ }
DEBUGP("deleting rule\n");
__nft_rule_del(h, r);
} else
@@ -2802,6 +2815,10 @@ int nft_rule_delete_num(struct nft_handle *h, const char *chain,
if (r != NULL) {
ret = 1;
+ if (h->commit) {
+ nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+ NFT_RULE_F_COMMIT);
+ }
DEBUGP("deleting rule by number %d\n", rulenum);
__nft_rule_del(h, r);
} else
@@ -2834,6 +2851,10 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
(unsigned long long)
nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE));
+ if (h->commit) {
+ 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);
@@ -3435,6 +3456,41 @@ next:
return 1;
}
+static int nft_action(struct nft_handle *h, int type)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t seq;
+ int ret;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_NFTABLES<< 8) | type;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_seq = seq = time(NULL);
+
+ struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = AF_INET;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = 0;
+
+ ret = mnl_talk(h, nlh, NULL, NULL);
+ if (ret < 0) {
+ if (errno != EEXIST)
+ perror("mnl-talk:nft_commit");
+ }
+ return ret;
+}
+
+int nft_commit(struct nft_handle *h)
+{
+ return nft_action(h, NFT_MSG_COMMIT);
+}
+
+int nft_abort(struct nft_handle *h)
+{
+ return nft_action(h, NFT_MSG_ABORT);
+}
+
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
{
struct mnl_socket *nl;
diff --git a/iptables/nft.h b/iptables/nft.h
index f7ed0a38..834fff0d 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -8,6 +8,7 @@ struct nft_handle {
struct mnl_socket *nl;
uint32_t portid;
uint32_t seq;
+ bool commit;
};
int nft_init(struct nft_handle *h);
@@ -56,6 +57,12 @@ int nft_rule_save(struct nft_handle *h, const char *table, bool counters);
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table);
/*
+ * global commit and abort
+ */
+int nft_commit(struct nft_handle *h);
+int nft_abort(struct nft_handle *h);
+
+/*
* revision compatibility.
*/
int nft_compatible_revision(const char *name, uint8_t rev, int opt);
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 9778a9f7..ca9e0c05 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -164,6 +164,7 @@ xtables_restore_main(int argc, char *argv[])
{
struct nft_handle h = {
.family = AF_INET, /* default to IPv4 */
+ .commit = true,
};
char buffer[10240];
int c;
@@ -253,10 +254,14 @@ xtables_restore_main(int argc, char *argv[])
continue;
} else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) {
if (!testing) {
- if (nft_table_wake_dormant(&h, curtable) < 0) {
- fprintf(stderr, "Failed to wake up "
- "dormant table `%s'\n",
- curtable);
+ /* Commit per table, although we support
+ * global commit at once, stick by now to
+ * the existing behaviour.
+ */
+ if (nft_commit(&h)) {
+ fprintf(stderr, "Failed to commit "
+ "table %s\n",
+ curtable);
}
DEBUGP("Calling commit\n");
ret = 1;
@@ -288,7 +293,6 @@ xtables_restore_main(int argc, char *argv[])
if (tablename && (strcmp(tablename, table) != 0))
continue;
- nft_table_set_dormant(&h, table);
if (noflush == 0) {
DEBUGP("Cleaning all chains of table '%s'\n",
table);
@@ -426,6 +430,14 @@ xtables_restore_main(int argc, char *argv[])
DEBUGP("argv[%u]: %s\n", a, newargv[a]);
ret = do_commandx(&h, newargc, newargv, &newargv[2]);
+ if (ret < 0) {
+ ret = nft_abort(&h);
+ if (ret < 0) {
+ fprintf(stderr, "failed to abort "
+ "commit operation\n");
+ }
+ exit(1);
+ }
free_argv();
fflush(stdout);
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index f746c902..28416117 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -46,6 +46,8 @@ xtables_main(int argc, char *argv[])
char *table = "filter";
struct nft_handle h;
+ memset(&h, 0, sizeof(h));
+
iptables_globals.program_name = "xtables";
ret = xtables_init_all(&xtables_globals, NFPROTO_IPV4);
if (ret < 0) {