summaryrefslogtreecommitdiffstats
path: root/src/mnl.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-09-16 18:58:11 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2014-09-19 14:57:11 +0200
commit01b27b6d961d548c25f0fc185fd05fc3d2380080 (patch)
treee51fbb12e49e7f31ce6340a30d13f226e51ddb76 /src/mnl.c
parent8c41f0bff62ba2eb0b3651b65a59511fb38c4947 (diff)
mnl: consistency checks across several netlink dumps
Obtain the generation ID before dumping the object lists. Then, check for generation ID updates when dumping the several lists that this needs. In case of interference, nft has to remove the stale objects and retry from scratch. This is complementary to the NLM_F_DUMP_INTR flag which is local to one single netlink dump. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/mnl.c')
-rw-r--r--src/mnl.c51
1 files changed, 51 insertions, 0 deletions
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;
}