diff mbox series

[iptables] iptables-compat: handle netlink dump EINTR errors

Message ID 20180424140727.16737-1-pablo@netfilter.org
State Accepted
Delegated to: Pablo Neira
Headers show
Series [iptables] iptables-compat: handle netlink dump EINTR errors | expand

Commit Message

Pablo Neira Ayuso April 24, 2018, 2:07 p.m. UTC
Cancel existing list and restart in case that netlink dump hits EINTR.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 iptables/nft.c | 41 +++++++++++++++++++++++++++++++++++++++--
 iptables/nft.h |  1 +
 2 files changed, 40 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/iptables/nft.c b/iptables/nft.c
index b3d9646d5d7c..d4b1a9f80603 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -761,6 +761,22 @@  err:
 	return ret;
 }
 
+int nft_restart(struct nft_handle *h)
+{
+	mnl_socket_close(h->nl);
+
+	h->nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (h->nl == NULL)
+		return -1;
+
+	if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
+		return -1;
+
+	h->portid = mnl_socket_get_portid(h->nl);
+
+	return 0;
+}
+
 int nft_init(struct nft_handle *h, struct builtin_table *t)
 {
 	h->nl = mnl_socket_open(NETLINK_NETFILTER);
@@ -1191,7 +1207,9 @@  static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h)
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nlmsghdr *nlh;
 	struct nftnl_chain_list *list;
+	int ret;
 
+retry:
 	list = nftnl_chain_list_alloc();
 	if (list == NULL) {
 		errno = ENOMEM;
@@ -1201,7 +1219,12 @@  static struct nftnl_chain_list *nftnl_chain_list_get(struct nft_handle *h)
 	nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
 					NLM_F_DUMP, h->seq);
 
-	mnl_talk(h, nlh, nftnl_chain_list_cb, list);
+	ret = mnl_talk(h, nlh, nftnl_chain_list_cb, list);
+	if (ret < 0 && errno == EINTR) {
+		nft_restart(h);
+		nftnl_chain_list_free(list);
+		goto retry;
+	}
 
 	return list;
 }
@@ -1299,6 +1322,7 @@  static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
 	if (h->rule_cache)
 		return h->rule_cache;
 
+retry:
 	list = nftnl_rule_list_alloc();
 	if (list == NULL)
 		return 0;
@@ -1308,6 +1332,12 @@  static struct nftnl_rule_list *nft_rule_list_get(struct nft_handle *h)
 
 	ret = mnl_talk(h, nlh, nftnl_rule_list_cb, list);
 	if (ret < 0) {
+		if (errno == EINTR) {
+			nft_restart(h);
+			nftnl_rule_list_free(list);
+			goto retry;
+		}
+
 		nftnl_rule_list_free(list);
 		return NULL;
 	}
@@ -1658,7 +1688,9 @@  static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nlmsghdr *nlh;
 	struct nftnl_table_list *list;
+	int ret;
 
+retry:
 	list = nftnl_table_list_alloc();
 	if (list == NULL)
 		return 0;
@@ -1666,7 +1698,12 @@  static struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)
 	nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
 					NLM_F_DUMP, h->seq);
 
-	mnl_talk(h, nlh, nftnl_table_list_cb, list);
+	ret = mnl_talk(h, nlh, nftnl_table_list_cb, list);
+	if (ret < 0 && errno == EINTR) {
+		nft_restart(h);
+		nftnl_table_list_free(list);
+		goto retry;
+	}
 
 	return list;
 }
diff --git a/iptables/nft.h b/iptables/nft.h
index 310cedeca730..e72255811c8f 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -49,6 +49,7 @@  int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
 	     void *data);
 int nft_init(struct nft_handle *h, struct builtin_table *t);
 void nft_fini(struct nft_handle *h);
+int nft_restart(struct nft_handle *h);
 
 /*
  * Operations with tables.