diff mbox

[nft-sync,2/3] mnl: sync source code with nft

Message ID 20141226125127.16382.40927.stgit@nfdev.cica.es
State Changes Requested
Delegated to: Pablo Neira
Headers show

Commit Message

Arturo Borrero Dec. 26, 2014, 12:51 p.m. UTC
Let's update the mnl source code to match the latest in nft.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
 include/linux/netfilter/nf_tables.h |  125 +++++++++++++++++++++-
 include/mnl.h                       |    2 
 include/utils.h                     |    9 ++
 src/main.c                          |    2 
 src/mnl.c                           |  198 ++++++++++++++++++++++-------------
 src/utils.c                         |    7 +
 6 files changed, 261 insertions(+), 82 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Pablo Neira Ayuso Jan. 5, 2015, 11:29 a.m. UTC | #1
On Fri, Dec 26, 2014 at 01:51:28PM +0100, Arturo Borrero Gonzalez wrote:
> Let's update the mnl source code to match the latest in nft.

Please, split this in smaller patches, it's good to keep track of the
git history when looking at the past.

> Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
> ---
>  include/linux/netfilter/nf_tables.h |  125 +++++++++++++++++++++-
>  include/mnl.h                       |    2 
>  include/utils.h                     |    9 ++
>  src/main.c                          |    2 
>  src/mnl.c                           |  198 ++++++++++++++++++++++-------------
>  src/utils.c                         |    7 +
>  6 files changed, 261 insertions(+), 82 deletions(-)
> 
> diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> index 11d5937..832bc46 100644
> --- a/include/linux/netfilter/nf_tables.h
> +++ b/include/linux/netfilter/nf_tables.h
[...]

At least this one should come in an initial patch to refresh the
cached header.

We should also start abstracting and moving things to the library in a
way that nft-sync can reuse, so we avoid code redundancy.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arturo Borrero Jan. 5, 2015, 12:17 p.m. UTC | #2
On 5 January 2015 at 12:29, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>
> We should also start abstracting and moving things to the library in a
> way that nft-sync can reuse, so we avoid code redundancy.

Ok, I like that path.

I tried it once (a patch series called mnlio, some time ago). I will
try again :-)
diff mbox

Patch

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 11d5937..832bc46 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1,7 +1,8 @@ 
 #ifndef _LINUX_NF_TABLES_H
 #define _LINUX_NF_TABLES_H
 
-#define NFT_CHAIN_MAXNAMELEN 32
+#define NFT_CHAIN_MAXNAMELEN	32
+#define NFT_USERDATA_MAXLEN	256
 
 enum nft_registers {
 	NFT_REG_VERDICT,
@@ -50,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,
@@ -67,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,
 };
 
@@ -156,6 +161,7 @@  enum nft_chain_attributes {
  * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
  * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
  * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
+ * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
  */
 enum nft_rule_attributes {
 	NFTA_RULE_UNSPEC,
@@ -165,6 +171,7 @@  enum nft_rule_attributes {
 	NFTA_RULE_EXPRESSIONS,
 	NFTA_RULE_COMPAT,
 	NFTA_RULE_POSITION,
+	NFTA_RULE_USERDATA,
 	__NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX		(__NFTA_RULE_MAX - 1)
@@ -209,6 +216,29 @@  enum nft_set_flags {
 };
 
 /**
+ * enum nft_set_policies - set selection policy
+ *
+ * @NFT_SET_POL_PERFORMANCE: prefer high performance over low memory use
+ * @NFT_SET_POL_MEMORY: prefer low memory use over high performance
+ */
+enum nft_set_policies {
+	NFT_SET_POL_PERFORMANCE,
+	NFT_SET_POL_MEMORY,
+};
+
+/**
+ * enum nft_set_desc_attributes - set element description
+ *
+ * @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
+ */
+enum nft_set_desc_attributes {
+	NFTA_SET_DESC_UNSPEC,
+	NFTA_SET_DESC_SIZE,
+	__NFTA_SET_DESC_MAX
+};
+#define NFTA_SET_DESC_MAX	(__NFTA_SET_DESC_MAX - 1)
+
+/**
  * enum nft_set_attributes - nf_tables set netlink attributes
  *
  * @NFTA_SET_TABLE: table name (NLA_STRING)
@@ -218,6 +248,9 @@  enum nft_set_flags {
  * @NFTA_SET_KEY_LEN: key data length (NLA_U32)
  * @NFTA_SET_DATA_TYPE: mapping data type (NLA_U32)
  * @NFTA_SET_DATA_LEN: mapping data length (NLA_U32)
+ * @NFTA_SET_POLICY: selection policy (NLA_U32)
+ * @NFTA_SET_DESC: set description (NLA_NESTED)
+ * @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
  */
 enum nft_set_attributes {
 	NFTA_SET_UNSPEC,
@@ -228,6 +261,9 @@  enum nft_set_attributes {
 	NFTA_SET_KEY_LEN,
 	NFTA_SET_DATA_TYPE,
 	NFTA_SET_DATA_LEN,
+	NFTA_SET_POLICY,
+	NFTA_SET_DESC,
+	NFTA_SET_ID,
 	__NFTA_SET_MAX
 };
 #define NFTA_SET_MAX		(__NFTA_SET_MAX - 1)
@@ -263,12 +299,14 @@  enum nft_set_elem_attributes {
  * @NFTA_SET_ELEM_LIST_TABLE: table of the set to be changed (NLA_STRING)
  * @NFTA_SET_ELEM_LIST_SET: name of the set to be changed (NLA_STRING)
  * @NFTA_SET_ELEM_LIST_ELEMENTS: list of set elements (NLA_NESTED: nft_set_elem_attributes)
+ * @NFTA_SET_ELEM_LIST_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
  */
 enum nft_set_elem_list_attributes {
 	NFTA_SET_ELEM_LIST_UNSPEC,
 	NFTA_SET_ELEM_LIST_TABLE,
 	NFTA_SET_ELEM_LIST_SET,
 	NFTA_SET_ELEM_LIST_ELEMENTS,
+	NFTA_SET_ELEM_LIST_SET_ID,
 	__NFTA_SET_ELEM_LIST_MAX
 };
 #define NFTA_SET_ELEM_LIST_MAX	(__NFTA_SET_ELEM_LIST_MAX - 1)
@@ -454,12 +492,14 @@  enum nft_cmp_attributes {
  * @NFTA_LOOKUP_SET: name of the set where to look for (NLA_STRING)
  * @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers)
  * @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_LOOKUP_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
  */
 enum nft_lookup_attributes {
 	NFTA_LOOKUP_UNSPEC,
 	NFTA_LOOKUP_SET,
 	NFTA_LOOKUP_SREG,
 	NFTA_LOOKUP_DREG,
+	NFTA_LOOKUP_SET_ID,
 	__NFTA_LOOKUP_MAX
 };
 #define NFTA_LOOKUP_MAX		(__NFTA_LOOKUP_MAX - 1)
@@ -535,6 +575,11 @@  enum nft_exthdr_attributes {
  * @NFT_META_L4PROTO: layer 4 protocol number
  * @NFT_META_BRI_IIFNAME: packet input bridge interface name
  * @NFT_META_BRI_OIFNAME: packet output bridge interface name
+ * @NFT_META_PKTTYPE: packet type (skb->pkt_type), special handling for loopback
+ * @NFT_META_CPU: cpu id through smp_processor_id()
+ * @NFT_META_IIFGROUP: packet input interface group
+ * @NFT_META_OIFGROUP: packet output interface group
+ * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid)
  */
 enum nft_meta_keys {
 	NFT_META_LEN,
@@ -556,6 +601,11 @@  enum nft_meta_keys {
 	NFT_META_L4PROTO,
 	NFT_META_BRI_IIFNAME,
 	NFT_META_BRI_OIFNAME,
+	NFT_META_PKTTYPE,
+	NFT_META_CPU,
+	NFT_META_IIFGROUP,
+	NFT_META_OIFGROUP,
+	NFT_META_CGROUP,
 };
 
 /**
@@ -590,7 +640,6 @@  enum nft_meta_attributes {
  * @NFT_CT_PROTOCOL: conntrack layer 4 protocol
  * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
  * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
- * @NFT_CT_LABELS: conntrack label bitset (stored in conntrack extension)
  */
 enum nft_ct_keys {
 	NFT_CT_STATE,
@@ -606,7 +655,7 @@  enum nft_ct_keys {
 	NFT_CT_PROTOCOL,
 	NFT_CT_PROTO_SRC,
 	NFT_CT_PROTO_DST,
-	NFT_CT_LABEL,
+	NFT_CT_LABELS,
 };
 
 /**
@@ -615,12 +664,14 @@  enum nft_ct_keys {
  * @NFTA_CT_DREG: destination register (NLA_U32)
  * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys)
  * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8)
+ * @NFTA_CT_SREG: source register (NLA_U32)
  */
 enum nft_ct_attributes {
 	NFTA_CT_UNSPEC,
 	NFTA_CT_DREG,
 	NFTA_CT_KEY,
 	NFTA_CT_DIRECTION,
+	NFTA_CT_SREG,
 	__NFTA_CT_MAX
 };
 #define NFTA_CT_MAX		(__NFTA_CT_MAX - 1)
@@ -660,6 +711,8 @@  enum nft_counter_attributes {
  * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING)
  * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32)
  * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32)
+ * @NFTA_LOG_LEVEL: log level (NLA_U32)
+ * @NFTA_LOG_FLAGS: logging flags (NLA_U32)
  */
 enum nft_log_attributes {
 	NFTA_LOG_UNSPEC,
@@ -667,6 +720,8 @@  enum nft_log_attributes {
 	NFTA_LOG_PREFIX,
 	NFTA_LOG_SNAPLEN,
 	NFTA_LOG_QTHRESHOLD,
+	NFTA_LOG_LEVEL,
+	NFTA_LOG_FLAGS,
 	__NFTA_LOG_MAX
 };
 #define NFTA_LOG_MAX		(__NFTA_LOG_MAX - 1)
@@ -696,11 +751,32 @@  enum nft_queue_attributes {
  *
  * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
  * @NFT_REJECT_TCP_RST: reject using TCP RST
+ * @NFT_REJECT_ICMPX_UNREACH: abstracted ICMP unreachable for bridge and inet
  */
 enum nft_reject_types {
 	NFT_REJECT_ICMP_UNREACH,
 	NFT_REJECT_TCP_RST,
+	NFT_REJECT_ICMPX_UNREACH,
+};
+
+/**
+ * enum nft_reject_code - Generic reject codes for IPv4/IPv6
+ *
+ * @NFT_REJECT_ICMPX_NO_ROUTE: no route to host / network unreachable
+ * @NFT_REJECT_ICMPX_PORT_UNREACH: port unreachable
+ * @NFT_REJECT_ICMPX_HOST_UNREACH: host unreachable
+ * @NFT_REJECT_ICMPX_ADMIN_PROHIBITED: administratively prohibited
+ *
+ * These codes are mapped to real ICMP and ICMPv6 codes.
+ */
+enum nft_reject_inet_code {
+	NFT_REJECT_ICMPX_NO_ROUTE	= 0,
+	NFT_REJECT_ICMPX_PORT_UNREACH,
+	NFT_REJECT_ICMPX_HOST_UNREACH,
+	NFT_REJECT_ICMPX_ADMIN_PROHIBITED,
+	__NFT_REJECT_ICMPX_MAX
 };
+#define NFT_REJECT_ICMPX_MAX	(__NFT_REJECT_ICMPX_MAX - 1)
 
 /**
  * enum nft_reject_attributes - nf_tables reject expression netlink attributes
@@ -736,6 +812,7 @@  enum nft_nat_types {
  * @NFTA_NAT_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
  * @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
  * @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ * @NFTA_NAT_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
  */
 enum nft_nat_attributes {
 	NFTA_NAT_UNSPEC,
@@ -745,19 +822,49 @@  enum nft_nat_attributes {
 	NFTA_NAT_REG_ADDR_MAX,
 	NFTA_NAT_REG_PROTO_MIN,
 	NFTA_NAT_REG_PROTO_MAX,
+	NFTA_NAT_FLAGS,
 	__NFTA_NAT_MAX
 };
 #define NFTA_NAT_MAX		(__NFTA_NAT_MAX - 1)
 
 /**
- * enum nft_nfacct_attributes - nf_tables nfacct expression netlink attributes
+ * enum nft_masq_attributes - nf_tables masquerade expression attributes
+ *
+ * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
+ */
+enum nft_masq_attributes {
+	NFTA_MASQ_UNSPEC,
+	NFTA_MASQ_FLAGS,
+	__NFTA_MASQ_MAX
+};
+#define NFTA_MASQ_MAX		(__NFTA_MASQ_MAX - 1)
+
+/**
+ * enum nft_redir_attributes - nf_tables redirect expression netlink attributes
+ *
+ * @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_REDIR_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ * @NFTA_REDIR_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
+ */
+enum nft_redir_attributes {
+	NFTA_REDIR_UNSPEC,
+	NFTA_REDIR_REG_PROTO_MIN,
+	NFTA_REDIR_REG_PROTO_MAX,
+	NFTA_REDIR_FLAGS,
+	__NFTA_REDIR_MAX
+};
+#define NFTA_REDIR_MAX		(__NFTA_REDIR_MAX - 1)
+
+/**
+ * enum nft_gen_attributes - nf_tables ruleset generation attributes
  *
- * @NFTA_NFACCT_NAME: nfacct object name (NLA_STRING)
+ * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32)
  */
-enum nft_nfacct_attributes {
-	NFTA_NFACCT_NAME,
-	__NFTA_NFACCT_MAX,
+enum nft_gen_attributes {
+	NFTA_GEN_UNSPEC,
+	NFTA_GEN_ID,
+	__NFTA_GEN_MAX
 };
-#define NFTA_NFACCT_MAX		(__NFTA_NFACCT_MAX -1)
+#define NFTA_GEN_MAX		(__NFTA_GEN_MAX - 1)
 
 #endif /* _LINUX_NF_TABLES_H */
diff --git a/include/mnl.h b/include/mnl.h
index cd146bd..db409c4 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -11,6 +11,8 @@ 
 
 #include "config.h"
 
+void mnl_genid_get(struct mnl_socket *nf_sock);
+
 struct nft_rule_list *mnl_rule_dump(struct mnl_socket *nf_sock, int family);
 struct nft_chain_list *mnl_chain_dump(struct mnl_socket *nf_sock,  int family);
 struct nft_table_list *mnl_table_dump(struct mnl_socket *nf_sock, int family);
diff --git a/include/utils.h b/include/utils.h
index 8d0eb38..d6be446 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -1,7 +1,16 @@ 
 #ifndef _UTILS_H_
 #define _UTILS_H_
 
+#include <stdint.h>
+
+#define __noreturn		__attribute__((__noreturn__))
+
 void xfree(const void *ptr);
 
+void __memory_allocation_error(const char *filename, uint32_t line) __noreturn;
+
+#define memory_allocation_error()		\
+	__memory_allocation_error(__FILE__, __LINE__);
+
 #endif /* _UTILS_H_ */
 
diff --git a/src/main.c b/src/main.c
index 0e6a8bc..e8f2dab 100644
--- a/src/main.c
+++ b/src/main.c
@@ -108,6 +108,8 @@  int main(int argc, char *argv[])
 			goto err;
 		}
 
+		mnl_genid_get(nfts_inst.nl_query_sock);
+
 		nfts_log(NFTS_LOG_INFO, "listening at %s",
 			 inet_ntoa(nfts_inst.tcp.server.ipv4.inet_addr));
 	}
diff --git a/src/mnl.c b/src/mnl.c
index 3bb3ade..65ac4ea 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -14,27 +14,36 @@ 
 
 #include <errno.h>
 #include <stdlib.h>
+#include <fcntl.h>
 
+#include "utils.h"
 #include "mnl.h"
 #include "linux/netfilter/nf_tables.h"
 #include "linux/netfilter.h"
+#include <linux/netfilter/nfnetlink.h>
+#include <libnftnl/ruleset.h>
+#include <libnftnl/common.h>
 
 static int seq;
 
+/* The largest nf_tables netlink message is the set element message, which
+ * contains the NFTA_SET_ELEM_LIST_ELEMENTS attribute. This attribute is
+ * a nest that describes the set elements. Given that the netlink attribute
+ * length (nla_len) is 16 bits, the largest message is a bit larger than
+ * 64 KBytes.
+ */
+#define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
+
 static int
-nfts_mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
+nfts_mnl_recv(struct mnl_socket *nf_sock, uint32_t seqnum, uint32_t portid,
 	      int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
 {
-	char buf[MNL_SOCKET_BUFFER_SIZE];
-	uint32_t portid = mnl_socket_get_portid(nf_sock);
+	char buf[NFT_NLMSG_MAXSIZE];
 	int ret;
 
-	if (mnl_socket_sendto(nf_sock, data, len) < 0)
-		return -1;
-
 	ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
 	while (ret > 0) {
-		ret = mnl_cb_run(buf, ret, seq, portid, cb, cb_data);
+		ret = mnl_cb_run(buf, ret, seqnum, portid, cb, cb_data);
 		if (ret <= 0)
 			goto out;
 
@@ -47,6 +56,53 @@  out:
 	return ret;
 }
 
+static int
+nfts_mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
+	      int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
+{
+	uint32_t portid = mnl_socket_get_portid(nf_sock);
+
+	if (mnl_socket_sendto(nf_sock, data, len) < 0)
+		return -1;
+
+	return nfts_mnl_recv(nf_sock, seq, portid, cb, cb_data);
+}
+
+/*
+ * Rule-set consistency check across several netlink dumps
+ */
+static uint16_t nfts_genid;
+
+static int genid_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
+
+	nfts_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. */
+	nfts_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 (nfts_genid != ntohs(nfh->res_id)) {
+		errno = EINTR;
+		return -1;
+	}
+	return 0;
+}
+
 /*
  * Rule
  */
@@ -55,9 +111,12 @@  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)
-		return -1;
+		memory_allocation_error();
 
 	if (nft_rule_nlmsg_parse(nlh, r) < 0)
 		goto err_free;
@@ -102,9 +161,12 @@  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)
-		return -1;
+		memory_allocation_error();
 
 	if (nft_chain_nlmsg_parse(nlh, c) < 0)
 		goto err_free;
@@ -150,9 +212,12 @@  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)
-		return -1;
+		memory_allocation_error();
 
 	if (nft_table_nlmsg_parse(nlh, t) < 0)
 		goto err_free;
@@ -174,7 +239,7 @@  struct nft_table_list *mnl_table_dump(struct mnl_socket *nf_sock, int family)
 
 	nlt_list = nft_table_list_alloc();
 	if (nlt_list == NULL)
-		return NULL;
+		memory_allocation_error();
 
 	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family,
 					NLM_F_DUMP, seq);
@@ -198,9 +263,12 @@  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)
-		return -1;
+		memory_allocation_error();
 
 	if (nft_set_nlmsg_parse(nlh, s) < 0)
 		goto err_free;
@@ -228,7 +296,10 @@  mnl_set_dump(struct mnl_socket *nf_sock, int family, const char *table)
 
 	nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
 				      NLM_F_DUMP|NLM_F_ACK, seq);
-	nft_set_attr_set(s, NFT_SET_ATTR_TABLE, table);
+
+	if (table != NULL)
+		nft_set_attr_set(s, NFT_SET_ATTR_TABLE, table);
+
 	nft_set_nlmsg_build_payload(nlh, s);
 	nft_set_free(s);
 
@@ -246,32 +317,15 @@  err:
 	return NULL;
 }
 
-static void
-nft_set_list_merge(struct nft_set_list *dest, struct nft_set_list *orig)
-{
-	struct nft_set_list_iter *it;
-	struct nft_set *o;
-
-	it = nft_set_list_iter_create(orig);
-	if (it == NULL)
-		return;
-
-	o = nft_set_list_iter_next(it);
-	while (o != NULL) {
-		nft_set_list_add_tail(o, dest);
-		o = nft_set_list_iter_next(it);
-	}
-
-	nft_set_list_iter_destroy(it);
-}
-
-
 /*
  * Set elements
  */
 
 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;
 }
@@ -296,61 +350,57 @@  int mnl_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls)
 struct nft_ruleset *mnl_ruleset_dump(struct mnl_socket *nf_sock)
 {
 	struct nft_ruleset *rs;
-	struct nft_rule_list *r;
-	struct nft_chain_list *c;
-	struct nft_set_list *complete_set_list = NULL, *s;
 	struct nft_table_list *t;
-	struct nft_table_list_iter *it;
-	struct nft_table *o;
-	const char *table;
-	uint16_t family;
-
-	t = mnl_table_dump(nf_sock, NFPROTO_UNSPEC);
-	if (t == NULL)
-		return NULL;
+	struct nft_chain_list *c;
+	struct nft_set_list *sl;
+	struct nft_set_list_iter *i;
+	struct nft_set *s;
+	struct nft_rule_list *r;
+	int ret = 0;
 
 	rs = nft_ruleset_alloc();
 	if (rs == NULL)
-		return NULL;
+		memory_allocation_error();
+
+	t = mnl_table_dump(nf_sock, NFPROTO_UNSPEC);
+	if (t == NULL)
+		goto err;
 
 	nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST, t);
 
 	c = mnl_chain_dump(nf_sock, NFPROTO_UNSPEC);
-	if (c != NULL)
-		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST, c);
-
-	r = mnl_rule_dump(nf_sock, NFPROTO_UNSPEC);
-	if (r != NULL)
-		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, r);
+	if (c == NULL)
+		goto err;
 
-	it = nft_table_list_iter_create(t);
-	if (it == NULL)
-		return NULL;
+	nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST, c);
 
-	o = nft_table_list_iter_next(it);
-	while (o != NULL) {
-		table = nft_table_attr_get_str(o, NFT_TABLE_ATTR_NAME);
-		family = nft_table_attr_get_u32(o, NFT_TABLE_ATTR_FAMILY);
+	sl = mnl_set_dump(nf_sock, NFPROTO_UNSPEC, NULL);
+	if (sl == NULL)
+		goto err;
 
-		s = mnl_set_dump(nf_sock, family, table);
-		if (s != NULL) {
-			if (complete_set_list == NULL) {
-				complete_set_list = nft_set_list_alloc();
-				if (complete_set_list == NULL)
-					return NULL;
-			}
+	i = nft_set_list_iter_create(sl);
+	s = nft_set_list_iter_next(i);
+	while (s != NULL) {
+		ret = mnl_setelem_get(nf_sock, s);
+		if (ret < 0)
+			goto err;
 
-			nft_set_list_merge(complete_set_list, s);
-		}
-		o = nft_table_list_iter_next(it);
+		s = nft_set_list_iter_next(i);
 	}
-	nft_table_list_iter_destroy(it);
+	nft_set_list_iter_destroy(i);
+
+	nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, sl);
+
+	r = mnl_rule_dump(nf_sock, NFPROTO_UNSPEC);
+	if (r == NULL)
+		goto err;
 
-	if (complete_set_list != NULL)
-		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST,
-				     complete_set_list);
+	nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, r);
 
 	return rs;
+err:
+	nft_ruleset_free(rs);
+	return NULL;
 }
 
 /*
@@ -365,7 +415,9 @@  int nfts_socket_open(struct nft_sync_inst *inst)
 {
 	struct mnl_socket *s = netlink_socket_open();
 	if (s == NULL)
-		return -1;
+		memory_allocation_error();
+
+	fcntl(mnl_socket_get_fd(s), F_SETFL, O_NONBLOCK);
 
 	inst->nl_query_sock = s;
 	return 0;
diff --git a/src/utils.c b/src/utils.c
index f1886c4..da1e6ae 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -8,6 +8,7 @@ 
  */
 
 #include <stdlib.h>
+#include <stdio.h>
 
 #include "utils.h"
 
@@ -15,3 +16,9 @@  void xfree(const void *ptr)
 {
 	free((void *)ptr);
 }
+
+void __noreturn __memory_allocation_error(const char *filename, uint32_t line)
+{
+	fprintf(stderr, "%s:%u: Memory allocation failure\n", filename, line);
+	exit(EXIT_FAILURE);
+}