Blob Blame History Raw
From dd9a0db422716dd9bbc329a6e2f23ee3d55d2008 Mon Sep 17 00:00:00 2001
From: Quentin Armitage <quentin@armitage.org.uk>
Date: Mon, 27 Mar 2017 11:26:44 +0100
Subject: [PATCH 1/3] Handle not being able to load ip_tables or ip6_tables
 modules

When running in a docker container it isn't possible to load kernel
modules, so we need to cleanly handle a failure to load the modules.

Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
---
 keepalived/core/global_data.c            |   2 -
 keepalived/include/global_data.h         |   2 -
 keepalived/include/vrrp.h                |   5 +
 keepalived/include/vrrp_ipset.h          |   4 +-
 keepalived/include/vrrp_iptables.h       |   7 +-
 keepalived/include/vrrp_iptables_calls.h |   2 +-
 keepalived/vrrp/vrrp.c                   |  53 ++++++--
 keepalived/vrrp/vrrp_daemon.c            |  13 +-
 keepalived/vrrp/vrrp_ipaddress.c         | 137 ++++++++++++++++---
 keepalived/vrrp/vrrp_ipset.c             |  73 +++++++---
 keepalived/vrrp/vrrp_iptables.c          | 225 +++++++++++++++++++------------
 keepalived/vrrp/vrrp_iptables_calls.c    | 108 +++++++--------
 12 files changed, 421 insertions(+), 210 deletions(-)

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