diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56e9f4a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/keepalived-1.3.5.tar.gz diff --git a/.keepalived.metadata b/.keepalived.metadata new file mode 100644 index 0000000..d210999 --- /dev/null +++ b/.keepalived.metadata @@ -0,0 +1 @@ +5a373d8f5d382700cf53b827947a92a7f4cef148 SOURCES/keepalived-1.3.5.tar.gz diff --git a/SOURCES/bz1419049-fix-unused-variables.patch b/SOURCES/bz1419049-fix-unused-variables.patch new file mode 100644 index 0000000..17ae5da --- /dev/null +++ b/SOURCES/bz1419049-fix-unused-variables.patch @@ -0,0 +1,32 @@ +From 6e855aa91876e6a41324e870439f2c185318be88 Mon Sep 17 00:00:00 2001 +From: Ryan O'Hara +Date: Wed, 15 Mar 2017 14:46:33 -0500 +Subject: [PATCH] Fix unused variables + +--- + keepalived/vrrp/vrrp_snmp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/keepalived/vrrp/vrrp_snmp.c b/keepalived/vrrp/vrrp_snmp.c +index 7956f66..84aa00e 100644 +--- a/keepalived/vrrp/vrrp_snmp.c ++++ b/keepalived/vrrp/vrrp_snmp.c +@@ -1112,13 +1112,13 @@ vrrp_snmp_encap(struct variable *vp, oid *name, size_t *length, + { + #if HAVE_DECL_LWTUNNEL_ENCAP_MPLS + static char labels[11*MAX_MPLS_LABELS]; +-#endif + char *op; ++ unsigned i; ++#endif + ip_route_t *route; + nexthop_t *nh; + encap_t *encap; + int state = HEADER_STATE_STATIC_ROUTE; +- unsigned i; + static struct counter64 c64; + + if (vp->name[vp->namelen - 3] == 7) { +-- +2.9.3 + diff --git a/SOURCES/bz1477563-fix-keepalived_script-user.patch b/SOURCES/bz1477563-fix-keepalived_script-user.patch new file mode 100644 index 0000000..49ee81a --- /dev/null +++ b/SOURCES/bz1477563-fix-keepalived_script-user.patch @@ -0,0 +1,729 @@ +From 99f31a89d2f5803fe2d6229f2557e72efb3ef95f Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Tue, 28 Mar 2017 09:11:44 +0100 +Subject: [PATCH] Make dynamic flag bool + +Signed-off-by: Quentin Armitage + +Fix releasing malloc'd memory for saved core pattern + +Signed-off-by: Quentin Armitage + +Fix detecting default script uid/gid + +Signed-off-by: Quentin Armitage + +Don't complain about keepalived_script user if not needed + +keepalived logged a warning every time if the keepalived_script user +didn't exist. We only need that warning if there is a script that uses +the default user, and an alternative defult user isn't specified. + +Signed-off-by: Quentin Armitage +--- + doc/keepalived.conf.SYNOPSIS | 30 +++++---- + doc/man/man5/keepalived.conf.5 | 4 +- + keepalived/check/check_misc.c | 72 ++++++++++++++++----- + keepalived/check/check_parser.c | 9 +-- + keepalived/core/global_parser.c | 49 +------------- + keepalived/core/main.c | 15 +---- + keepalived/include/check_misc.h | 2 +- + keepalived/include/main.h | 2 - + keepalived/vrrp/vrrp_data.c | 3 +- + keepalived/vrrp/vrrp_parser.c | 46 ++++++++++--- + keepalived/vrrp/vrrp_print.c | 1 + + lib/notify.c | 140 ++++++++++++++++++++++++++++++++++------ + lib/notify.h | 7 +- + 13 files changed, 242 insertions(+), 138 deletions(-) + +diff --git a/doc/keepalived.conf.SYNOPSIS b/doc/keepalived.conf.SYNOPSIS +index 5b1dfb8..90eb83d 100644 +--- a/doc/keepalived.conf.SYNOPSIS ++++ b/doc/keepalived.conf.SYNOPSIS +@@ -568,12 +568,14 @@ virtual_server group { # VS group declaration + weight # weight to use (default: 1) + inhibit_on_failure # Set weight to 0 on healthchecker + # failure +- notify_up | # Script to launch when +- # healthchecker consider service +- # as up. +- notify_down | # Script to launch when +- # healthchecker consider service +- # as down. ++ notify_up | [username [groupname]] ++ # Script to launch when ++ # healthchecker consider service ++ # as up. ++ notify_down | [username [groupname]] ++ # Script to launch when ++ # healthchecker consider service ++ # as down. + + HTTP_GET|SSL_GET { # HTTP and SSL healthcheckers + url { # A set of url to test +@@ -603,8 +605,8 @@ virtual_server group { # VS group declaration + real_server { # Idem + weight # Idem + inhibit_on_failure # Idem +- notify_up | # Idem +- notify_down | # Idem ++ notify_up | [username [groupname]] # Idem ++ notify_down | [username [groupname]] # Idem + + TCP_CHECK { # TCP healthchecker + connect_ip # IP address to connect +@@ -620,8 +622,8 @@ virtual_server group { # VS group declaration + real_server { # Idem + weight # Idem + inhibit_on_failure # Idem +- notify_up | # Idem +- notify_down | # Idem ++ notify_up | [username [groupname]] # Idem ++ notify_down | [username [groupname]] # Idem + + SMTP_CHECK { # SMTP healthchecker + connect_ip # Optional IP address to connect to +@@ -658,8 +660,8 @@ virtual_server group { # VS group declaration + real_server { # Idem + weight # Idem + inhibit_on_failure # Idem +- notify_up | # Idem +- notify_down | # Idem ++ notify_up | [username [groupname]] # Idem ++ notify_down | [username [groupname]] # Idem + + DNS_CHECK { # DNS healthchecker + connect_ip # Optional IP address to connect to +@@ -677,8 +679,8 @@ virtual_server group { # VS group declaration + real_server { # Idem + weight # Idem + inhibit_on_failure # Idem +- notify_up | # Idem +- notify_down | # Idem ++ notify_up | [username [groupname]] # Idem ++ notify_down | [username [groupname]] # Idem + + MISC_CHECK { # MISC healthchecker + misc_path | # External system script or program +diff --git a/doc/man/man5/keepalived.conf.5 b/doc/man/man5/keepalived.conf.5 +index 9ce2206..be33063 100644 +--- a/doc/man/man5/keepalived.conf.5 ++++ b/doc/man/man5/keepalived.conf.5 +@@ -711,10 +711,10 @@ A virtual_server can be a declaration of one of + + # Script to execute when healthchecker + # considers service as up. +- notify_up | ++ notify_up | [username [groupname]] + # Script to execute when healthchecker + # considers service as down. +- notify_down | ++ notify_down | [username [groupname]] + + uthreshold # maximum number of connections to server + lthreshold # minimum number of connections to server +diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c +index ccb9b63..a041d81 100644 +--- a/keepalived/check/check_misc.c ++++ b/keepalived/check/check_misc.c +@@ -44,6 +44,11 @@ static int misc_check_thread(thread_t *); + static int misc_check_child_thread(thread_t *); + static int misc_check_child_timeout_thread(thread_t *); + ++static bool script_user_set; ++static bool remove_script; ++static misc_checker_t *misck_checker; ++ ++ + /* Configuration stream handling */ + static void + free_misc_check(void *data) +@@ -70,49 +75,83 @@ dump_misc_check(void *data) + static void + misc_check_handler(__attribute__((unused)) vector_t *strvec) + { +- misc_checker_t *misck_checker = (misc_checker_t *) MALLOC(sizeof (misc_checker_t)); +- +- misck_checker->uid = default_script_uid; +- misck_checker->gid = default_script_gid; ++ misck_checker = (misc_checker_t *) MALLOC(sizeof (misc_checker_t)); + +- /* queue new checker */ +- queue_checker(free_misc_check, dump_misc_check, misc_check_thread, +- misck_checker, NULL); ++ script_user_set = false; + } + + static void + misc_path_handler(vector_t *strvec) + { +- misc_checker_t *misck_checker = CHECKER_GET(); ++ if (!misck_checker) ++ return; ++ + misck_checker->path = CHECKER_VALUE_STRING(strvec); + } + + static void + misc_timeout_handler(vector_t *strvec) + { +- misc_checker_t *misck_checker = CHECKER_GET(); ++ if (!misck_checker) ++ return; ++ + misck_checker->timeout = CHECKER_VALUE_UINT(strvec) * TIMER_HZ; + } + + static void + misc_dynamic_handler(__attribute__((unused)) vector_t *strvec) + { +- misc_checker_t *misck_checker = CHECKER_GET(); +- misck_checker->dynamic = 1; ++ if (!misck_checker) ++ return; ++ ++ misck_checker->dynamic = true; + } + + static void + misc_user_handler(vector_t *strvec) + { +- misc_checker_t *misck_checker = CHECKER_GET(); ++ if (!misck_checker) ++ return; + + if (vector_size(strvec) < 2) { + log_message(LOG_INFO, "No user specified for misc checker script %s", misck_checker->path); + return; + } + +- if (set_script_uid_gid(strvec, 1, &misck_checker->uid, &misck_checker->gid)) +- log_message(LOG_INFO, "Failed to set uid/gid for misc checker script %s", misck_checker->path); ++ if (set_script_uid_gid(strvec, 1, &misck_checker->uid, &misck_checker->gid)) { ++ log_message(LOG_INFO, "Failed to set uid/gid for misc checker script %s - removing", misck_checker->path); ++ FREE(misck_checker); ++ misck_checker = NULL; ++ } ++ else ++ script_user_set = true; ++} ++ ++static void ++misc_end_handler(void) ++{ ++ if (!misck_checker) ++ return; ++ ++ if (!script_user_set) ++ { ++log_message(LOG_INFO, "remove_script 1 %d", remove_script); ++ if ( set_default_script_user(NULL, NULL, global_data->script_security)) { ++ log_message(LOG_INFO, "Unable to set default user for misc script %s - removing", misck_checker->path); ++ FREE(misck_checker); ++ misck_checker = NULL; ++ return; ++ } ++ ++log_message(LOG_INFO, "Setting uid.gid"); ++ misck_checker->uid = default_script_uid; ++ misck_checker->gid = default_script_gid; ++ } ++ ++ /* queue new checker */ ++ queue_checker(free_misc_check, dump_misc_check, misc_check_thread, misck_checker, NULL); ++ misck_checker = NULL; ++log_message(LOG_INFO, "Leaving misc_end_handler"); + } + + void +@@ -125,6 +164,7 @@ install_misc_check_keyword(void) + install_keyword("misc_dynamic", &misc_dynamic_handler); + install_keyword("warmup", &warmup_handler); + install_keyword("user", &misc_user_handler); ++ install_sublevel_end_handler(&misc_end_handler); + install_sublevel_end(); + } + +@@ -251,13 +291,13 @@ misc_check_child_thread(thread_t * thread) + int status; + status = WEXITSTATUS(wait_status); + if (status == 0 || +- (misck_checker->dynamic == 1 && status >= 2 && status <= 255)) { ++ (misck_checker->dynamic && status >= 2 && status <= 255)) { + /* + * The actual weight set when using misc_dynamic is two less than + * the exit status returned. Effective range is 0..253. + * Catch legacy case of status being 0 but misc_dynamic being set. + */ +- if (misck_checker->dynamic == 1 && status != 0) ++ if (misck_checker->dynamic && status != 0) + update_svr_wgt(status - 2, checker->vs, + checker->rs, true); + +diff --git a/keepalived/check/check_parser.c b/keepalived/check/check_parser.c +index 2adac98..382861c 100644 +--- a/keepalived/check/check_parser.c ++++ b/keepalived/check/check_parser.c +@@ -322,14 +322,7 @@ inhibit_handler(__attribute__((unused)) vector_t *strvec) + static inline notify_script_t* + set_check_notify_script(vector_t *strvec) + { +- notify_script_t *script = notify_script_init(strvec, default_script_uid, default_script_gid); +- +- if (vector_size(strvec) > 2 ) { +- if (set_script_uid_gid(strvec, 2, &script->uid, &script->gid)) +- log_message(LOG_INFO, "Invalid user/group for quorum/notify script %s", script->name); +- } +- +- return script; ++ return notify_script_init(strvec, "quorum/notify", global_data->script_security); + } + static void + notify_up_handler(vector_t *strvec) +diff --git a/keepalived/core/global_parser.c b/keepalived/core/global_parser.c +index 45d4cfb..a59fbc0 100644 +--- a/keepalived/core/global_parser.c ++++ b/keepalived/core/global_parser.c +@@ -701,53 +701,6 @@ use_pid_dir_handler(__attribute__((unused)) vector_t *strvec) + use_pid_dir = true; + } + +-bool +-set_script_uid_gid(vector_t *strvec, unsigned keyword_offset, uid_t *uid_p, gid_t *gid_p) +-{ +- char *username; +- char *groupname; +- uid_t uid; +- gid_t gid; +- struct passwd pwd; +- struct passwd *pwd_p; +- struct group grp; +- struct group *grp_p; +- int ret; +- char buf[getpwnam_buf_len]; +- +- username = strvec_slot(strvec, keyword_offset); +- +- if ((ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &pwd_p))) { +- log_message(LOG_INFO, "Unable to resolve script username '%s' - ignoring", username); +- return true; +- } +- if (!pwd_p) { +- log_message(LOG_INFO, "Script user '%s' does not exist", username); +- return true; +- } +- +- uid = pwd.pw_uid; +- gid = pwd.pw_gid; +- +- if (vector_size(strvec) > keyword_offset + 1) { +- groupname = strvec_slot(strvec, keyword_offset + 1); +- if ((ret = getgrnam_r(groupname, &grp, buf, sizeof(buf), &grp_p))) { +- log_message(LOG_INFO, "Unable to resolve script group name '%s' - ignoring", groupname); +- return true; +- } +- if (!grp_p) { +- log_message(LOG_INFO, "Script group '%s' does not exist", groupname); +- return true; +- } +- gid = grp.gr_gid; +- } +- +- *uid_p = uid; +- *gid_p = gid; +- +- return false; +-} +- + static void + script_user_handler(vector_t *strvec) + { +@@ -756,7 +709,7 @@ script_user_handler(vector_t *strvec) + return; + } + +- if (set_script_uid_gid(strvec, 1, &default_script_uid, &default_script_gid)) ++ if (set_default_script_user(strvec_slot(strvec, 1), vector_size(strvec) > 2 ? strvec_slot(strvec, 2) : NULL, true)) + log_message(LOG_INFO, "Error setting global script uid/gid"); + } + +diff --git a/keepalived/core/main.c b/keepalived/core/main.c +index 55eb263..95bb76a 100644 +--- a/keepalived/core/main.c ++++ b/keepalived/core/main.c +@@ -119,6 +119,9 @@ free_parent_mallocs_startup(bool am_child) + #else + free(syslog_ident); + #endif ++ ++ if (orig_core_dump_pattern) ++ FREE_PTR(orig_core_dump_pattern); + } + + if (free_main_pidfile) { +@@ -765,7 +768,6 @@ keepalived_main(int argc, char **argv) + bool report_stopped = true; + struct utsname uname_buf; + char *end; +- long buf_len; + + /* Init debugging level */ + debug = 0; +@@ -814,17 +816,6 @@ keepalived_main(int argc, char **argv) + + netlink_set_recv_buf_size(); + +- set_default_script_user(&default_script_uid, &default_script_gid); +- +- /* Get buffer length needed for getpwnam_r/getgrnam_r */ +- if ((buf_len = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) +- getpwnam_buf_len = 1024; /* A safe default if no value is returned */ +- else +- getpwnam_buf_len = (size_t)buf_len; +- if ((buf_len = sysconf(_SC_GETGR_R_SIZE_MAX)) != -1 && +- (size_t)buf_len > getpwnam_buf_len) +- getpwnam_buf_len = (size_t)buf_len; +- + /* Some functionality depends on kernel version, so get the version here */ + if (uname(&uname_buf)) + log_message(LOG_INFO, "Unable to get uname() information - error %d", errno); +diff --git a/keepalived/include/check_misc.h b/keepalived/include/check_misc.h +index ed0d962..ec97149 100644 +--- a/keepalived/include/check_misc.h ++++ b/keepalived/include/check_misc.h +@@ -36,7 +36,7 @@ + typedef struct _misc_checker { + char *path; + unsigned long timeout; +- int dynamic; /* 0: old-style, 1: exit code from checker affects weight */ ++ bool dynamic; /* false: old-style, true: exit code from checker affects weight */ + bool forcing_termination; /* Set if we have sent the process a SIGTERM */ + uid_t uid; /* uid for script execution */ + gid_t gid; /* gid for script execution */ +diff --git a/keepalived/include/main.h b/keepalived/include/main.h +index d125566..eebde77 100644 +--- a/keepalived/include/main.h ++++ b/keepalived/include/main.h +@@ -73,8 +73,6 @@ extern bool namespace_with_ipsets; /* override for namespaces with ipsets on Lin + #endif + extern char *instance_name; /* keepalived instance name */ + extern bool use_pid_dir; /* pid files in /var/run/keepalived */ +-extern uid_t default_script_uid; /* Default user/group for script execution */ +-extern gid_t default_script_gid; + extern unsigned os_major; /* Kernel version */ + extern unsigned os_minor; + extern unsigned os_release; +diff --git a/keepalived/vrrp/vrrp_data.c b/keepalived/vrrp/vrrp_data.c +index 76f17a4..b5c59df 100644 +--- a/keepalived/vrrp/vrrp_data.c ++++ b/keepalived/vrrp/vrrp_data.c +@@ -160,8 +160,7 @@ dump_vscript(void *data) + str = (vscript->result >= vscript->rise) ? "GOOD" : "BAD"; + } + log_message(LOG_INFO, " Status = %s", str); +- if (vscript->uid || vscript->gid) +- log_message(LOG_INFO, " Script uid:gid = %d:%d", vscript->uid, vscript->gid); ++ log_message(LOG_INFO, " Script uid:gid = %d:%d", vscript->uid, vscript->gid); + + } + +diff --git a/keepalived/vrrp/vrrp_parser.c b/keepalived/vrrp/vrrp_parser.c +index 7a38315..c774dec 100644 +--- a/keepalived/vrrp/vrrp_parser.c ++++ b/keepalived/vrrp/vrrp_parser.c +@@ -48,6 +48,9 @@ + #include "bitops.h" + #include "notify.h" + ++static bool script_user_set; ++static bool remove_script; ++ + /* Static addresses handler */ + static void + static_addresses_handler(__attribute__((unused)) vector_t *strvec) +@@ -120,14 +123,7 @@ vrrp_group_handler(vector_t *strvec) + static inline notify_script_t* + set_vrrp_notify_script(vector_t *strvec) + { +- notify_script_t *script = notify_script_init(strvec, default_script_uid, default_script_gid); +- +- if (vector_size(strvec) > 2) { +- if (set_script_uid_gid(strvec, 2, &script->uid, &script->gid)) +- log_message(LOG_INFO, "Invalid user/group for notify script %s", script->name); +- } +- +- return script; ++ return notify_script_init(strvec, "notify", global_data->script_security); + } + + static void +@@ -680,6 +676,8 @@ static void + vrrp_script_handler(vector_t *strvec) + { + alloc_vrrp_script(strvec_slot(strvec, 1)); ++ script_user_set = false; ++ remove_script = false; + } + static void + vrrp_vscript_script_handler(vector_t *strvec) +@@ -731,8 +729,35 @@ static void + vrrp_vscript_user_handler(vector_t *strvec) + { + vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); +- if (set_script_uid_gid(strvec, 1, &vscript->uid, &vscript->gid)) +- log_message(LOG_INFO, "Unable to set uid/gid for script %s", vscript->script); ++ if (set_script_uid_gid(strvec, 1, &vscript->uid, &vscript->gid)) { ++ log_message(LOG_INFO, "Unable to set uid/gid for script %s - disabling", vscript->script); ++ remove_script = true; ++ } ++ else ++ script_user_set = true; ++} ++static void ++vrrp_vscript_end_handler(void) ++{ ++ vrrp_script_t *vscript = LIST_TAIL_DATA(vrrp_data->vrrp_script); ++ ++ if (script_user_set) ++ return; ++ ++ if (!remove_script && ++ set_default_script_user(NULL, NULL, global_data->script_security)) { ++ log_message(LOG_INFO, "Unable to set default user for track script %s - removing", vscript->script); ++ remove_script = true; ++ } ++ ++ if (remove_script) { ++ free_list_element(vrrp_data->vrrp_script, vrrp_data->vrrp_script->tail); ++ return; ++ } ++ ++ vscript->uid = default_script_uid; ++ vscript->gid = default_script_gid; ++ + } + static void + vrrp_vscript_init_fail_handler(__attribute__((unused)) vector_t *strvec) +@@ -964,6 +989,7 @@ init_vrrp_keywords(bool active) + install_keyword("fall", &vrrp_vscript_fall_handler); + install_keyword("user", &vrrp_vscript_user_handler); + install_keyword("init_fail", &vrrp_vscript_init_fail_handler); ++ install_sublevel_end_handler(&vrrp_vscript_end_handler); + } + + vector_t * +diff --git a/keepalived/vrrp/vrrp_print.c b/keepalived/vrrp/vrrp_print.c +index 7adb701..54da044 100644 +--- a/keepalived/vrrp/vrrp_print.c ++++ b/keepalived/vrrp/vrrp_print.c +@@ -92,6 +92,7 @@ vscript_print(FILE *file, void *data) + fprintf(file, " Rise = %d\n", vscript->rise); + fprintf(file, " Full = %d\n", vscript->fall); + fprintf(file, " Insecure = %s\n", vscript->insecure ? "yes" : "no"); ++ fprintf(file, " uid:gid = %d:%d\n", vscript->uid, vscript->gid); + + switch (vscript->result) { + case VRRP_SCRIPT_STATUS_INIT: +diff --git a/lib/notify.c b/lib/notify.c +index d92c50d..a8742fe 100644 +--- a/lib/notify.c ++++ b/lib/notify.c +@@ -44,10 +44,15 @@ + #include "vector.h" + #include "parser.h" + +-size_t getpwnam_buf_len; /* Buffer length needed for getpwnam_r/getgrname_r */ + ++uid_t default_script_uid; /* Default user/group for script execution */ ++gid_t default_script_gid; ++static bool default_script_uid_set = false; ++static bool default_user_fail = false; /* Set if failed to set default user, ++ unless it defaults to root */ + static char *path; + static bool path_is_malloced; ++static size_t getpwnam_buf_len; /* Buffer length needed for getpwnam_r/getgrname_r */ + + /* perform a system call */ + static int +@@ -565,40 +570,135 @@ check_notify_script_secure(notify_script_t **script_p, bool script_security, boo + return flags; + } + +-/* The default script user/group is keepalived_script if it exists, or root otherwise */ +-void +-set_default_script_user(uid_t *uid, gid_t *gid) ++static void ++set_pwnam_buf_len(void) ++{ ++ long buf_len; ++ ++ /* Get buffer length needed for getpwnam_r/getgrnam_r */ ++ if ((buf_len = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) ++ getpwnam_buf_len = 1024; /* A safe default if no value is returned */ ++ else ++ getpwnam_buf_len = (size_t)buf_len; ++ if ((buf_len = sysconf(_SC_GETGR_R_SIZE_MAX)) != -1 && ++ (size_t)buf_len > getpwnam_buf_len) ++ getpwnam_buf_len = (size_t)buf_len; ++} ++ ++bool ++set_uid_gid(const char *username, const char *groupname, uid_t *uid_p, gid_t *gid_p, bool default_user) + { +- char buf[getpwnam_buf_len]; +- char *default_user_name = "keepalived_script"; ++ uid_t uid; ++ gid_t gid; + struct passwd pwd; + struct passwd *pwd_p; ++ struct group grp; ++ struct group *grp_p; ++ int ret; ++ bool using_default_default_user = false; ++ ++ if (!getpwnam_buf_len) ++ set_pwnam_buf_len(); + +- if (getpwnam_r(default_user_name, &pwd, buf, sizeof(buf), &pwd_p)) { +- log_message(LOG_INFO, "Unable to resolve default script username '%s' - ignoring", default_user_name); +- return; ++ { ++ char buf[getpwnam_buf_len]; ++ ++ if (default_user && !username) { ++ using_default_default_user = true; ++ username = "keepalived_script"; ++ } ++ ++ if ((ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &pwd_p))) { ++ log_message(LOG_INFO, "Unable to resolve %sscript username '%s' - ignoring", default_user ? "default " : "", username); ++ return true; ++ } ++ if (!pwd_p) { ++ if (using_default_default_user) ++ log_message(LOG_INFO, "WARNING - default user '%s' for script execution does not exist - please create.", username); ++ else ++ log_message(LOG_INFO, "%script user '%s' does not exist", default_user ? "Default s" : "S", username); ++ return true; ++ } ++ ++ uid = pwd.pw_uid; ++ gid = pwd.pw_gid; ++ ++ if (groupname) { ++ if ((ret = getgrnam_r(groupname, &grp, buf, sizeof(buf), &grp_p))) { ++ log_message(LOG_INFO, "Unable to resolve %sscript group name '%s' - ignoring", default_user ? "default " : "", groupname); ++ return true; ++ } ++ if (!grp_p) { ++ log_message(LOG_INFO, "%script group '%s' does not exist", default_user ? "Default s" : "S", groupname); ++ return true; ++ } ++ gid = grp.gr_gid; ++ } ++ ++ *uid_p = uid; ++ *gid_p = gid; + } +- if (!pwd_p) { +- /* The username does not exist */ +- log_message(LOG_INFO, "WARNING - default user '%s' for script execution does not exist - please create.", default_user_name); +- return; ++ ++ return false; ++} ++ ++bool ++set_default_script_user(const char *username, const char *groupname, bool script_security) ++{ ++ if (!default_script_uid_set || username) { ++ /* Even if we fail to set it, there is no point in trying again */ ++ default_script_uid_set = true; ++ ++ if (set_uid_gid(username, groupname, &default_script_uid, &default_script_gid, true)) { ++ if (username || script_security) ++ default_user_fail = true; ++ } ++ else ++ default_user_fail = false; + } + +- *uid = pwd.pw_uid; +- *gid = pwd.pw_gid; ++ return default_user_fail; ++} ++ ++bool ++set_script_uid_gid(vector_t *strvec, unsigned keyword_offset, uid_t *uid_p, gid_t *gid_p) ++{ ++ char *username; ++ char *groupname; ++ ++ username = strvec_slot(strvec, keyword_offset); ++ if (vector_size(strvec) > keyword_offset + 1) ++ groupname = strvec_slot(strvec, keyword_offset + 1); ++ else ++ groupname = NULL; + +- log_message(LOG_INFO, "Setting default script user to '%s', uid:gid %d:%d", default_user_name, pwd.pw_uid, pwd.pw_gid); ++ return set_uid_gid(username, groupname, uid_p, gid_p, false); + } + + notify_script_t* +-notify_script_init(vector_t *strvec, uid_t uid, gid_t gid) ++notify_script_init(vector_t *strvec, const char *type, bool script_security) + { + notify_script_t *script = MALLOC(sizeof(notify_script_t)); + + script->name = set_value(strvec); +- script->uid = uid; +- script->gid = gid; ++ ++ if (vector_size(strvec) > 2) { ++ if (set_script_uid_gid(strvec, 2, &script->uid, &script->gid)) { ++ log_message(LOG_INFO, "Invalid user/group for %s script %s - ignoring", type, script->name); ++ FREE(script); ++ return NULL; ++ } ++ } ++ else { ++ if (set_default_script_user(NULL, NULL, script_security)) { ++ log_message(LOG_INFO, "Failed to set default user for %s script %s - ignoring", type, script->name); ++ FREE(script); ++ return NULL; ++ } ++ ++ script->uid = default_script_uid; ++ script->gid = default_script_gid; ++ } + + return script; + } +- +diff --git a/lib/notify.h b/lib/notify.h +index ac07edb..3d092ea 100644 +--- a/lib/notify.h ++++ b/lib/notify.h +@@ -56,7 +56,8 @@ free_notify_script(notify_script_t **script) + } + + /* Global variables */ +-extern size_t getpwnam_buf_len; /* Buffer length needed for getpwnam_r/getgrnam_r */ ++extern uid_t default_script_uid; /* Default user/group for script execution */ ++extern gid_t default_script_gid; + + /* prototypes */ + extern int system_call_script(thread_master_t *, int (*) (thread_t *), void *, unsigned long, const char*, uid_t, gid_t); +@@ -64,7 +65,7 @@ extern int notify_exec(const notify_script_t *); + extern void script_killall(thread_master_t *, int); + extern int check_script_secure(notify_script_t *, bool, bool); + extern int check_notify_script_secure(notify_script_t **, bool, bool); +-extern void set_default_script_user(uid_t *, gid_t *); +-extern notify_script_t* notify_script_init(vector_t *, uid_t, gid_t); ++extern bool set_default_script_user(const char *, const char *, bool); ++extern notify_script_t* notify_script_init(vector_t *, const char *, bool); + + #endif +-- +2.9.4 + diff --git a/SOURCES/bz1477572-fix-man-page-vrrp_ipsets.patch b/SOURCES/bz1477572-fix-man-page-vrrp_ipsets.patch new file mode 100644 index 0000000..55ba6c3 --- /dev/null +++ b/SOURCES/bz1477572-fix-man-page-vrrp_ipsets.patch @@ -0,0 +1,29 @@ +From 431ba58daf11771195d0b494b0b0b3655a9b25cd Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Wed, 2 Aug 2017 16:18:32 +0100 +Subject: [PATCH] Fix keepalived.doc(5) man page + +Ryan O'Hara identified that 'vrrp_ipset' should be 'vrrp_ipsets' +in the man page. + +Signed-off-by: Quentin Armitage +--- + doc/man/man5/keepalived.conf.5 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/doc/man/man5/keepalived.conf.5 b/doc/man/man5/keepalived.conf.5 +index 5f044af..c7b9d2e 100644 +--- a/doc/man/man5/keepalived.conf.5 ++++ b/doc/man/man5/keepalived.conf.5 +@@ -151,7 +151,7 @@ and + # If no names are specified, ipsets will not be used, otherwise any omitted + # names will be constructed by adding "_if" and/or "6" to previously specified + # names. +- vrrp_ipset [keepalived [keepalived6 [keepalived_if6]]] ++ vrrp_ipsets [keepalived [keepalived6 [keepalived_if6]]] + + # The following enables checking that when in unicast mode, the source + # address of a VRRP packet is one of our unicast peers. +-- +2.9.4 + diff --git a/SOURCES/bz1477587-exclude-mismatch-vips.patch b/SOURCES/bz1477587-exclude-mismatch-vips.patch new file mode 100644 index 0000000..abbb6c2 --- /dev/null +++ b/SOURCES/bz1477587-exclude-mismatch-vips.patch @@ -0,0 +1,38 @@ +From f42914b07166db123b55a4acd31f4a6eb280d0f8 Mon Sep 17 00:00:00 2001 +From: Ryan O'Hara +Date: Mon, 11 Dec 2017 12:36:26 -0600 +Subject: [PATCH] Exclude mixed family VIPs from VRRP advertisements + +In previous releases of keepalived, it was allowed to have both IPv5 +and IPv6 addresses in the 'virtual_ipaddress' block. The address count +in VRRP advertisements would reflect all VIPS, both IPv4 and IPv6, but +the address list would contain empty addresses for any VIP that did +not match the VRRP instance family. In VRRPv3 this is not allowed, and +recent releases will simply ignore any VIP that does not match the +instance family causing those VIPs to not be created in the interface. + +Rather than ignore the VIP of mismatched family, this patch will move +non-matching VIP to the excluded list causing them to not be included +in the VRRP advertisements but still create them when in MASTER state. +--- + keepalived/vrrp/vrrp_parser.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/keepalived/vrrp/vrrp_parser.c b/keepalived/vrrp/vrrp_parser.c +index 7a383153..d2cd720a 100644 +--- a/keepalived/vrrp/vrrp_parser.c ++++ b/keepalived/vrrp/vrrp_parser.c +@@ -641,8 +641,9 @@ vrrp_vip_handler(__attribute__((unused)) vector_t *strvec) + if (vrrp->family == AF_UNSPEC) + vrrp->family = address_family; + else if (address_family != vrrp->family) { +- log_message(LOG_INFO, "(%s): address family must match VRRP instance [%s] - ignoring", vrrp->iname, str); ++ log_message(LOG_WARNING, "(%s): address family does not match VRRP instance [%s]", vrrp->iname, str); + free_list_element(vrrp->vip, vrrp->vip->tail); ++ alloc_vrrp_evip(vec); + } + } + +-- +2.14.2 + diff --git a/SOURCES/bz1508435-load-ip-tables-handling.patch b/SOURCES/bz1508435-load-ip-tables-handling.patch new file mode 100644 index 0000000..27b82a2 --- /dev/null +++ b/SOURCES/bz1508435-load-ip-tables-handling.patch @@ -0,0 +1,1154 @@ +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 + diff --git a/SOURCES/bz1508435-no-segfault-ip_vs-load.patch b/SOURCES/bz1508435-no-segfault-ip_vs-load.patch new file mode 100644 index 0000000..b894b25 --- /dev/null +++ b/SOURCES/bz1508435-no-segfault-ip_vs-load.patch @@ -0,0 +1,168 @@ +From 19d0482859d9068b893104b9f8beeaba709aec2d Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Mon, 27 Mar 2017 11:28:02 +0100 +Subject: [PATCH 2/3] Don't segfault if unable to load ip_vs module + +In a docker container it isn't possible to load a kernel module. The +check code was detecting that it couldn't load the module, but the +checker process, when cleaning up prior to exiting, was assuming that +certain pointers had been initialised which hadn't been when an error +was detected so early in the initialisation. + +This commit adds testing for uninitialised pointers during the exit +sequence. + +Signed-off-by: Quentin Armitage +--- + keepalived/check/check_api.c | 3 +++ + keepalived/check/check_daemon.c | 8 +++++--- + keepalived/check/check_data.c | 7 ++++++- + keepalived/check/ipvswrapper.c | 9 ++++++--- + keepalived/check/ipwrapper.c | 6 ++++-- + keepalived/check/libipvs.c | 5 ++++- + keepalived/core/keepalived_netlink.c | 7 ++++--- + 7 files changed, 32 insertions(+), 13 deletions(-) + +diff --git a/keepalived/check/check_api.c b/keepalived/check/check_api.c +index 51d8cc71..b7081fd0 100644 +--- a/keepalived/check/check_api.c ++++ b/keepalived/check/check_api.c +@@ -224,6 +224,9 @@ init_checkers_queue(void) + void + free_checkers_queue(void) + { ++ if (!checkers_queue) ++ return; ++ + free_list(&checkers_queue); + ncheckers = 0; + } +diff --git a/keepalived/check/check_daemon.c b/keepalived/check/check_daemon.c +index a87fd4cd..a3ff8cab 100644 +--- a/keepalived/check/check_daemon.c ++++ b/keepalived/check/check_daemon.c +@@ -74,7 +74,7 @@ stop_check(int status) + clear_services(); + ipvs_stop(); + #ifdef _WITH_SNMP_CHECKER_ +- if (global_data->enable_snmp_checker) ++ if (global_data && global_data->enable_snmp_checker) + check_snmp_agent_close(); + #endif + +@@ -82,8 +82,10 @@ stop_check(int status) + pidfile_rm(checkers_pidfile); + + /* Clean data */ +- free_global_data(global_data); +- free_check_data(check_data); ++ if (global_data) ++ free_global_data(global_data); ++ if (check_data) ++ free_check_data(check_data); + free_parent_mallocs_exit(); + + /* +diff --git a/keepalived/check/check_data.c b/keepalived/check/check_data.c +index 0c3f1940..6ce87229 100644 +--- a/keepalived/check/check_data.c ++++ b/keepalived/check/check_data.c +@@ -51,7 +51,12 @@ alloc_ssl(void) + void + free_ssl(void) + { +- ssl_data_t *ssl = check_data->ssl; ++ ssl_data_t *ssl; ++ ++ if (!check_data) ++ return; ++ ++ ssl = check_data->ssl; + + if (!ssl) + return; +diff --git a/keepalived/check/ipvswrapper.c b/keepalived/check/ipvswrapper.c +index cd7f169e..20757c94 100644 +--- a/keepalived/check/ipvswrapper.c ++++ b/keepalived/check/ipvswrapper.c +@@ -165,9 +165,12 @@ void + ipvs_stop(void) + { + /* Clean up the room */ +- FREE(srule); +- FREE(drule); +- FREE(daemonrule); ++ if (srule) ++ FREE(srule); ++ if (drule) ++ FREE(drule); ++ if (daemonrule) ++ FREE(daemonrule); + ipvs_close(); + } + +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index 0c2fc46b..ecf12713 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -138,10 +138,12 @@ void + clear_services(void) + { + element e; +- list l = check_data->vs; + virtual_server_t *vs; + +- for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { ++ if (!check_data || !check_data->vs) ++ return; ++ ++ for (e = LIST_HEAD(check_data->vs); e; ELEMENT_NEXT(e)) { + vs = ELEMENT_DATA(e); + clear_service_vs(vs); + } +diff --git a/keepalived/check/libipvs.c b/keepalived/check/libipvs.c +index 2250e2b4..8722f7a6 100644 +--- a/keepalived/check/libipvs.c ++++ b/keepalived/check/libipvs.c +@@ -1157,7 +1157,10 @@ void ipvs_close(void) + if (try_nl) + return; + #endif +- close(sockfd); ++ if (sockfd != -1) { ++ close(sockfd); ++ sockfd = -1; ++ } + } + + const char *ipvs_strerror(int err) +diff --git a/keepalived/core/keepalived_netlink.c b/keepalived/core/keepalived_netlink.c +index 41e63b85..0f465cf5 100644 +--- a/keepalived/core/keepalived_netlink.c ++++ b/keepalived/core/keepalived_netlink.c +@@ -251,9 +251,12 @@ netlink_socket(nl_handle_t *nl, int flags, int group, ...) + } + + /* Close a netlink socket */ +-static int ++static void + netlink_close(nl_handle_t *nl) + { ++ if (!nl) ++ return; ++ + /* First of all release pending thread */ + thread_cancel(nl->thread); + +@@ -269,8 +272,6 @@ netlink_close(nl_handle_t *nl) + #endif + close(nl->fd); + #endif +- +- return 0; + } + + #ifdef _WITH_VRRP_ +-- +2.13.5 + diff --git a/SOURCES/bz1508435-remove-ipset-handling.patch b/SOURCES/bz1508435-remove-ipset-handling.patch new file mode 100644 index 0000000..2cc4f94 --- /dev/null +++ b/SOURCES/bz1508435-remove-ipset-handling.patch @@ -0,0 +1,30 @@ +From dcb5af32ea618c42e353f399962bdd6dc1c8a7d9 Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Mon, 27 Mar 2017 20:44:50 +0100 +Subject: [PATCH 3/3] Don't attempt to remove ipsets if ipset handling not + initialised + +Signed-off-by: Quentin Armitage +--- + keepalived/vrrp/vrrp_ipset.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/keepalived/vrrp/vrrp_ipset.c b/keepalived/vrrp/vrrp_ipset.c +index 1c3e4990..b40bc836 100644 +--- a/keepalived/vrrp/vrrp_ipset.c ++++ b/keepalived/vrrp/vrrp_ipset.c +@@ -270,6 +270,11 @@ bool remove_ipsets(void) + if (!global_data->using_ipsets) + return true; + ++#ifdef _LIBIPSET_DYNAMIC_ ++ if (!libipset_handle) ++ return true; ++#endif ++ + session = ipset_session_init(printf); + if (!session) { + log_message(LOG_INFO, "Cannot initialize ipset session."); +-- +2.13.5 + diff --git a/SOURCES/bz1652694-fix-buffer-overflow-http-status.patch b/SOURCES/bz1652694-fix-buffer-overflow-http-status.patch new file mode 100644 index 0000000..c147780 --- /dev/null +++ b/SOURCES/bz1652694-fix-buffer-overflow-http-status.patch @@ -0,0 +1,57 @@ +From f28015671a4b04785859d1b4b1327b367b6a10e9 Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Tue, 24 Jul 2018 09:28:43 +0100 +Subject: [PATCH] Fix buffer overflow in extract_status_code() + +Issue #960 identified that the buffer allocated for copying the +HTTP status code could overflow if the http response was corrupted. + +This commit changes the way the status code is read, avoids copying +data, and also ensures that the status code is three digits long, +is non-negative and occurs on the first line of the response. + +Signed-off-by: Quentin Armitage +--- + lib/html.c | 23 +++++++++-------------- + 1 file changed, 9 insertions(+), 14 deletions(-) + +diff --git a/lib/html.c b/lib/html.c +index 5a3eaeac..69d3bd2d 100644 +--- a/lib/html.c ++++ b/lib/html.c +@@ -58,23 +58,18 @@ size_t extract_content_length(char *buffer, size_t size) + */ + int extract_status_code(char *buffer, size_t size) + { +- char *buf_code; +- char *begin; + char *end = buffer + size; +- size_t inc = 0; +- int code; +- +- /* Allocate the room */ +- buf_code = (char *)MALLOC(10); ++ unsigned long code; + + /* Status-Code extraction */ +- while (buffer < end && *buffer++ != ' ') ; +- begin = buffer; +- while (buffer < end && *buffer++ != ' ') +- inc++; +- strncat(buf_code, begin, inc); +- code = atoi(buf_code); +- FREE(buf_code); ++ while (buffer < end && *buffer != ' ' && *buffer != '\r') ++ buffer++; ++ buffer++; ++ if (buffer + 3 >= end || *buffer == ' ' || buffer[3] != ' ') ++ return 0; ++ code = strtoul(buffer, &end, 10); ++ if (buffer + 3 != end) ++ return 0; + return code; + } + +-- +2.19.1 + diff --git a/SOURCES/bz1654301-fix-improper-pathname-validation.patch b/SOURCES/bz1654301-fix-improper-pathname-validation.patch new file mode 100644 index 0000000..e0552fb --- /dev/null +++ b/SOURCES/bz1654301-fix-improper-pathname-validation.patch @@ -0,0 +1,171 @@ +diff --git a/keepalived/core/pidfile.c b/keepalived/core/pidfile.c +index f3f3a2c8..6cfbfe8d 100644 +--- a/keepalived/core/pidfile.c ++++ b/keepalived/core/pidfile.c +@@ -54,7 +54,7 @@ int + pidfile_write(const char *pid_file, int pid) + { + FILE *pidfile = NULL; +- int pidfd = creat(pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ++ int pidfd = open(pid_file, O_NOFOLLOW | O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (pidfd != -1) pidfile = fdopen(pidfd, "w"); + + if (!pidfile) { +diff --git a/keepalived/vrrp/vrrp_dbus.c b/keepalived/vrrp/vrrp_dbus.c +index f29a974f..1320a6c2 100644 +--- a/keepalived/vrrp/vrrp_dbus.c ++++ b/keepalived/vrrp/vrrp_dbus.c +@@ -551,7 +551,7 @@ read_file(gchar* filepath) + size_t length; + gchar *ret = NULL; + +- f = fopen(filepath, "rb"); ++ f = fopen(filepath, "r"); + if (f) { + fseek(f, 0, SEEK_END); + length = (size_t)ftell(f); +diff --git a/keepalived/vrrp/vrrp_print.c b/keepalived/vrrp/vrrp_print.c +index 7adb701d..03840adf 100644 +--- a/keepalived/vrrp/vrrp_print.c ++++ b/keepalived/vrrp/vrrp_print.c +@@ -27,6 +27,7 @@ + #include "vrrp.h" + #include "vrrp_data.h" + #include "vrrp_print.h" ++#include "utils.h" + #ifdef _HAVE_FIB_ROUTING_ + #include "vrrp_iproute.h" + #include "vrrp_iprule.h" +@@ -350,7 +351,7 @@ void + vrrp_print_data(void) + { + FILE *file; +- file = fopen ("/tmp/keepalived.data","w"); ++ file = fopen_safe("/tmp/keepalived.data","w"); + + if (!file) { + log_message(LOG_INFO, "Can't open /tmp/keepalived.data (%d: %s)", +@@ -374,7 +375,7 @@ void + vrrp_print_stats(void) + { + FILE *file; +- file = fopen ("/tmp/keepalived.stats","w"); ++ file = fopen_safe("/tmp/keepalived.stats","w"); + + if (!file) { + log_message(LOG_INFO, "Can't open /tmp/keepalived.stats (%d: %s)", +@@ -393,8 +394,7 @@ vrrp_print_stats(void) + fprintf(file, " Received: %" PRIu64 "\n", vrrp->stats->advert_rcvd); + fprintf(file, " Sent: %d\n", vrrp->stats->advert_sent); + fprintf(file, " Became master: %d\n", vrrp->stats->become_master); +- fprintf(file, " Released master: %d\n", +- vrrp->stats->release_master); ++ fprintf(file, " Released master: %d\n", vrrp->stats->release_master); + fprintf(file, " Packet Errors:\n"); + fprintf(file, " Length: %" PRIu64 "\n", vrrp->stats->packet_len_err); + fprintf(file, " TTL: %" PRIu64 "\n", vrrp->stats->ip_ttl_err); +diff --git a/lib/memory.c b/lib/memory.c +index 96a4e7b9..04b3d6ee 100644 +--- a/lib/memory.c ++++ b/lib/memory.c +@@ -441,7 +441,7 @@ mem_log_init(const char* prog_name, const char *banner) + } + + snprintf(log_name, log_name_len, "/tmp/%s_mem.%d.log", prog_name, getpid()); +- log_op = fopen(log_name, "a"); ++ log_op = fopen_safe(log_name, "a"); + if (log_op == NULL) { + log_message(LOG_INFO, "Unable to open %s for appending", log_name); + log_op = stderr; +diff --git a/lib/parser.c b/lib/parser.c +index 2f7959e8..a5c3465b 100644 +--- a/lib/parser.c ++++ b/lib/parser.c +@@ -153,12 +153,12 @@ dump_keywords(vector_t *keydump, int level, FILE *fp) + { + unsigned int i; + keyword_t *keyword_vec; +- char file_name[21]; ++ char file_name[22]; + + if (!level) { + sprintf(file_name, "/tmp/keywords.%d", getpid()); + snprintf(file_name, sizeof(file_name), "/tmp/keywords.%d", getpid()); +- fp = fopen(file_name, "w"); ++ fp = fopen_safe(file_name, "w"); + if (!fp) + return; + } +diff --git a/lib/utils.c b/lib/utils.c +index 88465609..f317937e 100644 +--- a/lib/utils.c ++++ b/lib/utils.c +@@ -89,7 +89,7 @@ dump_buffer(char *buff, size_t count, FILE* fp) + void + write_stacktrace(const char *file_name) + { +- int fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT, 0644); ++ int fd = open(file_name, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + void *buffer[100]; + int nptrs; + +@@ -518,6 +518,47 @@ string_equal(const char *str1, const char *str2) + return (*str1 == 0 && *str2 == 0); + } + ++/* We need to use O_NOFOLLOW if opening a file for write, so that a non privileged user can't ++ * create a symbolic link from the path to a system file and cause a system file to be overwritten. */ ++FILE *fopen_safe(const char *path, const char *mode) ++{ ++ int fd; ++ FILE *file; ++ int flags = O_NOFOLLOW | O_CREAT; ++ ++ if (mode[0] == 'r') ++ return fopen(path, mode); ++ ++ if (mode[0] != 'a' && mode[0] != 'w') ++ return NULL; ++ ++ if (mode[1] && ++ (mode[1] != '+' || mode[2])) ++ return NULL; ++ ++ if (mode[0] == 'w') ++ flags |= O_TRUNC; ++ else ++ flags |= O_APPEND; ++ ++ if (mode[1]) ++ flags |= O_RDWR; ++ else ++ flags |= O_WRONLY; ++ ++ fd = open(path, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); ++ if (fd == -1) ++ return NULL; ++ ++ file = fdopen (fd, "w"); ++ if (!file) { ++ close(fd); ++ return NULL; ++ } ++ ++ return file; ++} ++ + void + set_std_fd(int force) + { +diff --git a/lib/utils.h b/lib/utils.h +index ec717125..1e440795 100644 +--- a/lib/utils.h ++++ b/lib/utils.h +@@ -70,6 +70,7 @@ extern int inet_inaddrcmp(int, void *, void *); + extern int inet_sockaddrcmp(struct sockaddr_storage *, struct sockaddr_storage *); + extern char *get_local_name(void); + extern int string_equal(const char *, const char *); ++extern FILE *fopen_safe(const char *, const char *); + extern void set_std_fd(int); + #if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_ + extern int fork_exec(char **argv); diff --git a/SOURCES/bz1667292-fix-vrrp_script-misc_script.patch b/SOURCES/bz1667292-fix-vrrp_script-misc_script.patch new file mode 100644 index 0000000..355d3cd --- /dev/null +++ b/SOURCES/bz1667292-fix-vrrp_script-misc_script.patch @@ -0,0 +1,54 @@ +From 83d10ba08b8cd550196ae14f4f40fdbb72078057 Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Thu, 22 Mar 2018 16:54:54 +0000 +Subject: [PATCH] Fix vrrp_script and check_misc scripts of type + +--- + keepalived/check/check_misc.c | 8 ++++++++ + keepalived/vrrp/vrrp.c | 7 +++++++ + 2 files changed, 15 insertions(+) + +diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c +index ccb9b63b..7d7e740b 100644 +--- a/keepalived/check/check_misc.c ++++ b/keepalived/check/check_misc.c +@@ -149,6 +149,14 @@ check_misc_script_security(void) + continue; + + misc_script = CHECKER_ARG(checker); ++ ++ /* If the misc check script starts "path[0] == '<' && ++ misc_script->path[strspn(misc_script->path + 1, " \t") + 1] == '/') ++ return 0; ++ + script.name = misc_script->path; + script.uid = misc_script->uid; + script.gid = misc_script->gid; +diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c +index 3d2bfe41..c18a8d17 100644 +--- a/keepalived/vrrp/vrrp.c ++++ b/keepalived/vrrp/vrrp.c +@@ -149,6 +149,13 @@ check_track_script_secure(tracked_sc_t *script) + if (script->scr->insecure) + return 0; + ++ /* If the track script starts "scr->script[0] == '<' && ++ script->scr->script[strspn(script->scr->script + 1, " \t") + 1] == '/') ++ return 0; ++ + ns.name = script->scr->script; + ns.uid = script->scr->uid; + ns.gid = script->scr->gid; +-- +2.21.0 + diff --git a/SOURCES/bz1678480-add-child_wait_time.patch b/SOURCES/bz1678480-add-child_wait_time.patch new file mode 100644 index 0000000..11e4db7 --- /dev/null +++ b/SOURCES/bz1678480-add-child_wait_time.patch @@ -0,0 +1,158 @@ +From d3292ee776448de67241bf7efc8f9bb23f166752 Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Fri, 2 Feb 2018 10:12:06 +0000 +Subject: [PATCH 1/8] Add child_wait_time to allow longer shutdown time of + child processes + +With very large configurations it can be necessary to allow longer than +the default 5 seconds for child processes to cleanup and terminate. + +Signed-off-by: Quentin Armitage +--- + doc/keepalived.conf.SYNOPSIS | 5 ++++- + doc/man/man5/keepalived.conf.5 | 3 +++ + keepalived/core/global_parser.c | 19 +++++++++++++++++++ + keepalived/core/main.c | 12 +++++++----- + keepalived/include/main.h | 3 +++ + lib/parser.c | 2 ++ + 6 files changed, 38 insertions(+), 6 deletions(-) + +diff --git a/doc/keepalived.conf.SYNOPSIS b/doc/keepalived.conf.SYNOPSIS +index 90eb83d4..3d042b1c 100644 +--- a/doc/keepalived.conf.SYNOPSIS ++++ b/doc/keepalived.conf.SYNOPSIS +@@ -176,7 +176,10 @@ use_pid_dir # Create pid files in /var/run/keepalived + + linkbeat_use_polling # Use media link failure detection polling fashion + +- 1.2. Static addresses ++child_wait_time SECS # Time for main process to allow for child processes to exit on termination ++ # in seconds (default 5). This can be needed for very large configurations. ++ ++ 1.2. Static addresses + + The configuration block looks like : + +diff --git a/doc/man/man5/keepalived.conf.5 b/doc/man/man5/keepalived.conf.5 +index 1dabdec7..d0d04727 100644 +--- a/doc/man/man5/keepalived.conf.5 ++++ b/doc/man/man5/keepalived.conf.5 +@@ -219,6 +219,9 @@ and + + linkbeat_use_polling # Poll to detect media link failure otherwise attempt to use ETHTOOL or MII interface + ++ child_wait_time SECS # Time for main process to allow for child processes to exit on termination ++ # in seconds (default 5). This can be needed for very large configurations. ++ + .SH Static routes/addresses/rules + .PP + Keepalived can configure static addresses, routes, and rules. These addresses are +diff --git a/keepalived/core/global_parser.c b/keepalived/core/global_parser.c +index a59fbc0b..e8ed6333 100644 +--- a/keepalived/core/global_parser.c ++++ b/keepalived/core/global_parser.c +@@ -719,6 +719,24 @@ script_security_handler(__attribute__((unused)) vector_t *strvec) + global_data->script_security = true; + } + ++static void ++child_wait_handler(vector_t *strvec) ++{ ++ char *endptr; ++ unsigned long secs; ++ ++ if (!strvec) ++ return; ++ ++ secs = strtoul(strvec_slot(strvec,1), &endptr, 10); ++ if (*endptr) { ++ log_message(LOG_INFO, "Invalid child_wait_time %s", FMT_STR_VSLOT(strvec, 1)); ++ return; ++ } ++ ++ child_wait_time = secs; ++} ++ + void + init_global_keywords(bool global_active) + { +@@ -730,6 +748,7 @@ init_global_keywords(bool global_active) + #endif + install_keyword_root("use_pid_dir", &use_pid_dir_handler, !global_active); + install_keyword_root("instance", &instance_handler, !global_active); ++ install_keyword_root("child_wait_time", &child_wait_handler, !global_active); + install_keyword_root("global_defs", NULL, global_active); + install_keyword("router_id", &routerid_handler); + install_keyword("notification_email_from", &emailfrom_handler); +diff --git a/keepalived/core/main.c b/keepalived/core/main.c +index 95bb76a9..51f83a07 100644 +--- a/keepalived/core/main.c ++++ b/keepalived/core/main.c +@@ -93,6 +93,8 @@ bool namespace_with_ipsets; /* Override for using namespaces and ipsets with + static char *override_namespace; /* If namespace specified on command line */ + #endif + ++unsigned child_wait_time = CHILD_WAIT_SECS; /* Time to wait for children to exit */ ++ + /* Log facility table */ + static struct { + int facility; +@@ -359,7 +361,7 @@ sigend(__attribute__((unused)) void *v, __attribute__((unused)) int sig) + int wait_count = 0; + sigset_t old_set, child_wait; + struct timespec timeout = { +- .tv_sec = CHILD_WAIT_SECS, ++ .tv_sec = child_wait_time, + .tv_nsec = 0 + }; + struct timeval start_time, now; +@@ -416,17 +418,17 @@ sigend(__attribute__((unused)) void *v, __attribute__((unused)) int sig) + gettimeofday(&now, NULL); + if (now.tv_usec < start_time.tv_usec) { + timeout.tv_nsec = (start_time.tv_usec - now.tv_usec) * 1000; +- timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec); ++ timeout.tv_sec = child_wait_time - (now.tv_sec - start_time.tv_sec); + } else if (now.tv_usec == start_time.tv_usec) { + timeout.tv_nsec = 0; +- timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec); ++ timeout.tv_sec = child_wait_time - (now.tv_sec - start_time.tv_sec); + } else { + timeout.tv_nsec = (1000000L + start_time.tv_usec - now.tv_usec) * 1000; +- timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec + 1); ++ timeout.tv_sec = child_wait_time - (now.tv_sec - start_time.tv_sec + 1); + } + + timeout.tv_nsec = (start_time.tv_usec - now.tv_usec) * 1000; +- timeout.tv_sec = CHILD_WAIT_SECS - (now.tv_sec - start_time.tv_sec); ++ timeout.tv_sec = child_wait_time - (now.tv_sec - start_time.tv_sec); + if (timeout.tv_nsec < 0) { + timeout.tv_nsec += 1000000000L; + timeout.tv_sec--; +diff --git a/keepalived/include/main.h b/keepalived/include/main.h +index eebde77e..b03a7efd 100644 +--- a/keepalived/include/main.h ++++ b/keepalived/include/main.h +@@ -82,4 +82,7 @@ extern void free_parent_mallocs_exit(void); + extern char *make_syslog_ident(const char*); + + extern int keepalived_main(int, char**); /* The "real" main function */ ++ ++extern unsigned child_wait_time; ++ + #endif +diff --git a/lib/parser.c b/lib/parser.c +index a5c3465b..2e1beac8 100644 +--- a/lib/parser.c ++++ b/lib/parser.c +@@ -120,6 +120,8 @@ install_sublevel_end(void) + void + install_keyword_root(const char *string, void (*handler) (vector_t *), bool active) + { ++ /* If the root keyword is inactive, the handler will still be called, ++ * but with a NULL strvec */ + keyword_alloc(keywords, string, handler, active); + } + +-- +2.20.1 + diff --git a/SOURCES/bz1678480-fix-checker-coding-style.patch b/SOURCES/bz1678480-fix-checker-coding-style.patch new file mode 100644 index 0000000..6b12508 --- /dev/null +++ b/SOURCES/bz1678480-fix-checker-coding-style.patch @@ -0,0 +1,350 @@ +From 99ad17d4906f478c51b58ab8f288edbca0bab906 Mon Sep 17 00:00:00 2001 +From: YAMAMOTO Masaya +Date: Fri, 14 Jul 2017 14:34:28 +0900 +Subject: [PATCH 6/8] Fix to match coding style + +--- + keepalived/check/check_api.c | 22 ++++++++++------------ + keepalived/check/check_dns.c | 20 +++++++++----------- + keepalived/check/check_http.c | 26 ++++++++++++-------------- + keepalived/check/check_misc.c | 18 ++++++++---------- + keepalived/check/check_smtp.c | 26 ++++++++++++-------------- + keepalived/check/check_tcp.c | 18 ++++++++---------- + keepalived/include/check_api.h | 6 +++--- + 7 files changed, 62 insertions(+), 74 deletions(-) + +diff --git a/keepalived/check/check_api.c b/keepalived/check/check_api.c +index a722fc84..1d915414 100644 +--- a/keepalived/check/check_api.c ++++ b/keepalived/check/check_api.c +@@ -81,7 +81,7 @@ dump_conn_opts(void *data) + void + queue_checker(void (*free_func) (void *), void (*dump_func) (void *) + , int (*launch) (thread_t *) +- , int (*compare) (void *, void *) ++ , bool (*compare) (void *, void *) + , void *data + , conn_opts_t *co) + { +@@ -120,28 +120,26 @@ queue_checker(void (*free_func) (void *), void (*dump_func) (void *) + } + } + +-int ++bool + compare_conn_opts(conn_opts_t *a, conn_opts_t *b) + { + if (a == b) +- return 0; ++ return true; + + if (!a || !b) +- goto err; ++ return false; + if (!sockstorage_equal(&a->dst, &b->dst)) +- goto err; ++ return false; + if (!sockstorage_equal(&a->bindto, &b->bindto)) +- goto err; +- //if (a->connection_to != b->connection_to) +- // goto err; ++ return false; ++ if (a->connection_to != b->connection_to) ++ return false; + #ifdef _WITH_SO_MARK_ + if (a->fwmark != b->fwmark) +- goto err; ++ return false; + #endif + +- return 0; +-err: +- return -1; ++ return true; + } + + static void +diff --git a/keepalived/check/check_dns.c b/keepalived/check/check_dns.c +index 84a5f56d..603742a4 100644 +--- a/keepalived/check/check_dns.c ++++ b/keepalived/check/check_dns.c +@@ -388,24 +388,22 @@ dns_dump(void *data) + log_message(LOG_INFO, " Name = %s", dns_check->name); + } + +-static int +-dns_compare(void *a, void *b) ++static bool ++dns_check_compare(void *a, void *b) + { + dns_check_t *old = CHECKER_DATA(a); + dns_check_t *new = CHECKER_DATA(b); + +- if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) +- goto err; ++ if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) ++ return false; + if (old->retry != new->retry) +- goto err; ++ return false; + if (strcmp(old->type, new->type) != 0) +- goto err; ++ return false; + if (strcmp(old->name, new->name) != 0) +- goto err; ++ return false; + +- return 0; +-err: +- return -1; ++ return true; + } + + static void +@@ -417,7 +415,7 @@ dns_check_handler(__attribute__((unused)) vector_t * strvec) + dns_check->type = DNS_DEFAULT_TYPE; + dns_check->name = DNS_DEFAULT_NAME; + queue_checker(dns_free, dns_dump, dns_connect_thread, +- dns_compare, dns_check, CHECKER_NEW_CO()); ++ dns_check_compare, dns_check, CHECKER_NEW_CO()); + } + + static void +diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c +index c2089a3b..1ad395cf 100644 +--- a/keepalived/check/check_http.c ++++ b/keepalived/check/check_http.c +@@ -123,36 +123,34 @@ alloc_http_get(char *proto) + return http_get_chk; + } + +-static int +-compare_http_get_check(void *a, void *b) ++static bool ++http_get_check_compare(void *a, void *b) + { + http_checker_t *old = CHECKER_DATA(a); + http_checker_t *new = CHECKER_DATA(b); + size_t n; + url_t *u1, *u2; + +- if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) +- goto err; ++ if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) ++ return false; + if (old->nb_get_retry != new->nb_get_retry) +- goto err; ++ return false; + if (old->delay_before_retry != new->delay_before_retry) +- goto err; ++ return false; + if (LIST_SIZE(old->url) != LIST_SIZE(new->url)) +- goto err; ++ return false; + for (n = 0; n < LIST_SIZE(new->url); n++) { + u1 = (url_t *)list_element(old->url, n); + u2 = (url_t *)list_element(new->url, n); + if (strcmp(u1->path, u2->path) != 0) +- goto err; ++ return false; + if (strcmp(u1->digest, u2->digest) != 0) +- goto err; ++ return false; + if (u1->status_code != u2->status_code) +- goto err; ++ return false; + } + +- return 0; +-err: +- return -1; ++ return true; + } + + static void +@@ -164,7 +162,7 @@ http_get_handler(vector_t *strvec) + /* queue new checker */ + http_get_chk = alloc_http_get(str); + queue_checker(free_http_get_check, dump_http_get_check, +- http_connect_thread, compare_http_get_check, ++ http_connect_thread, http_get_check_compare, + http_get_chk, CHECKER_NEW_CO()); + } + +diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c +index 311a1127..f1f66955 100644 +--- a/keepalived/check/check_misc.c ++++ b/keepalived/check/check_misc.c +@@ -72,24 +72,22 @@ dump_misc_check(void *data) + log_message(LOG_INFO, " insecure = %s", misck_checker->insecure ? "Yes" : "No"); + } + +-static int +-compare_misc_check(void *a, void *b) ++static bool ++misc_check_compare(void *a, void *b) + { + misc_checker_t *old = CHECKER_DATA(a); + misc_checker_t *new = CHECKER_DATA(b); + + if (strcmp(old->path, new->path) != 0) +- goto err; ++ return false; + if (old->timeout != new->timeout) +- goto err; ++ return false; + if (old->dynamic != new->dynamic) +- goto err; ++ return false; + if (old->uid != new->uid || new->gid != new->gid) +- goto err; ++ return false; + +- return 0; +-err: +- return -1; ++ return true; + } + + static void +@@ -169,7 +167,7 @@ log_message(LOG_INFO, "Setting uid.gid"); + } + + /* queue new checker */ +- queue_checker(free_misc_check, dump_misc_check, misc_check_thread, compare_misc_check, misck_checker, NULL); ++ queue_checker(free_misc_check, dump_misc_check, misc_check_thread, misc_check_compare, misck_checker, NULL); + misck_checker = NULL; + log_message(LOG_INFO, "Leaving misc_end_handler"); + } +diff --git a/keepalived/check/check_smtp.c b/keepalived/check/check_smtp.c +index e19511cc..44d15e01 100644 +--- a/keepalived/check/check_smtp.c ++++ b/keepalived/check/check_smtp.c +@@ -82,8 +82,8 @@ dump_smtp_check(void *data) + dump_list(smtp_checker->host); + } + +-static int +-compare_smtp_check(void *a, void *b) ++static bool ++smtp_check_compare(void *a, void *b) + { + smtp_checker_t *old = CHECKER_DATA(a); + smtp_checker_t *new = CHECKER_DATA(b); +@@ -91,26 +91,24 @@ compare_smtp_check(void *a, void *b) + smtp_host_t *h1, *h2; + + if (strcmp(old->helo_name, new->helo_name) != 0) +- goto err; ++ return false; + if (old->retry != new->retry) +- goto err; ++ return false; + if (old->db_retry != new->db_retry) +- goto err; +- if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) +- goto err; ++ return false; ++ if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) ++ return false; + if (LIST_SIZE(old->host) != LIST_SIZE(new->host)) +- goto err; ++ return false; + for (n = 0; n < LIST_SIZE(new->host); n++) { + h1 = (smtp_host_t *)list_element(old->host, n); + h2 = (smtp_host_t *)list_element(new->host, n); +- if (compare_conn_opts(h1, h2) != 0) { +- goto err; ++ if (!compare_conn_opts(h1, h2)) { ++ return false; + } + } + +- return 0; +-err: +- return -1; ++ return true; + } + + /* Allocates a default host structure */ +@@ -167,7 +165,7 @@ smtp_check_handler(__attribute__((unused)) vector_t *strvec) + * void *data, conn_opts_t *) + */ + queue_checker(free_smtp_check, dump_smtp_check, smtp_connect_thread, +- compare_smtp_check, smtp_checker, smtp_checker->default_co); ++ smtp_check_compare, smtp_checker, smtp_checker->default_co); + + /* + * Last, allocate the list that will hold all the per host +diff --git a/keepalived/check/check_tcp.c b/keepalived/check/check_tcp.c +index 026a0e3c..1858f5fc 100644 +--- a/keepalived/check/check_tcp.c ++++ b/keepalived/check/check_tcp.c +@@ -62,22 +62,20 @@ dump_tcp_check(void *data) + } + } + +-static int +-compare_tcp_check(void *a, void *b) ++static bool ++tcp_check_compare(void *a, void *b) + { + tcp_check_t *old = CHECKER_DATA(a); + tcp_check_t *new = CHECKER_DATA(b); + +- if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) +- goto err; ++ if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) ++ return false; + if (old->n_retry != new->n_retry) +- goto err; ++ return false; + if (old->delay_before_retry != new->delay_before_retry) +- goto err; ++ return false; + +- return 0; +-err: +- return -1; ++ return true; + } + + static void +@@ -91,7 +89,7 @@ tcp_check_handler(__attribute__((unused)) vector_t *strvec) + + /* queue new checker */ + queue_checker(free_tcp_check, dump_tcp_check, tcp_connect_thread, +- compare_tcp_check, tcp_check, CHECKER_NEW_CO()); ++ tcp_check_compare, tcp_check, CHECKER_NEW_CO()); + } + + static void +diff --git a/keepalived/include/check_api.h b/keepalived/include/check_api.h +index 4a10a36b..c7bc297d 100644 +--- a/keepalived/include/check_api.h ++++ b/keepalived/include/check_api.h +@@ -36,7 +36,7 @@ typedef struct _checker { + void (*free_func) (void *); + void (*dump_func) (void *); + int (*launch) (struct _thread *); +- int (*compare) (void *, void *); ++ bool (*compare) (void *, void *); + virtual_server_t *vs; /* pointer to the checker thread virtualserver */ + real_server_t *rs; /* pointer to the checker thread realserver */ + void *data; +@@ -71,10 +71,10 @@ extern void init_checkers_queue(void); + extern void dump_conn_opts(void *); + extern void queue_checker(void (*free_func) (void *), void (*dump_func) (void *) + , int (*launch) (thread_t *) +- , int (*compare) (void *, void *) ++ , bool (*compare) (void *, void *) + , void * + , conn_opts_t *); +-extern int compare_conn_opts(conn_opts_t *, conn_opts_t *); ++extern bool compare_conn_opts(conn_opts_t *, conn_opts_t *); + extern void dump_checkers_queue(void); + extern void free_checkers_queue(void); + extern void register_checkers_thread(void); +-- +2.20.1 + diff --git a/SOURCES/bz1678480-fix-wrong-migrate-checker-id.patch b/SOURCES/bz1678480-fix-wrong-migrate-checker-id.patch new file mode 100644 index 0000000..eb171fe --- /dev/null +++ b/SOURCES/bz1678480-fix-wrong-migrate-checker-id.patch @@ -0,0 +1,25 @@ +From cd8b3f6b79d8cd5e89a05825144277785933b687 Mon Sep 17 00:00:00 2001 +From: YAMAMOTO Masaya +Date: Tue, 11 Jul 2017 15:47:12 +0900 +Subject: [PATCH 4/8] Fix worng migrate of checker-id + +--- + keepalived/check/ipwrapper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index 49262e25..09d86f08 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -651,7 +651,7 @@ migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs) + if (old_c->compare == new_c->compare && new_c->compare(old_c, new_c) == 0) { + if (svr_checker_up(old_c->id, old_rs) == 0) { + id = (checker_id_t *) MALLOC(sizeof(checker_id_t)); +- *id = old_c->id; ++ *id = new_c->id; + list_add(new_rs->failed_checkers, id); + } + break; +-- +2.20.1 + diff --git a/SOURCES/bz1678480-implment-checker-comparison.patch b/SOURCES/bz1678480-implment-checker-comparison.patch new file mode 100644 index 0000000..b542750 --- /dev/null +++ b/SOURCES/bz1678480-implment-checker-comparison.patch @@ -0,0 +1,420 @@ +From fce93460597d27a86798c57ec410f63e4bd33be9 Mon Sep 17 00:00:00 2001 +From: YAMAMOTO Masaya +Date: Fri, 7 Jul 2017 19:27:16 +0900 +Subject: [PATCH 3/8] Implement comparison of checkers + +--- + keepalived/check/check_api.c | 29 ++++++++++++++++++++++++- + keepalived/check/check_daemon.c | 7 +++++- + keepalived/check/check_dns.c | 24 +++++++++++++++++++-- + keepalived/check/check_http.c | 35 +++++++++++++++++++++++++++++- + keepalived/check/check_misc.c | 22 ++++++++++++++++++- + keepalived/check/check_smtp.c | 33 +++++++++++++++++++++++++++- + keepalived/check/check_tcp.c | 22 +++++++++++++++++-- + keepalived/check/ipwrapper.c | 38 +++++++++++++++++++++++++-------- + keepalived/include/check_api.h | 5 +++++ + 9 files changed, 197 insertions(+), 18 deletions(-) + +diff --git a/keepalived/check/check_api.c b/keepalived/check/check_api.c +index b7081fd0..a722fc84 100644 +--- a/keepalived/check/check_api.c ++++ b/keepalived/check/check_api.c +@@ -42,8 +42,9 @@ + #include "check_dns.h" + + /* Global vars */ +-static checker_id_t ncheckers = 0; ++checker_id_t ncheckers = 0; + list checkers_queue; ++list old_checkers_queue; + + /* free checker data */ + static void +@@ -80,6 +81,7 @@ dump_conn_opts(void *data) + void + queue_checker(void (*free_func) (void *), void (*dump_func) (void *) + , int (*launch) (thread_t *) ++ , int (*compare) (void *, void *) + , void *data + , conn_opts_t *co) + { +@@ -96,6 +98,7 @@ queue_checker(void (*free_func) (void *), void (*dump_func) (void *) + checker->free_func = free_func; + checker->dump_func = dump_func; + checker->launch = launch; ++ checker->compare = compare; + checker->vs = vs; + checker->rs = rs; + checker->data = data; +@@ -117,6 +120,30 @@ queue_checker(void (*free_func) (void *), void (*dump_func) (void *) + } + } + ++int ++compare_conn_opts(conn_opts_t *a, conn_opts_t *b) ++{ ++ if (a == b) ++ return 0; ++ ++ if (!a || !b) ++ goto err; ++ if (!sockstorage_equal(&a->dst, &b->dst)) ++ goto err; ++ if (!sockstorage_equal(&a->bindto, &b->bindto)) ++ goto err; ++ //if (a->connection_to != b->connection_to) ++ // goto err; ++#ifdef _WITH_SO_MARK_ ++ if (a->fwmark != b->fwmark) ++ goto err; ++#endif ++ ++ return 0; ++err: ++ return -1; ++} ++ + static void + checker_set_dst_port(struct sockaddr_storage *dst, uint16_t port) + { +diff --git a/keepalived/check/check_daemon.c b/keepalived/check/check_daemon.c +index a3ff8cab..462360e6 100644 +--- a/keepalived/check/check_daemon.c ++++ b/keepalived/check/check_daemon.c +@@ -233,7 +233,11 @@ reload_check_thread(__attribute__((unused)) thread_t * thread) + thread_cleanup_master(master); + free_global_data(global_data); + +- free_checkers_queue(); ++ /* Save previous checker data */ ++ old_checkers_queue = checkers_queue; ++ checkers_queue = NULL; ++ ncheckers = 0; ++ + free_ssl(); + ipvs_stop(); + +@@ -246,6 +250,7 @@ reload_check_thread(__attribute__((unused)) thread_t * thread) + + /* free backup data */ + free_check_data(old_check_data); ++ free_list(&old_checkers_queue); + UNSET_RELOAD; + + return 0; +diff --git a/keepalived/check/check_dns.c b/keepalived/check/check_dns.c +index 96328027..84a5f56d 100644 +--- a/keepalived/check/check_dns.c ++++ b/keepalived/check/check_dns.c +@@ -388,6 +388,26 @@ dns_dump(void *data) + log_message(LOG_INFO, " Name = %s", dns_check->name); + } + ++static int ++dns_compare(void *a, void *b) ++{ ++ dns_check_t *old = CHECKER_DATA(a); ++ dns_check_t *new = CHECKER_DATA(b); ++ ++ if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) ++ goto err; ++ if (old->retry != new->retry) ++ goto err; ++ if (strcmp(old->type, new->type) != 0) ++ goto err; ++ if (strcmp(old->name, new->name) != 0) ++ goto err; ++ ++ return 0; ++err: ++ return -1; ++} ++ + static void + dns_check_handler(__attribute__((unused)) vector_t * strvec) + { +@@ -396,8 +416,8 @@ dns_check_handler(__attribute__((unused)) vector_t * strvec) + dns_check->attempts = 0; + dns_check->type = DNS_DEFAULT_TYPE; + dns_check->name = DNS_DEFAULT_NAME; +- queue_checker(dns_free, dns_dump, dns_connect_thread, dns_check, +- CHECKER_NEW_CO()); ++ queue_checker(dns_free, dns_dump, dns_connect_thread, ++ dns_compare, dns_check, CHECKER_NEW_CO()); + } + + static void +diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c +index 05e29b23..c2089a3b 100644 +--- a/keepalived/check/check_http.c ++++ b/keepalived/check/check_http.c +@@ -123,6 +123,38 @@ alloc_http_get(char *proto) + return http_get_chk; + } + ++static int ++compare_http_get_check(void *a, void *b) ++{ ++ http_checker_t *old = CHECKER_DATA(a); ++ http_checker_t *new = CHECKER_DATA(b); ++ size_t n; ++ url_t *u1, *u2; ++ ++ if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) ++ goto err; ++ if (old->nb_get_retry != new->nb_get_retry) ++ goto err; ++ if (old->delay_before_retry != new->delay_before_retry) ++ goto err; ++ if (LIST_SIZE(old->url) != LIST_SIZE(new->url)) ++ goto err; ++ for (n = 0; n < LIST_SIZE(new->url); n++) { ++ u1 = (url_t *)list_element(old->url, n); ++ u2 = (url_t *)list_element(new->url, n); ++ if (strcmp(u1->path, u2->path) != 0) ++ goto err; ++ if (strcmp(u1->digest, u2->digest) != 0) ++ goto err; ++ if (u1->status_code != u2->status_code) ++ goto err; ++ } ++ ++ return 0; ++err: ++ return -1; ++} ++ + static void + http_get_handler(vector_t *strvec) + { +@@ -132,7 +164,8 @@ http_get_handler(vector_t *strvec) + /* queue new checker */ + http_get_chk = alloc_http_get(str); + queue_checker(free_http_get_check, dump_http_get_check, +- http_connect_thread, http_get_chk, CHECKER_NEW_CO()); ++ http_connect_thread, compare_http_get_check, ++ http_get_chk, CHECKER_NEW_CO()); + } + + static void +diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c +index 10ac1e23..311a1127 100644 +--- a/keepalived/check/check_misc.c ++++ b/keepalived/check/check_misc.c +@@ -72,6 +72,26 @@ dump_misc_check(void *data) + log_message(LOG_INFO, " insecure = %s", misck_checker->insecure ? "Yes" : "No"); + } + ++static int ++compare_misc_check(void *a, void *b) ++{ ++ misc_checker_t *old = CHECKER_DATA(a); ++ misc_checker_t *new = CHECKER_DATA(b); ++ ++ if (strcmp(old->path, new->path) != 0) ++ goto err; ++ if (old->timeout != new->timeout) ++ goto err; ++ if (old->dynamic != new->dynamic) ++ goto err; ++ if (old->uid != new->uid || new->gid != new->gid) ++ goto err; ++ ++ return 0; ++err: ++ return -1; ++} ++ + static void + misc_check_handler(__attribute__((unused)) vector_t *strvec) + { +@@ -149,7 +169,7 @@ log_message(LOG_INFO, "Setting uid.gid"); + } + + /* queue new checker */ +- queue_checker(free_misc_check, dump_misc_check, misc_check_thread, misck_checker, NULL); ++ queue_checker(free_misc_check, dump_misc_check, misc_check_thread, compare_misc_check, misck_checker, NULL); + misck_checker = NULL; + log_message(LOG_INFO, "Leaving misc_end_handler"); + } +diff --git a/keepalived/check/check_smtp.c b/keepalived/check/check_smtp.c +index 901b77f5..e19511cc 100644 +--- a/keepalived/check/check_smtp.c ++++ b/keepalived/check/check_smtp.c +@@ -82,6 +82,37 @@ dump_smtp_check(void *data) + dump_list(smtp_checker->host); + } + ++static int ++compare_smtp_check(void *a, void *b) ++{ ++ smtp_checker_t *old = CHECKER_DATA(a); ++ smtp_checker_t *new = CHECKER_DATA(b); ++ size_t n; ++ smtp_host_t *h1, *h2; ++ ++ if (strcmp(old->helo_name, new->helo_name) != 0) ++ goto err; ++ if (old->retry != new->retry) ++ goto err; ++ if (old->db_retry != new->db_retry) ++ goto err; ++ if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) ++ goto err; ++ if (LIST_SIZE(old->host) != LIST_SIZE(new->host)) ++ goto err; ++ for (n = 0; n < LIST_SIZE(new->host); n++) { ++ h1 = (smtp_host_t *)list_element(old->host, n); ++ h2 = (smtp_host_t *)list_element(new->host, n); ++ if (compare_conn_opts(h1, h2) != 0) { ++ goto err; ++ } ++ } ++ ++ return 0; ++err: ++ return -1; ++} ++ + /* Allocates a default host structure */ + static smtp_host_t * + smtp_alloc_host(void) +@@ -136,7 +167,7 @@ smtp_check_handler(__attribute__((unused)) vector_t *strvec) + * void *data, conn_opts_t *) + */ + queue_checker(free_smtp_check, dump_smtp_check, smtp_connect_thread, +- smtp_checker, smtp_checker->default_co); ++ compare_smtp_check, smtp_checker, smtp_checker->default_co); + + /* + * Last, allocate the list that will hold all the per host +diff --git a/keepalived/check/check_tcp.c b/keepalived/check/check_tcp.c +index 078ba705..026a0e3c 100644 +--- a/keepalived/check/check_tcp.c ++++ b/keepalived/check/check_tcp.c +@@ -62,6 +62,24 @@ dump_tcp_check(void *data) + } + } + ++static int ++compare_tcp_check(void *a, void *b) ++{ ++ tcp_check_t *old = CHECKER_DATA(a); ++ tcp_check_t *new = CHECKER_DATA(b); ++ ++ if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0) ++ goto err; ++ if (old->n_retry != new->n_retry) ++ goto err; ++ if (old->delay_before_retry != new->delay_before_retry) ++ goto err; ++ ++ return 0; ++err: ++ return -1; ++} ++ + static void + tcp_check_handler(__attribute__((unused)) vector_t *strvec) + { +@@ -72,8 +90,8 @@ tcp_check_handler(__attribute__((unused)) vector_t *strvec) + tcp_check->delay_before_retry = 1 * TIMER_HZ; + + /* queue new checker */ +- queue_checker(free_tcp_check, dump_tcp_check, tcp_connect_thread +- ,tcp_check, CHECKER_NEW_CO()); ++ queue_checker(free_tcp_check, dump_tcp_check, tcp_connect_thread, ++ compare_tcp_check, tcp_check, CHECKER_NEW_CO()); + } + + static void +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index 6acf18ba..49262e25 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -626,20 +626,40 @@ rs_exist(real_server_t * old_rs, list l) + static void + migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs) + { +- element e; +- checker_t *checker; ++ list l; ++ element e, e1; ++ checker_t *old_c, *new_c; + checker_id_t *id; + +- /* Notes: It's a provisional implementation */ +- (void)old_rs; ++ l = alloc_list(NULL, NULL); ++ for (e = LIST_HEAD(old_checkers_queue); e; ELEMENT_NEXT(e)) { ++ old_c = ELEMENT_DATA(e); ++ if (old_c->rs == old_rs) { ++ list_add(l, old_c); ++ } ++ } ++ ++ if (LIST_ISEMPTY(l)) ++ goto end; ++ + for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { +- checker = ELEMENT_DATA(e); +- if (checker->rs == new_rs) { +- id = (checker_id_t *) MALLOC(sizeof(checker_id_t)); +- *id = checker->id; +- list_add(new_rs->failed_checkers, id); ++ new_c = ELEMENT_DATA(e); ++ if (new_c->rs != new_rs || !new_c->compare) ++ continue; ++ for (e1 = LIST_HEAD(l); e1; ELEMENT_NEXT(e1)) { ++ old_c = ELEMENT_DATA(e1); ++ if (old_c->compare == new_c->compare && new_c->compare(old_c, new_c) == 0) { ++ if (svr_checker_up(old_c->id, old_rs) == 0) { ++ id = (checker_id_t *) MALLOC(sizeof(checker_id_t)); ++ *id = old_c->id; ++ list_add(new_rs->failed_checkers, id); ++ } ++ break; ++ } + } + } ++end: ++ free_list(&l); + } + + /* Clear the diff rs of the old vs */ +diff --git a/keepalived/include/check_api.h b/keepalived/include/check_api.h +index 359c794a..4a10a36b 100644 +--- a/keepalived/include/check_api.h ++++ b/keepalived/include/check_api.h +@@ -36,6 +36,7 @@ typedef struct _checker { + void (*free_func) (void *); + void (*dump_func) (void *); + int (*launch) (struct _thread *); ++ int (*compare) (void *, void *); + virtual_server_t *vs; /* pointer to the checker thread virtualserver */ + real_server_t *rs; /* pointer to the checker thread realserver */ + void *data; +@@ -46,7 +47,9 @@ typedef struct _checker { + } checker_t; + + /* Checkers queue */ ++extern checker_id_t ncheckers; + extern list checkers_queue; ++extern list old_checkers_queue; + + /* utility macro */ + #define CHECKER_ARG(X) ((X)->data) +@@ -68,8 +71,10 @@ extern void init_checkers_queue(void); + extern void dump_conn_opts(void *); + extern void queue_checker(void (*free_func) (void *), void (*dump_func) (void *) + , int (*launch) (thread_t *) ++ , int (*compare) (void *, void *) + , void * + , conn_opts_t *); ++extern int compare_conn_opts(conn_opts_t *, conn_opts_t *); + extern void dump_checkers_queue(void); + extern void free_checkers_queue(void); + extern void register_checkers_thread(void); +-- +2.20.1 + diff --git a/SOURCES/bz1678480-include-check_api-in-ipwrapper.patch b/SOURCES/bz1678480-include-check_api-in-ipwrapper.patch new file mode 100644 index 0000000..6d97ff0 --- /dev/null +++ b/SOURCES/bz1678480-include-check_api-in-ipwrapper.patch @@ -0,0 +1,24 @@ +From 44ad4db4a45c7f152c074dacab48e051b42fde53 Mon Sep 17 00:00:00 2001 +From: Ryan O'Hara +Date: Wed, 3 Apr 2019 07:28:56 -0500 +Subject: [PATCH] Include check_api in ipwrapper + +--- + keepalived/check/ipwrapper.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index c9dce2b7..17f0157d 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -24,6 +24,7 @@ + + #include "ipwrapper.h" + #include "ipvswrapper.h" ++#include "check_api.h" + #include "logger.h" + #include "memory.h" + #include "utils.h" +-- +2.20.1 + diff --git a/SOURCES/bz1678480-migrate-failed-checkers-reload.patch b/SOURCES/bz1678480-migrate-failed-checkers-reload.patch new file mode 100644 index 0000000..9b10fdd --- /dev/null +++ b/SOURCES/bz1678480-migrate-failed-checkers-reload.patch @@ -0,0 +1,89 @@ +From 6c5646bec26fe86214a34a877b84da83f9d9cfb4 Mon Sep 17 00:00:00 2001 +From: YAMAMOTO Masaya +Date: Tue, 4 Jul 2017 15:08:36 +0900 +Subject: [PATCH 2/8] Migrate failed checkers at reload (provisional + implementation) + +--- + keepalived/check/ipwrapper.c | 36 +++++++++++++++++++++++++----------- + 1 file changed, 25 insertions(+), 11 deletions(-) + +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index ecf12713..6acf18ba 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -623,9 +623,28 @@ rs_exist(real_server_t * old_rs, list l) + return NULL; + } + ++static void ++migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs) ++{ ++ element e; ++ checker_t *checker; ++ checker_id_t *id; ++ ++ /* Notes: It's a provisional implementation */ ++ (void)old_rs; ++ for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { ++ checker = ELEMENT_DATA(e); ++ if (checker->rs == new_rs) { ++ id = (checker_id_t *) MALLOC(sizeof(checker_id_t)); ++ *id = checker->id; ++ list_add(new_rs->failed_checkers, id); ++ } ++ } ++} ++ + /* Clear the diff rs of the old vs */ + static void +-clear_diff_rs(virtual_server_t * old_vs, list new_rs_list) ++clear_diff_rs(virtual_server_t *old_vs, virtual_server_t *new_vs) + { + element e; + list l = old_vs->rs; +@@ -639,7 +658,7 @@ clear_diff_rs(virtual_server_t * old_vs, list new_rs_list) + list rs_to_remove = alloc_list (NULL, NULL); + for (e = LIST_HEAD(l); e; ELEMENT_NEXT(e)) { + rs = ELEMENT_DATA(e); +- new_rs = rs_exist(rs, new_rs_list); ++ new_rs = rs_exist(rs, new_vs->rs); + if (!new_rs) { + /* Reset inhibit flag to delete inhibit entries */ + log_message(LOG_INFO, "service %s no longer exist" +@@ -662,20 +681,15 @@ clear_diff_rs(virtual_server_t * old_vs, list new_rs_list) + free_list_elements(new_rs->failed_checkers); + } else { + /* +- * if not alive, we must copy the failed checker list ++ * if not alive, we must migrate the failed checker list + * If we do not, the new RS is in a state where it’s reported + * as down with no check failed. As a result, the server will never + * be put up back when it’s alive again in check_tcp.c#83 because + * of the check that put a rs up only if it was not previously up + * based on the failed_checkers list + */ +- element hc_e; +- list hc_l = rs->failed_checkers; +- list new_hc_l = new_rs->failed_checkers; +- for (hc_e = LIST_HEAD(hc_l); hc_e; ELEMENT_NEXT(hc_e)) { +- list_add(new_hc_l, ELEMENT_DATA(hc_e)); +- ELEMENT_DATA(hc_e) = NULL; +- } ++ if (!new_vs->alpha) ++ migrate_failed_checkers(rs, new_rs); + } + } + } +@@ -748,7 +762,7 @@ clear_diff_services(void) + /* omega = false must not prevent the notifiers from being called, + because the VS still exists in new configuration */ + vs->omega = true; +- clear_diff_rs(vs, new_vs->rs); ++ clear_diff_rs(vs, new_vs); + clear_diff_s_srv(vs, new_vs->s_svr); + } + } +-- +2.20.1 + diff --git a/SOURCES/bz1678480-remove-unnecessary-parameter-compare.patch b/SOURCES/bz1678480-remove-unnecessary-parameter-compare.patch new file mode 100644 index 0000000..5f3f18b --- /dev/null +++ b/SOURCES/bz1678480-remove-unnecessary-parameter-compare.patch @@ -0,0 +1,91 @@ +From a6a44b6a8f8a6af9d1cef3efaae9331e24257572 Mon Sep 17 00:00:00 2001 +From: YAMAMOTO Masaya +Date: Fri, 14 Jul 2017 14:47:00 +0900 +Subject: [PATCH 7/8] Remove unnecessary parameter compare + +--- + keepalived/check/check_dns.c | 2 -- + keepalived/check/check_http.c | 4 ---- + keepalived/check/check_misc.c | 6 ------ + keepalived/check/check_smtp.c | 4 ---- + keepalived/check/check_tcp.c | 4 ---- + 5 files changed, 20 deletions(-) + +diff --git a/keepalived/check/check_dns.c b/keepalived/check/check_dns.c +index 603742a4..671062bf 100644 +--- a/keepalived/check/check_dns.c ++++ b/keepalived/check/check_dns.c +@@ -396,8 +396,6 @@ dns_check_compare(void *a, void *b) + + if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) + return false; +- if (old->retry != new->retry) +- return false; + if (strcmp(old->type, new->type) != 0) + return false; + if (strcmp(old->name, new->name) != 0) +diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c +index 1ad395cf..2802d6f5 100644 +--- a/keepalived/check/check_http.c ++++ b/keepalived/check/check_http.c +@@ -133,10 +133,6 @@ http_get_check_compare(void *a, void *b) + + if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) + return false; +- if (old->nb_get_retry != new->nb_get_retry) +- return false; +- if (old->delay_before_retry != new->delay_before_retry) +- return false; + if (LIST_SIZE(old->url) != LIST_SIZE(new->url)) + return false; + for (n = 0; n < LIST_SIZE(new->url); n++) { +diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c +index f1f66955..0cc649b6 100644 +--- a/keepalived/check/check_misc.c ++++ b/keepalived/check/check_misc.c +@@ -80,12 +80,6 @@ misc_check_compare(void *a, void *b) + + if (strcmp(old->path, new->path) != 0) + return false; +- if (old->timeout != new->timeout) +- return false; +- if (old->dynamic != new->dynamic) +- return false; +- if (old->uid != new->uid || new->gid != new->gid) +- return false; + + return true; + } +diff --git a/keepalived/check/check_smtp.c b/keepalived/check/check_smtp.c +index 44d15e01..c135258f 100644 +--- a/keepalived/check/check_smtp.c ++++ b/keepalived/check/check_smtp.c +@@ -92,10 +92,6 @@ smtp_check_compare(void *a, void *b) + + if (strcmp(old->helo_name, new->helo_name) != 0) + return false; +- if (old->retry != new->retry) +- return false; +- if (old->db_retry != new->db_retry) +- return false; + if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) + return false; + if (LIST_SIZE(old->host) != LIST_SIZE(new->host)) +diff --git a/keepalived/check/check_tcp.c b/keepalived/check/check_tcp.c +index 1858f5fc..7afed022 100644 +--- a/keepalived/check/check_tcp.c ++++ b/keepalived/check/check_tcp.c +@@ -70,10 +70,6 @@ tcp_check_compare(void *a, void *b) + + if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) + return false; +- if (old->n_retry != new->n_retry) +- return false; +- if (old->delay_before_retry != new->delay_before_retry) +- return false; + + return true; + } +-- +2.20.1 + diff --git a/SOURCES/bz1678480-resolve-compiler-warning.patch b/SOURCES/bz1678480-resolve-compiler-warning.patch new file mode 100644 index 0000000..7d451eb --- /dev/null +++ b/SOURCES/bz1678480-resolve-compiler-warning.patch @@ -0,0 +1,27 @@ +From 1dce490fdf829a0decb544a6147c4c5cc4cecf51 Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Fri, 14 Jul 2017 16:45:02 +0100 +Subject: [PATCH 8/8] Resolve compiler warning introduced by commit 8361b11 + +Signed-off-by: Quentin Armitage +--- + keepalived/check/check_tcp.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/keepalived/check/check_tcp.c b/keepalived/check/check_tcp.c +index 7afed022..69615544 100644 +--- a/keepalived/check/check_tcp.c ++++ b/keepalived/check/check_tcp.c +@@ -65,9 +65,6 @@ dump_tcp_check(void *data) + static bool + tcp_check_compare(void *a, void *b) + { +- tcp_check_t *old = CHECKER_DATA(a); +- tcp_check_t *new = CHECKER_DATA(b); +- + if (!compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b))) + return false; + +-- +2.20.1 + diff --git a/SOURCES/bz1678480-set-active-if-failed-checkers-empty.patch b/SOURCES/bz1678480-set-active-if-failed-checkers-empty.patch new file mode 100644 index 0000000..3acd745 --- /dev/null +++ b/SOURCES/bz1678480-set-active-if-failed-checkers-empty.patch @@ -0,0 +1,26 @@ +From ebd51b5f4a26619a4dd0393a7e97e4ca1a122700 Mon Sep 17 00:00:00 2001 +From: YAMAMOTO Masaya +Date: Tue, 11 Jul 2017 17:55:50 +0900 +Subject: [PATCH 5/8] Set active if new failed_checkers is empty + +--- + keepalived/check/ipwrapper.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index 09d86f08..c9dce2b7 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -658,6 +658,9 @@ migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs) + } + } + } ++ ++ if (LIST_ISEMPTY(new_rs->failed_checkers)) ++ SET_ALIVE(new_rs); + end: + free_list(&l); + } +-- +2.20.1 + diff --git a/SOURCES/bz1715308-fix-checkers-comparison-on-reload.patch b/SOURCES/bz1715308-fix-checkers-comparison-on-reload.patch new file mode 100644 index 0000000..30233b9 --- /dev/null +++ b/SOURCES/bz1715308-fix-checkers-comparison-on-reload.patch @@ -0,0 +1,46 @@ +From 8e42d6970457336bd92d327c628e38129f221f8a Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Mon, 17 Jul 2017 11:43:28 +0100 +Subject: [PATCH] Correct comparison for checker compare in + migrate_failed_checkers + +Commit 2ff6b3f changed the sense of the comparisons of checkers, +but didn't make the corresponding change to checking the result. + +Signed-off-by: Quentin Armitage +--- + keepalived/check/check_api.c | 4 ++-- + keepalived/check/ipwrapper.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/keepalived/check/check_api.c b/keepalived/check/check_api.c +index 1d915414..82b0f2df 100644 +--- a/keepalived/check/check_api.c ++++ b/keepalived/check/check_api.c +@@ -266,8 +266,8 @@ register_checkers_thread(void) + + for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) { + checker = ELEMENT_DATA(e); +- log_message(LOG_INFO, "%sctivating healthchecker for service %s" +- , checker->enabled ? "A" : "Dea", FMT_VS(checker->vs)); ++ log_message(LOG_INFO, "%sctivating healthchecker for service %s" ++ , checker->enabled ? "A" : "Dea", FMT_VS(checker->vs)); + if (checker->launch) + { + /* wait for a random timeout to begin checker thread. +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index 17f0157d..ad8c3154 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -649,7 +649,7 @@ migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs) + continue; + for (e1 = LIST_HEAD(l); e1; ELEMENT_NEXT(e1)) { + old_c = ELEMENT_DATA(e1); +- if (old_c->compare == new_c->compare && new_c->compare(old_c, new_c) == 0) { ++ if (old_c->compare == new_c->compare && new_c->compare(old_c, new_c)) { + if (svr_checker_up(old_c->id, old_rs) == 0) { + id = (checker_id_t *) MALLOC(sizeof(checker_id_t)); + *id = new_c->id; +-- +2.21.0 + diff --git a/SOURCES/bz1715308-make-checker-variables-non-global.patch b/SOURCES/bz1715308-make-checker-variables-non-global.patch new file mode 100644 index 0000000..b60e725 --- /dev/null +++ b/SOURCES/bz1715308-make-checker-variables-non-global.patch @@ -0,0 +1,173 @@ +From 6f18ff4f0a06015691b25cb91bf4c6dccec5cc89 Mon Sep 17 00:00:00 2001 +From: Quentin Armitage +Date: Sun, 16 Jul 2017 10:00:20 +0100 +Subject: [PATCH] Make a couple of checker variables non global + +Signed-off-by: Quentin Armitage +--- + keepalived/check/check_api.c | 4 ++-- + keepalived/check/check_daemon.c | 11 ++++++----- + keepalived/check/ipwrapper.c | 10 +++++----- + keepalived/include/check_api.h | 2 -- + keepalived/include/ipwrapper.h | 2 +- + 5 files changed, 14 insertions(+), 15 deletions(-) + +diff --git a/keepalived/check/check_api.c b/keepalived/check/check_api.c +index 82b0f2df..016850f0 100644 +--- a/keepalived/check/check_api.c ++++ b/keepalived/check/check_api.c +@@ -42,9 +42,8 @@ + #include "check_dns.h" + + /* Global vars */ +-checker_id_t ncheckers = 0; ++static checker_id_t ncheckers; + list checkers_queue; +-list old_checkers_queue; + + /* free checker data */ + static void +@@ -243,6 +242,7 @@ void + init_checkers_queue(void) + { + checkers_queue = alloc_list(free_checker, dump_checker); ++ ncheckers = 0; + } + + /* release the checkers_queue */ +diff --git a/keepalived/check/check_daemon.c b/keepalived/check/check_daemon.c +index 462360e6..85f8bdbd 100644 +--- a/keepalived/check/check_daemon.c ++++ b/keepalived/check/check_daemon.c +@@ -108,7 +108,7 @@ stop_check(int status) + + /* Daemon init sequence */ + static void +-start_check(void) ++start_check(list old_checkers_queue) + { + /* Initialize sub-system */ + if (ipvs_start() != IPVS_SUCCESS) { +@@ -171,7 +171,7 @@ start_check(void) + + /* Processing differential configuration parsing */ + if (reload) +- clear_diff_services(); ++ clear_diff_services(old_checkers_queue); + + /* Initialize IPVS topology */ + if (!init_services()) +@@ -219,6 +219,8 @@ check_signal_init(void) + static int + reload_check_thread(__attribute__((unused)) thread_t * thread) + { ++ list old_checkers_queue; ++ + /* set the reloading flag */ + SET_RELOAD; + +@@ -236,7 +238,6 @@ reload_check_thread(__attribute__((unused)) thread_t * thread) + /* Save previous checker data */ + old_checkers_queue = checkers_queue; + checkers_queue = NULL; +- ncheckers = 0; + + free_ssl(); + ipvs_stop(); +@@ -246,7 +247,7 @@ reload_check_thread(__attribute__((unused)) thread_t * thread) + check_data = NULL; + + /* Reload the conf */ +- start_check(); ++ start_check(old_checkers_queue); + + /* free backup data */ + free_check_data(old_check_data); +@@ -355,7 +356,7 @@ start_check_child(void) + check_signal_init(); + + /* Start Healthcheck daemon */ +- start_check(); ++ start_check(NULL); + + /* Launch the scheduling I/O multiplexer */ + launch_scheduler(); +diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c +index ad8c3154..34bb59f8 100644 +--- a/keepalived/check/ipwrapper.c ++++ b/keepalived/check/ipwrapper.c +@@ -625,7 +625,7 @@ rs_exist(real_server_t * old_rs, list l) + } + + static void +-migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs) ++migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs, list old_checkers_queue) + { + list l; + element e, e1; +@@ -668,7 +668,7 @@ end: + + /* Clear the diff rs of the old vs */ + static void +-clear_diff_rs(virtual_server_t *old_vs, virtual_server_t *new_vs) ++clear_diff_rs(virtual_server_t *old_vs, virtual_server_t *new_vs, list old_checkers_queue) + { + element e; + list l = old_vs->rs; +@@ -713,7 +713,7 @@ clear_diff_rs(virtual_server_t *old_vs, virtual_server_t *new_vs) + * based on the failed_checkers list + */ + if (!new_vs->alpha) +- migrate_failed_checkers(rs, new_rs); ++ migrate_failed_checkers(rs, new_rs, old_checkers_queue); + } + } + } +@@ -746,7 +746,7 @@ clear_diff_s_srv(virtual_server_t *old_vs, real_server_t *new_rs) + /* When reloading configuration, remove negative diff entries + * and copy status of existing entries to the new ones */ + void +-clear_diff_services(void) ++clear_diff_services(list old_checkers_queue) + { + element e; + list l = old_check_data->vs; +@@ -786,7 +786,7 @@ clear_diff_services(void) + /* omega = false must not prevent the notifiers from being called, + because the VS still exists in new configuration */ + vs->omega = true; +- clear_diff_rs(vs, new_vs); ++ clear_diff_rs(vs, new_vs, old_checkers_queue); + clear_diff_s_srv(vs, new_vs->s_svr); + } + } +diff --git a/keepalived/include/check_api.h b/keepalived/include/check_api.h +index c7bc297d..c43eca14 100644 +--- a/keepalived/include/check_api.h ++++ b/keepalived/include/check_api.h +@@ -47,9 +47,7 @@ typedef struct _checker { + } checker_t; + + /* Checkers queue */ +-extern checker_id_t ncheckers; + extern list checkers_queue; +-extern list old_checkers_queue; + + /* utility macro */ + #define CHECKER_ARG(X) ((X)->data) +diff --git a/keepalived/include/ipwrapper.h b/keepalived/include/ipwrapper.h +index 11cdbbc6..0a6c48ba 100644 +--- a/keepalived/include/ipwrapper.h ++++ b/keepalived/include/ipwrapper.h +@@ -55,7 +55,7 @@ extern int svr_checker_up(checker_id_t, real_server_t *); + extern void update_svr_checker_state(bool, checker_id_t, virtual_server_t *, real_server_t *); + extern bool init_services(void); + extern void clear_services(void); +-extern void clear_diff_services(void); ++extern void clear_diff_services(list); + extern void link_vsg_to_vs(void); + + #endif +-- +2.21.0 + diff --git a/SOURCES/keepalived.service b/SOURCES/keepalived.service new file mode 100644 index 0000000..1b3e587 --- /dev/null +++ b/SOURCES/keepalived.service @@ -0,0 +1,14 @@ +[Unit] +Description=LVS and VRRP High Availability Monitor +After=syslog.target network-online.target + +[Service] +Type=forking +PIDFile=/var/run/keepalived.pid +KillMode=process +EnvironmentFile=-/etc/sysconfig/keepalived +ExecStart=/usr/sbin/keepalived $KEEPALIVED_OPTIONS +ExecReload=/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target diff --git a/SPECS/keepalived.spec b/SPECS/keepalived.spec new file mode 100644 index 0000000..d997f0a --- /dev/null +++ b/SPECS/keepalived.spec @@ -0,0 +1,442 @@ +%bcond_without snmp +%bcond_without vrrp +%bcond_without sha1 +%bcond_with profile +%bcond_with debug + +%global _hardened_build 1 + +Name: keepalived +Summary: Load balancer and high availability service +Version: 1.3.5 +Release: 16%{?dist} +License: GPLv2+ +URL: http://www.keepalived.org/ +Group: System Environment/Daemons + +Source0: http://www.keepalived.org/software/keepalived-%{version}.tar.gz +Source1: keepalived.service + +Patch0: bz1419049-fix-unused-variables.patch +Patch1: bz1477572-fix-man-page-vrrp_ipsets.patch +Patch2: bz1477563-fix-keepalived_script-user.patch +Patch3: bz1508435-load-ip-tables-handling.patch +Patch4: bz1508435-no-segfault-ip_vs-load.patch +Patch5: bz1508435-remove-ipset-handling.patch +Patch6: bz1477587-exclude-mismatch-vips.patch +Patch7: bz1652694-fix-buffer-overflow-http-status.patch +patch8: bz1654301-fix-improper-pathname-validation.patch +patch9: bz1667292-fix-vrrp_script-misc_script.patch +patch10: bz1678480-add-child_wait_time.patch +patch11: bz1678480-migrate-failed-checkers-reload.patch +patch12: bz1678480-implment-checker-comparison.patch +patch13: bz1678480-fix-wrong-migrate-checker-id.patch +patch14: bz1678480-set-active-if-failed-checkers-empty.patch +patch15: bz1678480-fix-checker-coding-style.patch +patch16: bz1678480-remove-unnecessary-parameter-compare.patch +patch17: bz1678480-resolve-compiler-warning.patch +patch18: bz1678480-include-check_api-in-ipwrapper.patch +patch19: bz1715308-make-checker-variables-non-global.patch +patch20: bz1715308-fix-checkers-comparison-on-reload.patch + +Requires: ipset-libs +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +%if %{with snmp} +BuildRequires: net-snmp +BuildRequires: net-snmp-devel +%endif +BuildRequires: systemd-units +BuildRequires: openssl-devel +BuildRequires: libnl3-devel +BuildRequires: ipset-devel +BuildRequires: iptables-devel +BuildRequires: libnfnetlink-devel + +%description +Keepalived provides simple and robust facilities for load balancing +and high availability. The load balancing framework relies on the +well-known and widely used Linux Virtual Server (IPVS) kernel module +providing layer-4 (transport layer) load balancing. Keepalived +implements a set of checkers to dynamically and adaptively maintain +and manage a load balanced server pool according their health. +Keepalived also implements the Virtual Router Redundancy Protocol +(VRRPv2) to achieve high availability with director failover. + +%prep +%setup -q +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 + +%build +%configure \ + %{?with_debug:--enable-debug} \ + %{?with_profile:--enable-profile} \ + %{!?with_vrrp:--disable-vrrp} \ + %{?with_snmp:--enable-snmp --enable-snmp-rfc} \ + %{?with_sha1:--enable-sha1} +%{__make} %{?_smp_mflags} STRIP=/bin/true + +%install +%{__rm} -rf %{buildroot} +%{__rm} -rf doc/samples/*.pem +%{__make} install DESTDIR=%{buildroot} +%{__rm} -rf %{buildroot}%{_initrddir}/ +%{__rm} -rf %{buildroot}%{_sysconfdir}/keepalived/samples/ +%{__install} -p -D -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/keepalived.service +%{__mkdir_p} %{buildroot}%{_libexecdir}/keepalived + +%if %{with snmp} +%{__mkdir_p} %{buildroot}%{_datadir}/snmp/mibs/ +%endif + +%clean +%{__rm} -rf %{buildroot} + +%post +%systemd_post keepalived.service + +%preun +%systemd_preun keepalived.service + +%postun +%systemd_postun_with_restart keepalived.service + +%files +%defattr(-,root,root,-) +%doc AUTHOR ChangeLog CONTRIBUTORS COPYING README TODO +%doc doc/keepalived.conf.SYNOPSIS doc/NOTE_vrrp_vmac.txt doc/samples/ +%dir %{_sysconfdir}/keepalived/ +%dir %{_libexecdir}/keepalived/ +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/keepalived/keepalived.conf +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/keepalived +%{_unitdir}/keepalived.service +%if %{with snmp} +%{_datadir}/snmp/mibs/KEEPALIVED-MIB.txt +%{_datadir}/snmp/mibs/VRRP-MIB.txt +%{_datadir}/snmp/mibs/VRRPv3-MIB.txt +%endif +%attr(0755,root,root) %{_bindir}/genhash +%attr(0755,root,root) %{_sbindir}/keepalived +%{_mandir}/man1/genhash.1* +%{_mandir}/man5/keepalived.conf.5* +%{_mandir}/man8/keepalived.8* + +%changelog +* Fri Jun 14 2019 Ryan O'Hara - 1.3.5-16 +- Rework previous misc_script/vrrp_script patch (#1667292) + +* Mon Jun 03 2019 Ryan O'Hara - 1.3.5-15 +- Rework previous checker comparison patch (#1715308) + +* Fri May 31 2019 Ryan O'Hara - 1.3.5-14 +- Make checker variables non global (#1715308) + +* Fri May 31 2019 Ryan O'Hara - 1.3.5-13 +- Fix comparison of checkers on reload (#1715308) + +* Wed Apr 03 2019 Ryan O'Hara - 1.3.5-12 +- Fix build errors (#1678480) + +* Tue Apr 02 2019 Ryan O'Hara - 1.3.5-11 +- Fix problems with health checks & real servers after reload/restart (#1678480) + +* Fri Jan 25 2019 Ryan O'Hara - 1.3.5-10 +- Fix vrrp_script and check_misc scripts of type " - 1.3.5-9 +- Fix improper pathname validation (#1654301) + +* Thu Dec 13 2018 Ryan O'Hara - 1.3.5-8 +- Fixed patch that was incorrectly removed (#1652694) + +* Mon Dec 10 2018 Ryan O'Hara - 1.3.5-7 +- Fix buffer overflow when parsing HTTP status codes (#1652694) + +* Wed Jan 31 2018 Ryan O'Hara - 1.3.5-6 +- Add net-snmp as BuildRequires (#1536252) + +* Mon Dec 11 2017 Ryan O'Hara - 1.3.5-5 +- Exclude VIPs of non-matching address family (#1477587) + +* Thu Nov 16 2017 Ryan O'Hara - 1.3.5-4 +- Fix bugs related to failures when load modules and/or segfaults (#1508435) + +* Wed Aug 02 2017 Ryan O'Hara - 1.3.5-3 +- Don't complain about keepalived_script user if not needed (#1477563) + +* Wed Aug 02 2017 Ryan O'Hara - 1.3.5-2 +- Fix ipset-libs dependency and vrrp_ipset in man page (#1477572) + +* Wed Mar 22 2017 Ryan O'Hara - 1.3.5-1 +- Rebase to upstream version 1.3.5 (#1419049) + +* Thu Mar 16 2017 Ryan O'Hara - 1.3.4-2 +- Start keepalived after network-online.target (#1425828) + +* Wed Mar 15 2017 Ryan O'Hara - 1.3.4-1 +- Rebase to upstream version 1.3.4 (#1419049) + +* Fri Jul 01 2016 Ryan O'Hara - 1.2.13-8 +- Add PIDFile to systemd unit file (#1336190) + +* Thu Jun 25 2015 Ryan O'Hara - 1.2.13-7 +- Set global default values after parsing config file (#1181107) + +* Tue Nov 18 2014 Ryan O'Hara - 1.2.13-6 +- Fix typo in changelog + +* Mon Nov 10 2014 Ryan O'Hara - 1.2.13-5 +- Bump release number (#1158114) + +* Thu Nov 06 2014 Ryan O'Hara - 1.2.13-4 +- Create /usr/libexec/keepalived directory (#1158114) + +* Tue Sep 30 2014 Ryan O'Hara - 1.2.13-3 +- Minor spec file modifications (#1067693, #1067145) + +* Tue Sep 30 2014 Ryan O'Hara - 1.2.13-2 +- Add SNMP subsystem option to man page (#1085535) + +* Thu Aug 07 2014 Ryan O'Hara - 1.2.13-1 +- Rebase to upstream version 1.2.13 (#1111716) + +* Fri Jan 24 2014 Daniel Mach - 1.2.10-2 +- Mass rebuild 2014-01-24 + +* Tue Jan 14 2014 Ryan O'Hara - 1.2.10-1 +- Rebase to upstream version 1.2.10 (#1052359) + +* Fri Dec 27 2013 Daniel Mach - 1.2.8-2 +- Mass rebuild 2013-12-27 + +* Thu Sep 05 2013 Ryan O'Hara - 1.2.8-1 +- Update to 1.2.8. + +* Mon Jul 22 2013 Ryan O'Hara - 1.2.7-8 +- Fix macro in keepalived.conf.5 man page. + +* Mon Jul 22 2013 Ryan O'Hara - 1.2.7-7 +- Fix systemd requirements. + +* Mon Jul 22 2013 Ryan O'Hara - 1.2.7-6 +- Install the systemd unit file, not the init script. + +* Mon Apr 22 2013 Ryan O'Hara - 1.2.7-5 +- Build with PIE flags (#955150) + +* Thu Feb 14 2013 Fedora Release Engineering - 1.2.7-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Jan 2 2013 Ryan O'Hara - 1.2.7-3 +- Update spec file. +- Add option to prevent respawn of child processes. +- Remove duplicate command-line option code. +- Use popt to generate usage message. +- Fix pointer arithmetic for VRRP packets. +- Fix comparison of primary IP address. +- Fix loading of SSL certificate. +- Fix typo in error message. +- Update FSF address in GPLv2 license. +- Remove debug message from if_get_by_ifname. + +* Mon Sep 24 2012 Václav Pavlín - 1.2.7-2 +- Scriptlets replaced with new systemd macros (#850173). + +* Tue Sep 04 2012 Ryan O'Hara - 1.2.7-1 +- Update to 1.2.7. +- Fix systemd service file (#769726). + +* Mon Aug 20 2012 Ryan O'Hara - 1.2.6-1 +- Update to 1.2.6. + +* Tue Aug 14 2012 Ryan O'Hara - 1.2.5-2 +- Install KEEPALIVED-MIB as KEEPALIVED-MIB.txt. + +* Mon Aug 13 2012 Ryan O'Hara - 1.2.5-1 +- Update to 1.2.5. + +* Wed Aug 01 2012 Ryan O'Hara - 1.2.4-1 +- Update to 1.2.4. + +* Mon Jul 23 2012 Ryan O'Hara - 1.2.3-1 +- Update to 1.2.3. + +* Thu Jul 19 2012 Fedora Release Engineering - 1.2.2-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue May 08 2012 Ryan O'Hara - 1.2.2-5 +- Fix IPv4 address comparison (#768119). + +* Fri Jan 13 2012 Fedora Release Engineering - 1.2.2-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Mon Sep 19 2011 Tom Callaway - 1.2.2-3 +- convert to systemd +- fix ip_vs.h path searching in configure + +* Sat Jul 23 2011 Matthias Saou 1.2.2-2 +- Build against libnl for Fedora. RHEL's libnl is too old. + +* Sat May 21 2011 Matthias Saou 1.2.2-1 +- Update to 1.2.2. + +* Mon Feb 07 2011 Fedora Release Engineering - 1.1.20-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Sun Jan 16 2011 Dan Horák 1.1.20-2 +- exclude arches where we don't provide 32-bit kernel + +* Tue Jan 11 2011 Matthias Saou 1.2.1-1 +- Update to 1.2.1, now with IPv6 support. + +* Sun May 23 2010 Matthias Saou 1.1.20-1 +- Update to 1.1.20 (#589923). +- Update BR conditional for RHEL6. +- No longer include goodies/arpreset.pl, it's gone from the sources. + +* Tue Dec 8 2009 Matthias Saou 1.1.19-3 +- Update init script to have keepalived start after the local MTA (#526512). +- Simplify the kernel source detection, to avoid running rpm from rpmbuild. + +* Tue Nov 24 2009 Matthias Saou 1.1.19-2 +- Include patch to remove obsolete -k option to modprobe (#528465). + +* Wed Oct 21 2009 Matthias Saou 1.1.19-1 +- Update to 1.1.19. + +* Fri Aug 21 2009 Tomas Mraz - 1.1.17-3 +- rebuilt with new openssl + +* Fri Jul 24 2009 Fedora Release Engineering - 1.1.17-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Sun Apr 12 2009 Matthias Saou 1.1.17-1 +- Update to 1.1.17. +- Update init script all the way. + +* Wed Feb 25 2009 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Sat Jan 17 2009 Tomas Mraz 1.1.15-7 +- rebuild with new openssl + +* Mon Dec 22 2008 Matthias Saou 1.1.15-6 +- Fork the init script to be (mostly for now) LSB compliant (#246966). + +* Thu Apr 24 2008 Matthias Saou 1.1.15-5 +- Add glob to the kerneldir location, since it contains the arch for F9+. + +* Tue Feb 19 2008 Fedora Release Engineering +- Autorebuild for GCC 4.3 + +* Wed Dec 05 2007 Release Engineering +- Rebuild for deps + +* Mon Oct 22 2007 Matthias Saou 1.1.15-2 +- Update to latest upstream sources, identical except for the included spec. + +* Mon Sep 17 2007 Matthias Saou 1.1.15-1 +- Update to 1.1.15. +- Remove merged genhashman and include patches. + +* Fri Sep 14 2007 Matthias Saou 1.1.14-2 +- Include patch from Shinji Tanaka to fix conf include from inside some + directives like vrrp_instance. + +* Thu Sep 13 2007 Matthias Saou 1.1.14-1 +- Update to 1.1.14. +- Remove all upstreamed patches. +- Remove our init script and sysconfig files, use the same now provided by the + upstream package (will need to patch for LSB stuff soonish). +- Include new goodies/arpreset.pl in %%doc. +- Add missing scriplet requirements. + +* Wed Aug 22 2007 Matthias Saou 1.1.13-8 +- Rebuild for new BuildID feature. + +* Sun Aug 5 2007 Matthias Saou 1.1.13-7 +- Update License field. + +* Mon Mar 26 2007 Matthias Saou 1.1.13-6 +- Fix doc/samples/sample.misccheck.smbcheck.sh mode (600 -> 644). + +* Thu Mar 22 2007 Matthias Saou 1.1.13-5 +- Include types patch to fix compile on F7 (David Woodhouse). +- Fix up file modes (main binary 700 -> 755 and config 600 -> 640). + +* Tue Feb 13 2007 Matthias Saou 1.1.13-4 +- Add missing \n to the kernel define, for when multiple kernels are installed. +- Pass STRIP=/bin/true to "make" in order to get a useful debuginfo package. + +* Tue Feb 13 2007 Matthias Saou 1.1.13-3 +- Add %%check section to make sure any build without LVS support will fail. + +* Mon Feb 5 2007 Matthias Saou 1.1.13-2 +- Use our own init script, include a sysconfig entry used by it for options. + +* Thu Jan 25 2007 Matthias Saou 1.1.13-1 +- Update to 1.1.13. +- Change mode of configuration file to 0600. +- Don't include all of "doc" since it meant re-including all man pages. +- Don't include samples in the main configuration path, they're in %%doc. +- Include patch to add an optional label to interfaces. + +* Sat Apr 08 2006 Dries Verachtert - 1.1.12-1.2 +- Rebuild for Fedora Core 5. + +* Sun Mar 12 2006 Dag Wieers - 1.1.12-1 +- Updated to release 1.1.12. + +* Fri Mar 04 2005 Dag Wieers - 1.1.11-1 +- Updated to release 1.1.11. + +* Wed Feb 23 2005 Dag Wieers - 1.1.10-2 +- Fixed IPVS/LVS support. (Joe Sauer) + +* Tue Feb 15 2005 Dag Wieers - 1.1.10-1 +- Updated to release 1.1.10. + +* Mon Feb 07 2005 Dag Wieers - 1.1.9-1 +- Updated to release 1.1.9. + +* Sun Oct 17 2004 Dag Wieers - 1.1.7-2 +- Fixes to build with kernel IPVS support. (Tim Verhoeven) + +* Fri Sep 24 2004 Dag Wieers - 1.1.7-1 +- Updated to release 1.1.7. (Mathieu Lubrano) + +* Mon Feb 23 2004 Dag Wieers - 1.1.6-0 +- Updated to release 1.1.6. + +* Mon Jan 26 2004 Dag Wieers - 1.1.5-0 +- Updated to release 1.1.5. + +* Mon Dec 29 2003 Dag Wieers - 1.1.4-0 +- Updated to release 1.1.4. + +* Fri Jun 06 2003 Dag Wieers - 1.0.3-0 +- Initial package. (using DAR) +