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