summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/nf_tables.h16
-rw-r--r--include/mnl.h1
-rw-r--r--include/netlink.h1
-rw-r--r--src/main.c1
-rw-r--r--src/mnl.c51
-rw-r--r--src/netlink.c5
6 files changed, 75 insertions, 0 deletions
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 66d66dd3..b72ccfea 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -51,6 +51,8 @@ enum nft_verdicts {
* @NFT_MSG_NEWSETELEM: create a new set element (enum nft_set_elem_attributes)
* @NFT_MSG_GETSETELEM: get a set element (enum nft_set_elem_attributes)
* @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes)
+ * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes)
*/
enum nf_tables_msg_types {
NFT_MSG_NEWTABLE,
@@ -68,6 +70,8 @@ enum nf_tables_msg_types {
NFT_MSG_NEWSETELEM,
NFT_MSG_GETSETELEM,
NFT_MSG_DELSETELEM,
+ NFT_MSG_NEWGEN,
+ NFT_MSG_GETGEN,
NFT_MSG_MAX,
};
@@ -812,4 +816,16 @@ enum nft_masq_attributes {
};
#define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1)
+/**
+ * enum nft_gen_attributes - nf_tables ruleset generation attributes
+ *
+ * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32)
+ */
+enum nft_gen_attributes {
+ NFTA_GEN_UNSPEC,
+ NFTA_GEN_ID,
+ __NFTA_GEN_MAX
+};
+#define NFTA_GEN_MAX (__NFTA_GEN_MAX - 1)
+
#endif /* _LINUX_NF_TABLES_H */
diff --git a/include/mnl.h b/include/mnl.h
index ed5a718b..03d1876e 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -6,6 +6,7 @@
struct mnl_socket;
uint32_t mnl_seqnum_alloc(void);
+void mnl_genid_get(struct mnl_socket *nf_sock);
struct mnl_err {
struct list_head head;
diff --git a/include/netlink.h b/include/netlink.h
index 2df37422..4f794707 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -138,6 +138,7 @@ extern void netlink_dump_set(struct nft_set *nls);
extern int netlink_batch_send(struct list_head *err_list);
+extern void netlink_genid_get(void);
extern void netlink_restart(void);
#define netlink_abi_error() \
__netlink_abi_error(__FILE__, __LINE__, strerror(errno));
diff --git a/src/main.c b/src/main.c
index 04a98e35..2685b0db 100644
--- a/src/main.c
+++ b/src/main.c
@@ -173,6 +173,7 @@ static int nft_netlink(struct parser_state *state, struct list_head *msgs)
bool batch_supported = netlink_batch_supported();
int ret = 0;
+ netlink_genid_get();
mnl_batch_init();
batch_seqnum = mnl_batch_begin();
diff --git a/src/mnl.c b/src/mnl.c
index febf7c23..b01e91c2 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -22,6 +22,7 @@
#include <mnl.h>
#include <string.h>
+#include <arpa/inet.h>
#include <errno.h>
#include <utils.h>
#include <nftables.h>
@@ -81,6 +82,41 @@ nft_mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
}
/*
+ * Rule-set consistency check across several netlink dumps
+ */
+static uint16_t nft_genid;
+
+static int genid_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
+
+ nft_genid = ntohs(nfh->res_id);
+
+ return MNL_CB_OK;
+}
+
+void mnl_genid_get(struct mnl_socket *nf_sock)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+
+ nlh = nft_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, AF_UNSPEC, 0, seq);
+ /* Skip error checking, old kernels sets res_id field to zero. */
+ nft_mnl_talk(nf_sock, nlh, nlh->nlmsg_len, genid_cb, NULL);
+}
+
+static int check_genid(const struct nlmsghdr *nlh)
+{
+ struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
+
+ if (nft_genid != ntohs(nfh->res_id)) {
+ errno = EINTR;
+ return -1;
+ }
+ return 0;
+}
+
+/*
* Batching
*/
@@ -387,6 +423,9 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
struct nft_rule_list *nlr_list = data;
struct nft_rule *r;
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
r = nft_rule_alloc();
if (r == NULL)
memory_allocation_error();
@@ -494,6 +533,9 @@ static int chain_cb(const struct nlmsghdr *nlh, void *data)
struct nft_chain_list *nlc_list = data;
struct nft_chain *c;
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
c = nft_chain_alloc();
if (c == NULL)
memory_allocation_error();
@@ -619,6 +661,9 @@ static int table_cb(const struct nlmsghdr *nlh, void *data)
struct nft_table_list *nlt_list = data;
struct nft_table *t;
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
t = nft_table_alloc();
if (t == NULL)
memory_allocation_error();
@@ -750,6 +795,9 @@ static int set_cb(const struct nlmsghdr *nlh, void *data)
struct nft_set_list *nls_list = data;
struct nft_set *s;
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
s = nft_set_alloc();
if (s == NULL)
memory_allocation_error();
@@ -864,6 +912,9 @@ int mnl_nft_setelem_delete(struct mnl_socket *nf_sock, struct nft_set *nls,
static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
{
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
nft_set_elems_nlmsg_parse(nlh, data);
return MNL_CB_OK;
}
diff --git a/src/netlink.c b/src/netlink.c
index 84d5db3c..17b82ee8 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -75,6 +75,11 @@ void netlink_restart(void)
netlink_open_sock();
}
+void netlink_genid_get(void)
+{
+ mnl_genid_get(nf_sock);
+}
+
static void netlink_open_mon_sock(void)
{
nf_mon_sock = nfsock_open();