]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
mnl: consistency checks across several netlink dumps
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 16 Sep 2014 16:58:11 +0000 (18:58 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 19 Sep 2014 12:57:11 +0000 (14:57 +0200)
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>
include/linux/netfilter/nf_tables.h
include/mnl.h
include/netlink.h
src/main.c
src/mnl.c
src/netlink.c

index 66d66dd3ff7995a2f6c7103072c59c088320007f..b72ccfeaf86527e12b61230597798d1cb902f949 100644 (file)
@@ -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 */
index ed5a718bef07dd2066ed0f6f7da6e646bf912af7..03d1876e5947c2d6cfc093da20f9efc7087234eb 100644 (file)
@@ -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;
index 2df374223572e76f35fd85d51d8d96bc00cef493..4f7947074471646cad2c545bbb1461ae10c95477 100644 (file)
@@ -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));
index 04a98e3553610228437d9709d4289691be91433a..2685b0db8a95326f774562cf8ad0a9254c37f639 100644 (file)
@@ -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();
index febf7c2309c6210513abb7c234c936cd154036b5..b01e91c246f885987f839871ccee9814a44afaa8 100644 (file)
--- 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>
@@ -80,6 +81,41 @@ nft_mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
        return nft_mnl_recv(nf_sock, seq, portid, cb, cb_data);
 }
 
+/*
+ * 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;
 }
index 84d5db3c8c5a116aaa3cd8f507b1d2fee1fa91ea..17b82ee88d650be8508ab56a72ea04d7e1ebd1a6 100644 (file)
@@ -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();