From dd9a0db422716dd9bbc329a6e2f23ee3d55d2008 Mon Sep 17 00:00:00 2001 From: Quentin Armitage 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 --- 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 #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 #include +/* 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 /* For __beXX types in userland */ #include /* For nf_inet_addr */ #include +#include #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 #include #endif +#include +#include +#include +#include #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 #include #include -#ifdef _HAVE_LIBIPSET_ #include #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 #endif #include #include #include -#ifdef _LIBXTABLES_DYNAMIC_ -#include -#include -#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