Blame SOURCES/bz1508435-load-ip-tables-handling.patch

cead2e
From dd9a0db422716dd9bbc329a6e2f23ee3d55d2008 Mon Sep 17 00:00:00 2001
cead2e
From: Quentin Armitage <quentin@armitage.org.uk>
cead2e
Date: Mon, 27 Mar 2017 11:26:44 +0100
cead2e
Subject: [PATCH 1/3] Handle not being able to load ip_tables or ip6_tables
cead2e
 modules
cead2e
cead2e
When running in a docker container it isn't possible to load kernel
cead2e
modules, so we need to cleanly handle a failure to load the modules.
cead2e
cead2e
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
cead2e
---
cead2e
 keepalived/core/global_data.c            |   2 -
cead2e
 keepalived/include/global_data.h         |   2 -
cead2e
 keepalived/include/vrrp.h                |   5 +
cead2e
 keepalived/include/vrrp_ipset.h          |   4 +-
cead2e
 keepalived/include/vrrp_iptables.h       |   7 +-
cead2e
 keepalived/include/vrrp_iptables_calls.h |   2 +-
cead2e
 keepalived/vrrp/vrrp.c                   |  53 ++++++--
cead2e
 keepalived/vrrp/vrrp_daemon.c            |  13 +-
cead2e
 keepalived/vrrp/vrrp_ipaddress.c         | 137 ++++++++++++++++---
cead2e
 keepalived/vrrp/vrrp_ipset.c             |  73 +++++++---
cead2e
 keepalived/vrrp/vrrp_iptables.c          | 225 +++++++++++++++++++------------
cead2e
 keepalived/vrrp/vrrp_iptables_calls.c    | 108 +++++++--------
cead2e
 12 files changed, 421 insertions(+), 210 deletions(-)
cead2e
cead2e
diff --git a/keepalived/core/global_data.c b/keepalived/core/global_data.c
cead2e
index d934f286..21c06c1c 100644
cead2e
--- a/keepalived/core/global_data.c
cead2e
+++ b/keepalived/core/global_data.c
cead2e
@@ -98,8 +98,6 @@ set_vrrp_defaults(data_t * data)
cead2e
 	data->vrrp_higher_prio_send_advert = false;
cead2e
 	data->vrrp_version = VRRP_VERSION_2;
cead2e
 	strcpy(data->vrrp_iptables_inchain, "INPUT");
cead2e
-	data->block_ipv4 = false;
cead2e
-	data->block_ipv6 = false;
cead2e
 #ifdef _HAVE_LIBIPSET_
cead2e
 	data->using_ipsets = true;
cead2e
 	strcpy(data->vrrp_ipset_address, "keepalived");
cead2e
diff --git a/keepalived/include/global_data.h b/keepalived/include/global_data.h
cead2e
index 6547ddac..eea34f75 100644
cead2e
--- a/keepalived/include/global_data.h
cead2e
+++ b/keepalived/include/global_data.h
cead2e
@@ -99,8 +99,6 @@ typedef struct _data {
cead2e
 	int				vrrp_version;	/* VRRP version (2 or 3) */
cead2e
 	char				vrrp_iptables_inchain[XT_EXTENSION_MAXNAMELEN];
cead2e
 	char				vrrp_iptables_outchain[XT_EXTENSION_MAXNAMELEN];
cead2e
-	bool				block_ipv4;
cead2e
-	bool				block_ipv6;
cead2e
 #ifdef _HAVE_LIBIPSET_
cead2e
 	bool				using_ipsets;
cead2e
 	char				vrrp_ipset_address[IPSET_MAXNAMELEN];
cead2e
diff --git a/keepalived/include/vrrp.h b/keepalived/include/vrrp.h
cead2e
index 6e874689..ab757277 100644
cead2e
--- a/keepalived/include/vrrp.h
cead2e
+++ b/keepalived/include/vrrp.h
cead2e
@@ -313,6 +313,10 @@ typedef struct _vrrp_t {
cead2e
 
cead2e
 #define VRRP_ISUP(V)		(VRRP_IF_ISUP(V) && VRRP_SCRIPT_ISUP(V))
cead2e
 
cead2e
+/* Global variables */
cead2e
+extern bool block_ipv4;
cead2e
+extern bool block_ipv6;
cead2e
+
cead2e
 /* prototypes */
cead2e
 extern vrrphdr_t *vrrp_get_header(sa_family_t, char *, unsigned *);
cead2e
 extern int open_vrrp_send_socket(sa_family_t, int, ifindex_t, bool);
cead2e
@@ -327,6 +331,7 @@ extern void vrrp_state_backup(vrrp_t *, char *, ssize_t);
cead2e
 extern void vrrp_state_goto_master(vrrp_t *);
cead2e
 extern void vrrp_state_leave_master(vrrp_t *);
cead2e
 extern bool vrrp_complete_init(void);
cead2e
+extern void vrrp_restore_interfaces_startup(void);
cead2e
 extern void restore_vrrp_interfaces(void);
cead2e
 extern void shutdown_vrrp_instances(void);
cead2e
 extern void clear_diff_vrrp(void);
cead2e
diff --git a/keepalived/include/vrrp_ipset.h b/keepalived/include/vrrp_ipset.h
cead2e
index 9ee1095a..6cc320ef 100644
cead2e
--- a/keepalived/include/vrrp_ipset.h
cead2e
+++ b/keepalived/include/vrrp_ipset.h
cead2e
@@ -27,8 +27,8 @@
cead2e
 #include <libipset/session.h>
cead2e
 #include "vrrp_ipaddress.h"
cead2e
 
cead2e
-int add_ipsets(bool);
cead2e
-int remove_ipsets(void);
cead2e
+bool add_ipsets(bool);
cead2e
+bool remove_ipsets(void);
cead2e
 bool has_ipset_setname(struct ipset_session*, const char *);
cead2e
 bool ipset_init(void);
cead2e
 struct ipset_session* ipset_session_start(void);
cead2e
diff --git a/keepalived/include/vrrp_iptables.h b/keepalived/include/vrrp_iptables.h
cead2e
index 2a7681b3..dbbd6fe7 100644
cead2e
--- a/keepalived/include/vrrp_iptables.h
cead2e
+++ b/keepalived/include/vrrp_iptables.h
cead2e
@@ -37,12 +37,11 @@ struct ipt_handle;
cead2e
 #define	IPTABLES_MAX_TRIES	3	/* How many times to try adding/deleting when get EAGAIN */
cead2e
 
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
-extern bool using_libiptc;		/* Set if using libiptc - for dynamic linking */
cead2e
+extern bool using_libip4tc;		/* Set if using lib4iptc - for dynamic linking */
cead2e
+extern bool using_libip6tc;		/* Set if using lib4iptc - for dynamic linking */
cead2e
 #endif
cead2e
-extern bool use_ip4tables;		/* Set if using iptables */
cead2e
-extern bool use_ip6tables;		/* Set if using ip6tables */
cead2e
 
cead2e
-bool iptables_init_lib(void);
cead2e
+void iptables_init_lib(void);
cead2e
 void iptables_fini(void);
cead2e
 void iptables_startup(bool);
cead2e
 void iptables_cleanup(void);
cead2e
diff --git a/keepalived/include/vrrp_iptables_calls.h b/keepalived/include/vrrp_iptables_calls.h
cead2e
index 34052fac..ef4e0183 100644
cead2e
--- a/keepalived/include/vrrp_iptables_calls.h
cead2e
+++ b/keepalived/include/vrrp_iptables_calls.h
cead2e
@@ -34,7 +34,6 @@
cead2e
 
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
 #ifdef _LIBXTABLES_DYNAMIC_ 
cead2e
-extern bool xtables_load(void);
cead2e
 extern void xtables_unload(void);
cead2e
 #endif
cead2e
 extern bool load_xtables_module(const char *, const char *);
cead2e
@@ -50,6 +49,7 @@ extern int ip6tables_is_chain(struct ip6tc_handle* handle, const char* chain_nam
cead2e
 extern int ip6tables_process_entry( struct ip6tc_handle* handle, const char* chain_name, unsigned int rulenum, const char* target_name, const ip_address_t* src_ip_address, const ip_address_t* dst_ip_address, const char* in_iface, const char* out_iface, uint16_t protocol, uint8_t type, int cmd, bool force);
cead2e
 extern int ip4tables_add_rules(struct iptc_handle* handle, const char* chain_name, unsigned int rulenum, uint8_t dim, uint8_t src_dst, const char* target_name, const char* set_name, uint16_t protocol, uint8_t param, int cmd, bool ignore_errors);
cead2e
 extern int ip6tables_add_rules(struct ip6tc_handle* handle, const char* chain_name, unsigned int rulenum, uint8_t dim, uint8_t src_dst, const char* target_name, const char* set_name, uint16_t protocol, uint8_t param, int cmd, bool ignore_errors);
cead2e
+extern void check_chains_exist_lib(void);
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
 extern bool iptables_lib_init(void);
cead2e
 #endif
cead2e
diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c
cead2e
index 3d2bfe41..38895af8 100644
cead2e
--- a/keepalived/vrrp/vrrp.c
cead2e
+++ b/keepalived/vrrp/vrrp.c
cead2e
@@ -72,6 +72,10 @@
cead2e
 #include <netinet/ip6.h>
cead2e
 #include <stdint.h>
cead2e
 
cead2e
+/* Set if need to block ip addresses and are able to do so */
cead2e
+bool block_ipv4;
cead2e
+bool block_ipv6;
cead2e
+
cead2e
 /* add/remove Virtual IP addresses */
cead2e
 static bool
cead2e
 vrrp_handle_ipaddress(vrrp_t * vrrp, int cmd, int type)
cead2e
@@ -124,7 +128,11 @@ vrrp_handle_accept_mode(vrrp_t *vrrp, int cmd, bool force)
cead2e
 
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
 		do {
cead2e
-			h = iptables_open();
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+			if ((vrrp->family == AF_INET && using_libip4tc) ||
cead2e
+			    (vrrp->family == AF_INET6 && using_libip6tc))
cead2e
+#endif
cead2e
+				h = iptables_open();
cead2e
 #endif
cead2e
 			/* As accept is false, add iptable rule to drop packets destinated to VIPs and eVIPs */
cead2e
 			if (!LIST_ISEMPTY(vrrp->vip))
cead2e
@@ -132,7 +140,10 @@ vrrp_handle_accept_mode(vrrp_t *vrrp, int cmd, bool force)
cead2e
 			if (!LIST_ISEMPTY(vrrp->evip))
cead2e
 				handle_iptable_rule_to_iplist(h, vrrp->evip, cmd, force);
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
-			res = iptables_close(h);
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+			if (h)
cead2e
+#endif
cead2e
+				res = iptables_close(h);
cead2e
 		} while (res == EAGAIN && ++tries < IPTABLES_MAX_TRIES);
cead2e
 #endif
cead2e
 		vrrp->iptable_rules_set = (cmd == IPADDRESS_ADD);
cead2e
@@ -2363,10 +2374,12 @@ vrrp_complete_instance(vrrp_t * vrrp)
cead2e
 	if (vrrp->base_priority != VRRP_PRIO_OWNER && !vrrp->accept) {
cead2e
 //TODO = we have a problem since SNMP may change accept mode
cead2e
 //it can also change priority
cead2e
-		if (vrrp->saddr.ss_family == AF_INET)
cead2e
-			global_data->block_ipv4 = true;
cead2e
+		if (!global_data->vrrp_iptables_inchain[0])
cead2e
+			log_message(LOG_INFO, "(%s): Unable to set no_accept mode since iptables chain name unset", vrrp->iname);
cead2e
+		else if (vrrp->family == AF_INET)
cead2e
+			block_ipv4 = true;
cead2e
 		else
cead2e
-			global_data->block_ipv6 = true;
cead2e
+			block_ipv6 = true;
cead2e
 	}
cead2e
 	if (!LIST_ISEMPTY(vrrp->vip)) {
cead2e
 		for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
cead2e
@@ -2390,7 +2403,6 @@ vrrp_complete_instance(vrrp_t * vrrp)
cead2e
 	if (!reload && interface_already_existed) {
cead2e
 // TODO - consider reload
cead2e
 		vrrp->vipset = true;	/* Set to force address removal */
cead2e
-		vrrp_restore_interface(vrrp, false, true);
cead2e
 	}
cead2e
 
cead2e
 	/* See if we need to set promote_secondaries */
cead2e
@@ -2452,12 +2464,6 @@ vrrp_complete_init(void)
cead2e
 	if (global_data->vrrp_garp_interval || global_data->vrrp_gna_interval)
cead2e
 		set_default_garp_delay();
cead2e
 
cead2e
-#ifdef _HAVE_LIBIPTC_
cead2e
-	/* Make sure we don't have any old iptables/ipsets settings left around */
cead2e
-	if (!reload)
cead2e
-		iptables_cleanup();
cead2e
-#endif
cead2e
-
cead2e
 	/* Mark any scripts as insecure */
cead2e
 	check_vrrp_script_security();
cead2e
 
cead2e
@@ -2623,6 +2629,18 @@ vrrp_complete_init(void)
cead2e
 	return true;
cead2e
 }
cead2e
 
cead2e
+void vrrp_restore_interfaces_startup(void)
cead2e
+{
cead2e
+	element e;
cead2e
+	vrrp_t *vrrp;
cead2e
+
cead2e
+	for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) {
cead2e
+		vrrp = ELEMENT_DATA(e);
cead2e
+		if (vrrp->vipset)
cead2e
+			vrrp_restore_interface(vrrp, false, true);
cead2e
+	}
cead2e
+}
cead2e
+
cead2e
 /* Try to find a VRRP instance */
cead2e
 static vrrp_t *
cead2e
 vrrp_exist(vrrp_t *old_vrrp)
cead2e
@@ -2690,12 +2708,19 @@ clear_diff_vrrp_vip(vrrp_t *old_vrrp, vrrp_t *vrrp)
cead2e
 
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
 	do {
cead2e
-		h = iptables_open();
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		if ((vrrp->family == AF_INET && using_libip4tc) ||
cead2e
+		    (vrrp->family == AF_INET6 && using_libip6tc))
cead2e
+#endif
cead2e
+			h = iptables_open();
cead2e
 #endif
cead2e
 		clear_diff_vrrp_vip_list(vrrp, h, old_vrrp->vip, vrrp->vip);
cead2e
 		clear_diff_vrrp_vip_list(vrrp, h, old_vrrp->evip, vrrp->evip);
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
-		res = iptables_close(h);
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		if (h)
cead2e
+#endif
cead2e
+			res = iptables_close(h);
cead2e
 	} while (res == EAGAIN && ++tries < IPTABLES_MAX_TRIES);
cead2e
 #endif
cead2e
 }
cead2e
diff --git a/keepalived/vrrp/vrrp_daemon.c b/keepalived/vrrp/vrrp_daemon.c
cead2e
index 1c2f9e89..1e9282a7 100644
cead2e
--- a/keepalived/vrrp/vrrp_daemon.c
cead2e
+++ b/keepalived/vrrp/vrrp_daemon.c
cead2e
@@ -202,8 +202,6 @@ start_vrrp(void)
cead2e
 	if (global_data->vrrp_no_swap)
cead2e
 		set_process_dont_swap(4096);	/* guess a stack size to reserve */
cead2e
 
cead2e
-	iptables_init();
cead2e
-
cead2e
 #ifdef _WITH_SNMP_
cead2e
 	if (!reload && (global_data->enable_snmp_keepalived || global_data->enable_snmp_rfcv2 || global_data->enable_snmp_rfcv3)) {
cead2e
 		vrrp_snmp_agent_init(global_data->snmp_socket);
cead2e
@@ -266,10 +264,21 @@ start_vrrp(void)
cead2e
 		return;
cead2e
 	}
cead2e
 
cead2e
+	/* We need to delay the init of iptables to after vrrp_complete_init()
cead2e
+	 * has been called so we know whether we want IPv4 and/or IPv6 */
cead2e
+	iptables_init();
cead2e
+
cead2e
+	/* Make sure we don't have any old iptables/ipsets settings left around */
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
+	if (!reload)
cead2e
+		iptables_cleanup();
cead2e
+
cead2e
 	iptables_startup(reload);
cead2e
 #endif
cead2e
 
cead2e
+	if (!reload)
cead2e
+		vrrp_restore_interfaces_startup();
cead2e
+
cead2e
 	/* clear_diff_vrrp must be called after vrrp_complete_init, since the latter
cead2e
 	 * sets ifa_index on the addresses, which is used for the address comparison */
cead2e
 	if (reload)
cead2e
diff --git a/keepalived/vrrp/vrrp_ipaddress.c b/keepalived/vrrp/vrrp_ipaddress.c
cead2e
index eb332e72..c72ea736 100644
cead2e
--- a/keepalived/vrrp/vrrp_ipaddress.c
cead2e
+++ b/keepalived/vrrp/vrrp_ipaddress.c
cead2e
@@ -27,6 +27,7 @@
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
 #include "vrrp_iptables.h"
cead2e
 #endif
cead2e
+#include "vrrp.h"
cead2e
 #include "keepalived_netlink.h"
cead2e
 #include "vrrp_data.h"
cead2e
 #include "logger.h"
cead2e
@@ -38,11 +39,16 @@
cead2e
 #if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
cead2e
 #include "utils.h"
cead2e
 #endif
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+#include "vrrp_iptables.h"
cead2e
+#endif
cead2e
 
cead2e
 #define INFINITY_LIFE_TIME      0xFFFFFFFF
cead2e
 
cead2e
-bool iptables_cmd_available = true;
cead2e
-bool ip6tables_cmd_available = true;
cead2e
+#if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
cead2e
+static bool iptables_cmd_available;
cead2e
+static bool ip6tables_cmd_available;
cead2e
+#endif
cead2e
 
cead2e
 char *
cead2e
 ipaddresstos(char *buf, ip_address_t *ipaddress)
cead2e
@@ -250,9 +256,6 @@ handle_iptable_rule_to_vip_cmd(ip_address_t *ipaddress, int cmd, bool force)
cead2e
 	char *addr_str;
cead2e
 	char *ifname = NULL;
cead2e
 
cead2e
-	if (global_data->vrrp_iptables_inchain[0] == '\0')
cead2e
-		return;
cead2e
-
cead2e
 	if (IP_IS6(ipaddress)) {
cead2e
 		if (!ip6tables_cmd_available)
cead2e
 			return;
cead2e
@@ -316,9 +319,18 @@ handle_iptable_rule_to_vip(ip_address_t *ipaddr, int cmd,
cead2e
 #endif
cead2e
 												   bool force)
cead2e
 {
cead2e
+	if (IP_IS6(ipaddr)) {
cead2e
+		if (!block_ipv6)
cead2e
+			return;
cead2e
+	} else {
cead2e
+		if (!block_ipv4)
cead2e
+			return;
cead2e
+	}
cead2e
+
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
-	if (using_libiptc)
cead2e
+	if ((IP_IS6(ipaddr) && using_libip6tc) ||
cead2e
+	    (!IP_IS6(ipaddr) && using_libip4tc))
cead2e
 #endif
cead2e
 	{
cead2e
 		handle_iptable_rule_to_vip_lib(ipaddr, cmd, h, force);
cead2e
@@ -612,31 +624,122 @@ clear_diff_saddresses(void)
cead2e
 	clear_diff_address(NULL, old_vrrp_data->static_addresses, vrrp_data->static_addresses);
cead2e
 }
cead2e
 
cead2e
+static void
cead2e
+check_chains_exist(void)
cead2e
+{
cead2e
+#ifdef _HAVE_LIBIPTC_
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+	if (using_libip4tc || using_libip6tc)
cead2e
+#endif
cead2e
+		check_chains_exist_lib();
cead2e
+#endif
cead2e
+
cead2e
+#if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
cead2e
+	char *argv[4];
cead2e
+
cead2e
+	argv[1] = "-nL";
cead2e
+	argv[2] = global_data->vrrp_iptables_inchain;
cead2e
+	argv[3] = NULL;
cead2e
+
cead2e
+	if (block_ipv4)
cead2e
+	{
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		if (!using_libip4tc)
cead2e
+#endif
cead2e
+		{
cead2e
+			argv[0] = "iptables";
cead2e
+
cead2e
+			if (fork_exec(argv) < 0) {
cead2e
+				log_message(LOG_INFO, "iptables chain %s does not exist", global_data->vrrp_iptables_inchain);
cead2e
+				block_ipv4 = false;
cead2e
+			}
cead2e
+			else if (global_data->vrrp_iptables_outchain[0]) {
cead2e
+				argv[2] = global_data->vrrp_iptables_outchain;
cead2e
+				if (fork_exec(argv) < 0) {
cead2e
+					log_message(LOG_INFO, "iptables chain %s does not exist", global_data->vrrp_iptables_outchain);
cead2e
+					block_ipv4 = false;
cead2e
+				}
cead2e
+			}
cead2e
+		}
cead2e
+	}
cead2e
+
cead2e
+	if (block_ipv6)
cead2e
+	{
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		if (!using_libip6tc)
cead2e
+#endif
cead2e
+		{
cead2e
+			argv[0] = "ip6tables";
cead2e
+			argv[2] = global_data->vrrp_iptables_inchain;
cead2e
+
cead2e
+			if (fork_exec(argv) < 0) {
cead2e
+				log_message(LOG_INFO, "ip6tables chain %s does not exist", global_data->vrrp_iptables_inchain);
cead2e
+				block_ipv6 = false;
cead2e
+			}
cead2e
+			else if (global_data->vrrp_iptables_outchain[0]) {
cead2e
+				argv[2] = global_data->vrrp_iptables_outchain;
cead2e
+				if (fork_exec(argv) < 0) {
cead2e
+					log_message(LOG_INFO, "ip6tables chain %s does not exist", global_data->vrrp_iptables_outchain);
cead2e
+					block_ipv6 = false;
cead2e
+				}
cead2e
+			}
cead2e
+		}
cead2e
+	}
cead2e
+#endif
cead2e
+}
cead2e
+
cead2e
 void
cead2e
 iptables_init(void)
cead2e
 {
cead2e
-#ifdef _HAVE_LIBIPTC_
cead2e
-	if (iptables_init_lib())
cead2e
+	if (!block_ipv4 && !block_ipv6) {
cead2e
+#ifdef _HAVE_LIBIPSET_
cead2e
+		global_data->using_ipsets = false;
cead2e
+#endif
cead2e
 		return;
cead2e
+	}
cead2e
+
cead2e
+#ifdef _HAVE_LIBIPTC_
cead2e
+	iptables_init_lib();
cead2e
 #endif
cead2e
 
cead2e
 #if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
cead2e
 	char *argv[3];
cead2e
 
cead2e
-	/* We can't use libiptc, so check iptables command available */
cead2e
-	argv[0] = "iptables";
cead2e
+	/* If can't use libiptc, check iptables command available */
cead2e
 	argv[1] = "-V";
cead2e
 	argv[2] = NULL;
cead2e
 
cead2e
-	if (fork_exec(argv) < 0) {
cead2e
-		log_message(LOG_INFO, "iptables command not available - can't filter IPv4 VIP address destinations");
cead2e
-		iptables_cmd_available = false;
cead2e
+	if (block_ipv4
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		       && !using_libip4tc
cead2e
+#endif
cead2e
+				       )
cead2e
+	{
cead2e
+		argv[0] = "iptables";
cead2e
+		if (!(iptables_cmd_available = (fork_exec(argv) >= 0))) {
cead2e
+			log_message(LOG_INFO, "iptables command not available - can't filter IPv4 VIP address destinations");
cead2e
+			block_ipv4 = false;
cead2e
+		}
cead2e
 	}
cead2e
 
cead2e
-	argv[0] = "ip6tables";
cead2e
-	if (fork_exec(argv) < 0) {
cead2e
-		log_message(LOG_INFO, "ip6tables command not available - can't filter IPv6 VIP address destinations");
cead2e
-		ip6tables_cmd_available = false;
cead2e
+	if (block_ipv6
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		       && !using_libip6tc
cead2e
+#endif
cead2e
+					 )
cead2e
+	{
cead2e
+		argv[0] = "ip6tables";
cead2e
+		if (!(ip6tables_cmd_available = (fork_exec(argv) >= 0))) {
cead2e
+			log_message(LOG_INFO, "ip6tables command not available - can't filter IPv6 VIP address destinations");
cead2e
+			block_ipv6 = false;
cead2e
+		}
cead2e
 	}
cead2e
 #endif
cead2e
+
cead2e
+	if (block_ipv4 || block_ipv6)
cead2e
+		check_chains_exist();
cead2e
+#ifdef _HAVE_LIBIPSET_
cead2e
+	else
cead2e
+		global_data->using_ipsets = false;
cead2e
+#endif
cead2e
 }
cead2e
diff --git a/keepalived/vrrp/vrrp_ipset.c b/keepalived/vrrp/vrrp_ipset.c
cead2e
index 194809f0..1c3e4990 100644
cead2e
--- a/keepalived/vrrp/vrrp_ipset.c
cead2e
+++ b/keepalived/vrrp/vrrp_ipset.c
cead2e
@@ -38,12 +38,14 @@
cead2e
 #include <linux/types.h>        /* For __beXX types in userland */
cead2e
 #include <linux/netfilter.h>    /* For nf_inet_addr */
cead2e
 #include <stdint.h>
cead2e
+#include <stdio.h>
cead2e
 
cead2e
 #include "logger.h"
cead2e
 #include "global_data.h"
cead2e
 #include "vrrp_iptables.h"
cead2e
 #include "vrrp_ipset.h"
cead2e
 #include "vrrp_ipaddress.h"
cead2e
+#include "vrrp.h"
cead2e
 #include "main.h"
cead2e
 
cead2e
 #ifdef _LIBIPSET_DYNAMIC_
cead2e
@@ -146,7 +148,7 @@ has_ipset_setname(struct ipset_session* session, const char *setname)
cead2e
 	return ipset_cmd1(session, IPSET_CMD_HEADER, 0) == 0;
cead2e
 }
cead2e
 
cead2e
-static int create_sets(const char* addr4, const char* addr6, const char* addr_if6, bool reload)
cead2e
+static bool create_sets(const char* addr4, const char* addr6, const char* addr_if6, bool reload)
cead2e
 {
cead2e
 	struct ipset_session *session;
cead2e
 
cead2e
@@ -161,12 +163,12 @@ static int create_sets(const char* addr4, const char* addr6, const char* addr_if
cead2e
 	if (!reload)
cead2e
 		ipset_envopt_parse(session, IPSET_ENV_EXIST, NULL);
cead2e
 
cead2e
-	if (use_ip4tables) {
cead2e
+	if (block_ipv4) {
cead2e
 		if (!reload || !has_ipset_setname(session, addr4))
cead2e
 			ipset_create(session, addr4, "hash:ip", NFPROTO_IPV4);
cead2e
 	}
cead2e
 
cead2e
-	if (use_ip6tables) {
cead2e
+	if (block_ipv6) {
cead2e
 		if (!reload || !has_ipset_setname(session, addr6))
cead2e
 			ipset_create(session, addr6, "hash:ip", NFPROTO_IPV6);
cead2e
 		if (!reload || !has_ipset_setname(session, addr_if6)) {
cead2e
@@ -184,6 +186,30 @@ static int create_sets(const char* addr4, const char* addr6, const char* addr_if
cead2e
 	return true;
cead2e
 }
cead2e
 
cead2e
+static
cead2e
+bool set_match_loaded(void)
cead2e
+{
cead2e
+	char buf[XT_FUNCTION_MAXNAMELEN+1];
cead2e
+	FILE *fp;
cead2e
+	bool found = false;
cead2e
+
cead2e
+	fp = fopen( "/proc/net/ip_tables_matches", "r");
cead2e
+	if (!fp)
cead2e
+		return false;
cead2e
+
cead2e
+	while (fgets(buf, sizeof(buf), fp)) {
cead2e
+		if ((buf[3] == '\0' || buf[3] == '\n') &&
cead2e
+		    !strncmp(buf, "set", 3)) {
cead2e
+			found = true;
cead2e
+			break;
cead2e
+		}
cead2e
+	}
cead2e
+
cead2e
+	fclose(fp);
cead2e
+
cead2e
+	return found;
cead2e
+}
cead2e
+
cead2e
 bool ipset_init(void)
cead2e
 {
cead2e
 #ifdef _LIBIPSET_DYNAMIC_
cead2e
@@ -213,44 +239,47 @@ bool ipset_init(void)
cead2e
 		return false;
cead2e
 	}
cead2e
 
cead2e
-	int err = false;
cead2e
-	if (!(ipset_session_init_addr = dlsym(libipset_handle, "ipset_session_init"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_init"); err = true;}
cead2e
-	if (!(ipset_session_fini_addr = dlsym(libipset_handle, "ipset_session_fini"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_fini"); err = true;}
cead2e
-	if (!(ipset_session_data_addr = dlsym(libipset_handle,"ipset_session_data"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_data"); err = true;}
cead2e
-	if (!(ipset_session_error_addr = dlsym(libipset_handle,"ipset_session_error"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_error"); err = true;}
cead2e
-	if (!(ipset_envopt_parse_addr = dlsym(libipset_handle,"ipset_envopt_parse"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_envopt_parse"); err = true;}
cead2e
-	if (!(ipset_type_get_addr = dlsym(libipset_handle,"ipset_type_get"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_type_get"); err = true;}
cead2e
-	if (!(ipset_data_set_addr = dlsym(libipset_handle,"ipset_data_set"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_data_set"); err = true;}
cead2e
-	if (!(ipset_cmd_addr = dlsym(libipset_handle,"ipset_cmd"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_cmd"); err = true;}
cead2e
-	if (!(ipset_load_types_addr = dlsym(libipset_handle,"ipset_load_types"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_load_types"); err = true;}
cead2e
-	if (err) {
cead2e
-		log_message(LOG_INFO, "Failed to dynamic link an ipset function");
cead2e
+	if (!(ipset_session_init_addr = dlsym(libipset_handle, "ipset_session_init")) ||
cead2e
+	    !(ipset_session_fini_addr = dlsym(libipset_handle, "ipset_session_fini")) ||
cead2e
+	    !(ipset_session_data_addr = dlsym(libipset_handle,"ipset_session_data")) ||
cead2e
+	    !(ipset_session_error_addr = dlsym(libipset_handle,"ipset_session_error")) ||
cead2e
+	    !(ipset_envopt_parse_addr = dlsym(libipset_handle,"ipset_envopt_parse")) ||
cead2e
+	    !(ipset_type_get_addr = dlsym(libipset_handle,"ipset_type_get")) ||
cead2e
+	    !(ipset_data_set_addr = dlsym(libipset_handle,"ipset_data_set")) ||
cead2e
+	    !(ipset_cmd_addr = dlsym(libipset_handle,"ipset_cmd")) ||
cead2e
+	    !(ipset_load_types_addr = dlsym(libipset_handle,"ipset_load_types"))) {
cead2e
+		log_message(LOG_INFO, "Failed to dynamic link an ipset function - %s", dlerror());
cead2e
 		return false;
cead2e
 	}
cead2e
 #endif
cead2e
 
cead2e
 	ipset_load_types();
cead2e
 
cead2e
-	if (!load_xtables_module("xt_set", "ipsets"))
cead2e
+	if (!set_match_loaded() && !load_xtables_module("xt_set", "ipsets")) {
cead2e
+		log_message(LOG_INFO, "Unable to load module xt_set - not using ipsets");
cead2e
 		return false;
cead2e
+	}
cead2e
 
cead2e
 	return true;
cead2e
 }
cead2e
 
cead2e
-int remove_ipsets(void)
cead2e
+bool remove_ipsets(void)
cead2e
 {
cead2e
 	struct ipset_session *session;
cead2e
 
cead2e
+	if (!global_data->using_ipsets)
cead2e
+		return true;
cead2e
+
cead2e
 	session = ipset_session_init(printf);
cead2e
 	if (!session) {
cead2e
 		log_message(LOG_INFO, "Cannot initialize ipset session.");
cead2e
 		return false;
cead2e
 	}
cead2e
 
cead2e
-	if (use_ip4tables)
cead2e
+	if (block_ipv4)
cead2e
 		ipset_destroy(session, global_data->vrrp_ipset_address);
cead2e
 
cead2e
-	if (use_ip6tables) {
cead2e
+	if (block_ipv6) {
cead2e
 		ipset_destroy(session, global_data->vrrp_ipset_address6);
cead2e
 		ipset_destroy(session, global_data->vrrp_ipset_address_iface6);
cead2e
 	}
cead2e
@@ -260,7 +289,7 @@ int remove_ipsets(void)
cead2e
 	return true;
cead2e
 }
cead2e
 
cead2e
-int add_ipsets(bool reload)
cead2e
+bool add_ipsets(bool reload)
cead2e
 {
cead2e
 	return create_sets(global_data->vrrp_ipset_address, global_data->vrrp_ipset_address6, global_data->vrrp_ipset_address_iface6, reload);
cead2e
 }
cead2e
@@ -281,12 +310,12 @@ void ipset_entry(struct ipset_session* session, int cmd, const ip_address_t* add
cead2e
 	char *iface = NULL;
cead2e
 
cead2e
 	if (addr->ifa.ifa_family == AF_INET) {
cead2e
-		if (!use_ip4tables)
cead2e
+		if (!block_ipv4)
cead2e
 			return;
cead2e
 		set = global_data->vrrp_ipset_address;
cead2e
 	}
cead2e
 	else if (IN6_IS_ADDR_LINKLOCAL(&addr->u.sin6_addr)) {
cead2e
-		if (!use_ip6tables)
cead2e
+		if (!block_ipv6)
cead2e
 			return;
cead2e
 
cead2e
 		set = global_data->vrrp_ipset_address_iface6;
cead2e
diff --git a/keepalived/vrrp/vrrp_iptables.c b/keepalived/vrrp/vrrp_iptables.c
cead2e
index 2c218cac..60ff6c8c 100644
cead2e
--- a/keepalived/vrrp/vrrp_iptables.c
cead2e
+++ b/keepalived/vrrp/vrrp_iptables.c
cead2e
@@ -59,6 +59,10 @@
cead2e
 #include <xtables.h>
cead2e
 #include <libipset/linux_ip_set.h>
cead2e
 #endif
cead2e
+#include <sys/stat.h>
cead2e
+#include <sys/vfs.h>
cead2e
+#include <linux/magic.h>
cead2e
+#include <stdbool.h>
cead2e
 
cead2e
 #include "vrrp_iptables.h"
cead2e
 #include "vrrp_iptables_calls.h"
cead2e
@@ -81,10 +85,9 @@ struct ipt_handle {
cead2e
 
cead2e
 /* If the chains don't exist, or modules not loaded, we can't use iptables/ip6tables */
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
-bool using_libiptc = true;
cead2e
+bool using_libip4tc = false;
cead2e
+bool using_libip6tc = false;
cead2e
 #endif
cead2e
-bool use_ip4tables = true;
cead2e
-bool use_ip6tables = true;
cead2e
 
cead2e
 #ifdef _HAVE_LIBIPSET_
cead2e
 static
cead2e
@@ -105,10 +108,13 @@ void add_del_rules(int cmd, bool ignore_errors)
cead2e
 	struct iptc_handle *h4;
cead2e
 	struct ip6tc_handle *h6;
cead2e
 
cead2e
-	if (use_ip4tables &&
cead2e
-	    global_data->block_ipv4 &&
cead2e
+	if (block_ipv4 &&
cead2e
 	    (global_data->vrrp_iptables_inchain[0] ||
cead2e
-	     global_data->vrrp_iptables_outchain[0])) {
cead2e
+	     global_data->vrrp_iptables_outchain[0])
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+	    && using_libip4tc
cead2e
+#endif
cead2e
+			      ) {
cead2e
 		if ((h4 = ip4tables_open("filter"))) {
cead2e
 			if (global_data->vrrp_iptables_inchain[0])
cead2e
 				ip4tables_add_rules(h4, global_data->vrrp_iptables_inchain, APPEND_RULE, IPSET_DIM_ONE, 0, XTC_LABEL_DROP, global_data->vrrp_ipset_address, IPPROTO_NONE, 0, cmd, ignore_errors);
cead2e
@@ -118,10 +124,13 @@ void add_del_rules(int cmd, bool ignore_errors)
cead2e
 		}
cead2e
 	}
cead2e
 
cead2e
-	if (use_ip6tables &&
cead2e
-	    global_data->block_ipv6 &&
cead2e
+	if (block_ipv6 &&
cead2e
 	    (global_data->vrrp_iptables_inchain[0] ||
cead2e
-	     global_data->vrrp_iptables_outchain[0])) {
cead2e
+	     global_data->vrrp_iptables_outchain[0])
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+	    && using_libip6tc
cead2e
+#endif
cead2e
+			     ) {
cead2e
 		if ((h6 = ip6tables_open("filter"))) {
cead2e
 			if (global_data->vrrp_iptables_inchain[0]) {
cead2e
 #ifdef HAVE_IPSET_ATTR_IFACE
cead2e
@@ -185,58 +194,64 @@ int iptables_close(struct ipt_handle* h)
cead2e
 	return res;
cead2e
 }
cead2e
 
cead2e
-static void check_chains_exist(void)
cead2e
+void check_chains_exist_lib(void)
cead2e
 {
cead2e
 	struct iptc_handle *h4;
cead2e
 	struct ip6tc_handle *h6;
cead2e
 
cead2e
-	if (global_data->block_ipv4) {
cead2e
-		h4 = ip4tables_open("filter");
cead2e
-
cead2e
-		if (!h4) {
cead2e
-			log_message(LOG_INFO, "WARNING, ip_tables module not installed - can't filter IPv4 addresses");
cead2e
-			use_ip4tables = false;
cead2e
-		} else {
cead2e
-			if (global_data->vrrp_iptables_inchain[0] &&
cead2e
-			    !ip4tables_is_chain(h4, global_data->vrrp_iptables_inchain)) {
cead2e
-				log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
cead2e
-				use_ip4tables = false;
cead2e
-			}
cead2e
-			if (global_data->vrrp_iptables_outchain[0] &&
cead2e
-			    !ip4tables_is_chain(h4, global_data->vrrp_iptables_outchain)) {
cead2e
-				log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
cead2e
-				use_ip4tables = false;
cead2e
+	if (block_ipv4) {
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		if (using_libip4tc)
cead2e
+#endif
cead2e
+		{
cead2e
+			h4 = ip4tables_open("filter");
cead2e
+
cead2e
+			if (!h4) {
cead2e
+				log_message(LOG_INFO, "WARNING, ip_tables module not installed - can't filter IPv4 addresses");
cead2e
+				block_ipv4 = false;
cead2e
+			} else {
cead2e
+				if (global_data->vrrp_iptables_inchain[0] &&
cead2e
+				    !ip4tables_is_chain(h4, global_data->vrrp_iptables_inchain)) {
cead2e
+					log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
cead2e
+					block_ipv4 = false;
cead2e
+				}
cead2e
+				if (global_data->vrrp_iptables_outchain[0] &&
cead2e
+				    !ip4tables_is_chain(h4, global_data->vrrp_iptables_outchain)) {
cead2e
+					log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
cead2e
+					block_ipv4 = false;
cead2e
+				}
cead2e
+
cead2e
+				ip4tables_close(h4, false);
cead2e
 			}
cead2e
-
cead2e
-			ip4tables_close(h4, false);
cead2e
 		}
cead2e
 	}
cead2e
-	else
cead2e
-		use_ip4tables = false;
cead2e
-
cead2e
-	if (global_data->block_ipv6) {
cead2e
-		h6 = ip6tables_open("filter");
cead2e
-
cead2e
-		if (!h6) {
cead2e
-			log_message(LOG_INFO, "WARNING, ip6_tables module not installed - can't filter IPv6 addresses");
cead2e
-			use_ip6tables = false;
cead2e
-		} else {
cead2e
-			if (global_data->vrrp_iptables_inchain[0] &&
cead2e
-			    !ip6tables_is_chain(h6, global_data->vrrp_iptables_inchain)) {
cead2e
-				log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
cead2e
-				use_ip6tables = false;
cead2e
-			}
cead2e
-			if (global_data->vrrp_iptables_outchain[0] &&
cead2e
-			    !ip6tables_is_chain(h6, global_data->vrrp_iptables_outchain)) {
cead2e
-				log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
cead2e
-				use_ip6tables = false;
cead2e
-			}
cead2e
 
cead2e
-			ip6tables_close(h6, false);
cead2e
+	if (block_ipv6) {
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+		if (using_libip6tc)
cead2e
+#endif
cead2e
+		{
cead2e
+			h6 = ip6tables_open("filter");
cead2e
+
cead2e
+			if (!h6) {
cead2e
+				log_message(LOG_INFO, "WARNING, ip6_tables module not installed - can't filter IPv6 addresses");
cead2e
+				block_ipv6 = false;
cead2e
+			} else {
cead2e
+				if (global_data->vrrp_iptables_inchain[0] &&
cead2e
+				    !ip6tables_is_chain(h6, global_data->vrrp_iptables_inchain)) {
cead2e
+					log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
cead2e
+					block_ipv6 = false;
cead2e
+				}
cead2e
+				if (global_data->vrrp_iptables_outchain[0] &&
cead2e
+				    !ip6tables_is_chain(h6, global_data->vrrp_iptables_outchain)) {
cead2e
+					log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
cead2e
+					block_ipv6 = false;
cead2e
+				}
cead2e
+
cead2e
+				ip6tables_close(h6, false);
cead2e
+			}
cead2e
 		}
cead2e
 	}
cead2e
-	else
cead2e
-		use_ip6tables = false;
cead2e
 }
cead2e
 
cead2e
 static int iptables_entry(struct ipt_handle* h, const char* chain_name, unsigned int rulenum, char* target_name, const ip_address_t* src_ip_address, const ip_address_t* dst_ip_address, const char* in_iface, const char* out_iface, uint16_t protocol, uint8_t type, int cmd, bool force)
cead2e
@@ -303,11 +318,8 @@ handle_iptable_rule_to_vip_lib(ip_address_t *ipaddress, int cmd, struct ipt_hand
cead2e
 	char *ifname = NULL;
cead2e
 
cead2e
 	/* If iptables for the address family isn't in use, skip */
cead2e
-	if ((ipaddress->ifa.ifa_family == AF_INET && !use_ip4tables) ||
cead2e
-	    (ipaddress->ifa.ifa_family == AF_INET6 && !use_ip6tables))
cead2e
-		return;
cead2e
-
cead2e
-	if (global_data->vrrp_iptables_inchain[0] == '\0')
cead2e
+	if ((ipaddress->ifa.ifa_family == AF_INET && !block_ipv4) ||
cead2e
+	    (ipaddress->ifa.ifa_family == AF_INET6 && !block_ipv6))
cead2e
 		return;
cead2e
 
cead2e
 #ifdef _HAVE_LIBIPSET_
cead2e
@@ -343,33 +355,28 @@ handle_iptable_rule_to_vip_lib(ip_address_t *ipaddress, int cmd, struct ipt_hand
cead2e
 			IPPROTO_NONE, 0, cmd, force);
cead2e
 }
cead2e
 
cead2e
+#ifdef _HAVE_LIBIPSET_
cead2e
 static void
cead2e
-iptables_remove_structure(
cead2e
-#ifndef _HAVE_LIBIPSET_
cead2e
-			  __attribute__((unused))
cead2e
-#endif
cead2e
-						 bool ignore_errors)
cead2e
+iptables_remove_structure(bool ignore_errors)
cead2e
 {
cead2e
-#ifdef _HAVE_LIBIPSET_
cead2e
 	if (global_data->using_ipsets) {
cead2e
 		add_del_rules(IPADDRESS_DEL, ignore_errors);
cead2e
 		add_del_sets(IPADDRESS_DEL, false);
cead2e
 	}
cead2e
-#endif
cead2e
 }
cead2e
+#endif
cead2e
 
cead2e
 void
cead2e
-iptables_startup(bool reload)
cead2e
+iptables_startup(
cead2e
+#ifndef _HAVE_LIBIPSET_
cead2e
+		 __attribute__((unused))
cead2e
+#endif
cead2e
+					 bool reload)
cead2e
 {
cead2e
-	if (!reload) {
cead2e
-		check_chains_exist();
cead2e
 #ifdef _HAVE_LIBIPSET_
cead2e
-		if (!use_ip4tables && !use_ip6tables)
cead2e
-			global_data->using_ipsets = false;
cead2e
-#endif
cead2e
-	}
cead2e
+	if (!block_ipv4 && !block_ipv6)
cead2e
+		global_data->using_ipsets = false;
cead2e
 
cead2e
-#ifdef _HAVE_LIBIPSET_
cead2e
 	if (global_data->using_ipsets) {
cead2e
 		add_del_sets(IPADDRESS_ADD, reload);
cead2e
 		add_del_rules(IPADDRESS_ADD, false);
cead2e
@@ -380,50 +387,94 @@ iptables_startup(bool reload)
cead2e
 void
cead2e
 iptables_cleanup(void)
cead2e
 {
cead2e
+#ifdef _HAVE_LIBIPSET_
cead2e
 	iptables_remove_structure(true);
cead2e
+#endif
cead2e
+}
cead2e
+
cead2e
+/* return true if a given file exists within procfs */
cead2e
+/* Taken from iptables code */
cead2e
+static
cead2e
+bool proc_file_exists(const char *filename)
cead2e
+{
cead2e
+	struct stat s;
cead2e
+	struct statfs f;
cead2e
+
cead2e
+	if (lstat(filename, &s))
cead2e
+		return false;
cead2e
+	if (!S_ISREG(s.st_mode))
cead2e
+		return false;
cead2e
+	if (statfs(filename, &f))
cead2e
+		return false;
cead2e
+	if (f.f_type != PROC_SUPER_MAGIC)
cead2e
+		return false;
cead2e
+
cead2e
+	return true;
cead2e
 }
cead2e
 
cead2e
-bool
cead2e
+void
cead2e
 iptables_init_lib(void)
cead2e
 {
cead2e
-#ifdef _LIBXTABLES_DYNAMIC_
cead2e
-	xtables_load();
cead2e
+	if (block_ipv4) {
cead2e
+		if (!proc_file_exists("/proc/net/ip_tables_names") &&
cead2e
+		    !load_xtables_module("ip_tables", "iptables"))
cead2e
+#ifdef _LIBIPTC_DYNAMIC_
cead2e
+			using_libip4tc = false;
cead2e
+		else
cead2e
+			using_libip4tc = true;
cead2e
+#else
cead2e
+		{
cead2e
+			block_ipv4 = false;
cead2e
+			log_message(LOG_INFO, "Unable to load module ip_tables");
cead2e
+		}
cead2e
 #endif
cead2e
+	}
cead2e
 
cead2e
+	if (block_ipv6) {
cead2e
+		if (!proc_file_exists("/proc/net/ip6_tables_names") &&
cead2e
+		    !load_xtables_module("ip6_tables", "ip6tables"))
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
-	if (!iptables_lib_init()) {
cead2e
-		using_libiptc = false;
cead2e
-#ifdef _LIBXTABLES_DYNAMIC_
cead2e
-		xtables_unload();
cead2e
+			using_libip6tc = false;
cead2e
+		else
cead2e
+			using_libip6tc = true;
cead2e
+#else
cead2e
+		{
cead2e
+			block_ipv6 = false;
cead2e
+			log_message(LOG_INFO, "Unable to load module ip_tables");
cead2e
+		}
cead2e
 #endif
cead2e
-		return false;
cead2e
 	}
cead2e
-#endif
cead2e
 
cead2e
-	if (!load_xtables_module("ip_tables", "iptables")) {
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
-		using_libiptc = false;
cead2e
-#endif
cead2e
+	if ((!block_ipv4 && !block_ipv6) ||
cead2e
+	    (!using_libip4tc && !using_libip6tc) ||
cead2e
+	    !iptables_lib_init()) {
cead2e
 #ifdef _LIBXTABLES_DYNAMIC_
cead2e
 		xtables_unload();
cead2e
 #endif
cead2e
-		return false;
cead2e
+
cead2e
+#ifdef _HAVE_LIBIPSET_
cead2e
+		global_data->using_ipsets = false;
cead2e
+#endif
cead2e
+
cead2e
+		return;
cead2e
 	}
cead2e
+#endif
cead2e
 
cead2e
 #ifdef _HAVE_LIBIPSET_
cead2e
-	if (!ipset_init())
cead2e
+	if (global_data->using_ipsets && !ipset_init())
cead2e
 		global_data->using_ipsets = false;
cead2e
 #endif
cead2e
 
cead2e
 #ifdef _LIBXTABLES_DYNAMIC_
cead2e
 	xtables_unload();
cead2e
 #endif
cead2e
-
cead2e
-	return true;
cead2e
 }
cead2e
 
cead2e
 void
cead2e
 iptables_fini(void)
cead2e
 {
cead2e
+#ifdef _HAVE_LIBIPSET_
cead2e
 	iptables_remove_structure(false);
cead2e
+#endif
cead2e
 }
cead2e
diff --git a/keepalived/vrrp/vrrp_iptables_calls.c b/keepalived/vrrp/vrrp_iptables_calls.c
cead2e
index fb5c98df..ff6b7e6e 100644
cead2e
--- a/keepalived/vrrp/vrrp_iptables_calls.c
cead2e
+++ b/keepalived/vrrp/vrrp_iptables_calls.c
cead2e
@@ -37,22 +37,18 @@
cead2e
 #include <xtables.h>
cead2e
 #include <libiptc/libiptc.h>
cead2e
 #include <libiptc/libip6tc.h>
cead2e
-#ifdef _HAVE_LIBIPSET_
cead2e
 #include <libipset/linux_ip_set.h>
cead2e
 #if defined XT_SET_H_ADD_IP_SET_H_GUARD
cead2e
 #define _IP_SET_H
cead2e
 #elif defined XT_SET_H_ADD_UAPI_IP_SET_H_GUARD
cead2e
 #define _UAPI_IP_SET_H
cead2e
 #endif
cead2e
+#ifdef _HAVE_LIBIPSET_
cead2e
 #include <linux/netfilter/xt_set.h>
cead2e
 #endif
cead2e
 #include <unistd.h>
cead2e
 #include <signal.h>
cead2e
 #include <stdint.h>
cead2e
-#ifdef _LIBXTABLES_DYNAMIC_
cead2e
-#include <sys/types.h>
cead2e
-#include <sys/stat.h>
cead2e
-#endif
cead2e
 
cead2e
 #include "vrrp_iptables_calls.h"
cead2e
 #include "memory.h"
cead2e
@@ -63,6 +59,7 @@
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
 #include "global_data.h"
cead2e
 #endif
cead2e
+#include "vrrp_iptables.h"
cead2e
 
cead2e
 /* We sometimes get a resource_busy on iptc_commit. This appears to happen
cead2e
  * when someone else is also updating it.
cead2e
@@ -406,6 +403,7 @@ int ip6tables_process_entry( struct ip6tc_handle* handle, const char* chain_name
cead2e
 
cead2e
 #ifdef _HAVE_LIBIPTC_
cead2e
 #ifdef _LIBXTABLES_DYNAMIC_ 
cead2e
+static
cead2e
 bool xtables_load(void)
cead2e
 {
cead2e
 	if (libxtables_handle)
cead2e
@@ -418,7 +416,7 @@ bool xtables_load(void)
cead2e
 	}
cead2e
 
cead2e
 	if (!(xtables_insmod_addr = dlsym(libxtables_handle, "xtables_insmod"))) {
cead2e
-		log_message(LOG_INFO, "Failed to dynamic link xtables_insmod");
cead2e
+		log_message(LOG_INFO, "Failed to dynamic link xtables_insmod - %s", dlerror());
cead2e
 		dlclose(libxtables_handle);
cead2e
 		libxtables_handle = NULL;
cead2e
 
cead2e
@@ -438,25 +436,18 @@ void xtables_unload(void)
cead2e
 }
cead2e
 #endif
cead2e
 
cead2e
-bool load_xtables_module(const char *module,
cead2e
+bool
cead2e
+load_xtables_module(const char *module,
cead2e
 #ifndef _LIBXTABLES_DYNAMIC_
cead2e
-					    __attribute__((unused))
cead2e
+					__attribute__((unused))
cead2e
 #endif
cead2e
-								    const char *function)
cead2e
+								const char *function)
cead2e
 {
cead2e
 	struct sigaction act, old_act;
cead2e
 	bool res = true;
cead2e
-#ifdef _LIBXTABLES_DYNAMIC_
cead2e
-	struct stat stat_buf;
cead2e
-	char module_path[32] = "/sys/module/";
cead2e
-
cead2e
-	if (!libxtables_handle) {
cead2e
-		/* See if the module is loaded anyway */
cead2e
-		strcat(module_path, module);
cead2e
-		if (!stat(module_path, &stat_buf) &&
cead2e
-		    (stat_buf.st_mode & S_IFDIR))
cead2e
-			return true;
cead2e
 
cead2e
+#ifdef _LIBXTABLES_DYNAMIC_
cead2e
+	if (!libxtables_handle && !xtables_load()) {
cead2e
 		log_message(LOG_INFO, "Module %s cannot be loaded; not using %s", module, function);
cead2e
 		return false;
cead2e
 	}
cead2e
@@ -882,47 +873,50 @@ int ip6tables_add_rules(struct ip6tc_handle* handle, const char* chain_name, uns
cead2e
 #ifdef _LIBIPTC_DYNAMIC_
cead2e
 bool iptables_lib_init(void)
cead2e
 {
cead2e
-	if (libip4tc_handle)
cead2e
-		return true;
cead2e
-
cead2e
-	/* Attempt to open the ip4tc library */
cead2e
-	if (!(libip4tc_handle = dlopen("libip4tc.so", RTLD_NOW)) &&
cead2e
-	    !(libip4tc_handle = dlopen(IP4TC_LIB_NAME, RTLD_NOW))) {
cead2e
-		log_message(LOG_INFO, "Unable to load ip4tc library - %s", dlerror());
cead2e
-		return false;
cead2e
-	}
cead2e
-
cead2e
-	if (!(iptc_init_addr = dlsym(libip4tc_handle, "iptc_init")) ||
cead2e
-	    !(iptc_free_addr = dlsym(libip4tc_handle, "iptc_free")) ||
cead2e
-	    !(iptc_is_chain_addr = dlsym(libip4tc_handle,"iptc_is_chain")) ||
cead2e
-	    !(iptc_insert_entry_addr = dlsym(libip4tc_handle,"iptc_insert_entry")) ||
cead2e
-	    !(iptc_append_entry_addr = dlsym(libip4tc_handle,"iptc_append_entry")) ||
cead2e
-	    !(iptc_delete_entry_addr = dlsym(libip4tc_handle,"iptc_delete_entry")) ||
cead2e
-	    !(iptc_commit_addr = dlsym(libip4tc_handle,"iptc_commit")) ||
cead2e
-	    !(iptc_strerror_addr = dlsym(libip4tc_handle,"iptc_strerror")))
cead2e
-		log_message(LOG_INFO, "Failed to dynamic link an iptc function");
cead2e
-
cead2e
-	/* Attempt to open the ip6tc library */
cead2e
-	if (!(libip6tc_handle = dlopen("libip6tc.so", RTLD_NOW)) &&
cead2e
-	    !(libip6tc_handle = dlopen(IP6TC_LIB_NAME, RTLD_NOW))) {
cead2e
-		log_message(LOG_INFO, "Unable to load ip6tc library - %s", dlerror());
cead2e
-
cead2e
-		if (global_data->block_ipv4)
cead2e
+	if (!libip4tc_handle && block_ipv4) {
cead2e
+		/* Attempt to open the ip4tc library */
cead2e
+		if (!(libip4tc_handle = dlopen("libip4tc.so", RTLD_NOW)) &&
cead2e
+		    !(libip4tc_handle = dlopen(IP4TC_LIB_NAME, RTLD_NOW))) {
cead2e
+			log_message(LOG_INFO, "Unable to load ip4tc library - %s", dlerror());
cead2e
+			using_libip4tc = false;
cead2e
+		}
cead2e
+		else if (!(iptc_init_addr = dlsym(libip4tc_handle, "iptc_init")) ||
cead2e
+			 !(iptc_free_addr = dlsym(libip4tc_handle, "iptc_free")) ||
cead2e
+			 !(iptc_is_chain_addr = dlsym(libip4tc_handle,"iptc_is_chain")) ||
cead2e
+			 !(iptc_insert_entry_addr = dlsym(libip4tc_handle,"iptc_insert_entry")) ||
cead2e
+			 !(iptc_append_entry_addr = dlsym(libip4tc_handle,"iptc_append_entry")) ||
cead2e
+			 !(iptc_delete_entry_addr = dlsym(libip4tc_handle,"iptc_delete_entry")) ||
cead2e
+			 !(iptc_commit_addr = dlsym(libip4tc_handle,"iptc_commit")) ||
cead2e
+			 !(iptc_strerror_addr = dlsym(libip4tc_handle,"iptc_strerror"))) {
cead2e
+			log_message(LOG_INFO, "Failed to dynamic link an iptc function - %s", dlerror());
cead2e
+			using_libip4tc = false;
cead2e
 			dlclose(libip4tc_handle);
cead2e
-
cead2e
-		return false;
cead2e
+			libip4tc_handle = NULL;
cead2e
+		}
cead2e
 	}
cead2e
 
cead2e
-	if (!(ip6tc_init_addr = dlsym(libip6tc_handle, "ip6tc_init")) ||
cead2e
-	    !(ip6tc_free_addr = dlsym(libip6tc_handle, "ip6tc_free")) ||
cead2e
-	    !(ip6tc_is_chain_addr = dlsym(libip6tc_handle,"ip6tc_is_chain")) ||
cead2e
-	    !(ip6tc_insert_entry_addr = dlsym(libip6tc_handle,"ip6tc_insert_entry")) ||
cead2e
-	    !(ip6tc_append_entry_addr = dlsym(libip6tc_handle,"ip6tc_append_entry")) ||
cead2e
-	    !(ip6tc_delete_entry_addr = dlsym(libip6tc_handle,"ip6tc_delete_entry")) ||
cead2e
-	    !(ip6tc_commit_addr = dlsym(libip6tc_handle,"ip6tc_commit")) ||
cead2e
-	    !(ip6tc_strerror_addr = dlsym(libip6tc_handle,"ip6tc_strerror")))
cead2e
-		log_message(LOG_INFO, "Failed to dynamic link an ip6tc function");
cead2e
+	if (!libip6tc_handle && block_ipv6) {
cead2e
+		/* Attempt to open the ip6tc library */
cead2e
+		if (!(libip6tc_handle = dlopen("libip6tc.so", RTLD_NOW)) &&
cead2e
+		    !(libip6tc_handle = dlopen(IP6TC_LIB_NAME, RTLD_NOW))) {
cead2e
+			log_message(LOG_INFO, "Unable to load ip6tc library - %s", dlerror());
cead2e
+			using_libip6tc = false;
cead2e
+		}
cead2e
+		else if (!(ip6tc_init_addr = dlsym(libip6tc_handle, "ip6tc_init")) ||
cead2e
+			 !(ip6tc_free_addr = dlsym(libip6tc_handle, "ip6tc_free")) ||
cead2e
+			 !(ip6tc_is_chain_addr = dlsym(libip6tc_handle,"ip6tc_is_chain")) ||
cead2e
+			 !(ip6tc_insert_entry_addr = dlsym(libip6tc_handle,"ip6tc_insert_entry")) ||
cead2e
+			 !(ip6tc_append_entry_addr = dlsym(libip6tc_handle,"ip6tc_append_entry")) ||
cead2e
+			 !(ip6tc_delete_entry_addr = dlsym(libip6tc_handle,"ip6tc_delete_entry")) ||
cead2e
+			 !(ip6tc_commit_addr = dlsym(libip6tc_handle,"ip6tc_commit")) ||
cead2e
+			 !(ip6tc_strerror_addr = dlsym(libip6tc_handle,"ip6tc_strerror"))) {
cead2e
+			log_message(LOG_INFO, "Failed to dynamic link an ip6tc function - %s", dlerror());
cead2e
+			using_libip6tc = false;
cead2e
+			dlclose(libip6tc_handle);
cead2e
+			libip6tc_handle = NULL;
cead2e
+		}
cead2e
+	}
cead2e
 
cead2e
-	return true;
cead2e
+	return libip4tc_handle || libip6tc_handle;
cead2e
 }
cead2e
 #endif
cead2e
-- 
cead2e
2.13.5
cead2e