diff options
-rw-r--r-- | include/linux/netfilter/nf_tables.h | 16 | ||||
-rw-r--r-- | include/mnl.h | 1 | ||||
-rw-r--r-- | include/netlink.h | 1 | ||||
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/mnl.c | 51 | ||||
-rw-r--r-- | src/netlink.c | 5 |
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)); @@ -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(); @@ -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(); |