High Availability monitor built upon LVS, VRRP and service pollers
CentOS Sources
2018-04-10 cead2e7f37c192ffc6b70c43efaaff4a822f6a23
import keepalived-1.3.5-6.el7
11 files added
1 files deleted
2585 ■■■■■ changed files
.gitignore 1 ●●●● patch | view | raw | blame | history
.keepalived.metadata 1 ●●●● patch | view | raw | blame | history
README.md 5 ●●●●● patch | view | raw | blame | history
SOURCES/bz1419049-fix-unused-variables.patch 32 ●●●●● patch | view | raw | blame | history
SOURCES/bz1477563-fix-keepalived_script-user.patch 729 ●●●●● patch | view | raw | blame | history
SOURCES/bz1477572-fix-man-page-vrrp_ipsets.patch 29 ●●●●● patch | view | raw | blame | history
SOURCES/bz1477587-exclude-mismatch-vips.patch 38 ●●●●● patch | view | raw | blame | history
SOURCES/bz1508435-load-ip-tables-handling.patch 1154 ●●●●● patch | view | raw | blame | history
SOURCES/bz1508435-no-segfault-ip_vs-load.patch 168 ●●●●● patch | view | raw | blame | history
SOURCES/bz1508435-remove-ipset-handling.patch 30 ●●●●● patch | view | raw | blame | history
SOURCES/keepalived.service 14 ●●●●● patch | view | raw | blame | history
SPECS/keepalived.spec 384 ●●●●● patch | view | raw | blame | history
.gitignore
New file
@@ -0,0 +1 @@
SOURCES/keepalived-1.3.5.tar.gz
.keepalived.metadata
New file
@@ -0,0 +1 @@
5a373d8f5d382700cf53b827947a92a7f4cef148 SOURCES/keepalived-1.3.5.tar.gz
README.md
File was deleted
SOURCES/bz1419049-fix-unused-variables.patch
New file
@@ -0,0 +1,32 @@
From 6e855aa91876e6a41324e870439f2c185318be88 Mon Sep 17 00:00:00 2001
From: Ryan O'Hara <rohara@redhat.com>
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
SOURCES/bz1477563-fix-keepalived_script-user.patch
New file
@@ -0,0 +1,729 @@
From 99f31a89d2f5803fe2d6229f2557e72efb3ef95f Mon Sep 17 00:00:00 2001
From: Quentin Armitage <quentin@armitage.org.uk>
Date: Tue, 28 Mar 2017 09:11:44 +0100
Subject: [PATCH] Make dynamic flag bool
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
Fix releasing malloc'd memory for saved core pattern
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
Fix detecting default script uid/gid
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
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 <quentin@armitage.org.uk>
---
 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 <STRING>      {    # VS group declaration
         weight <INTEGER>        # weight to use (default: 1)
         inhibit_on_failure        # Set weight to 0 on healthchecker
                     #  failure
-        notify_up <STRING>|<QUOTED-STRING> # Script to launch when
-                       #  healthchecker consider service
-                       #  as up.
-        notify_down <STRING>|<QUOTED-STRING> # Script to launch when
-                         #  healthchecker consider service
-                         #  as down.
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]]
+                    # Script to launch when
+                    #  healthchecker consider service
+                    #  as up.
+        notify_down <STRING>|<QUOTED-STRING> [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 <STRING>      {    # VS group declaration
     real_server <IP ADDRESS> <PORT> {    # Idem
         weight <INTEGER>        # Idem
         inhibit_on_failure        # Idem
-        notify_up <STRING>|<QUOTED-STRING> # Idem
-        notify_down <STRING>|<QUOTED-STRING> # Idem
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
         TCP_CHECK {            # TCP healthchecker
             connect_ip <IP ADDRESS> # IP address to connect
@@ -620,8 +622,8 @@ virtual_server group <STRING>      {    # VS group declaration
     real_server <IP ADDRESS> <PORT> {    # Idem
         weight <INTEGER>        # Idem
         inhibit_on_failure        # Idem
-        notify_up <STRING>|<QUOTED-STRING> # Idem
-        notify_down <STRING>|<QUOTED-STRING> # Idem
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
         SMTP_CHECK {                   # SMTP healthchecker
             connect_ip <IP ADDRESS>     # Optional IP address to connect to
@@ -658,8 +660,8 @@ virtual_server group <STRING>      {    # VS group declaration
     real_server <IP ADDRESS> <PORT> {    # Idem
         weight <INTEGER>        # Idem
         inhibit_on_failure        # Idem
-        notify_up <STRING>|<QUOTED-STRING> # Idem
-        notify_down <STRING>|<QUOTED-STRING> # Idem
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
         DNS_CHECK {                     # DNS healthchecker
             connect_ip <IP ADDRESS>     # Optional IP address to connect to
@@ -677,8 +679,8 @@ virtual_server group <STRING>      {    # VS group declaration
     real_server <IP ADDRESS> <PORT> {    # Idem
         weight <INTEGER>        # Idem
         inhibit_on_failure        # Idem
-        notify_up <STRING>|<QUOTED-STRING> # Idem
-        notify_down <STRING>|<QUOTED-STRING> # Idem
+        notify_up <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
+        notify_down <STRING>|<QUOTED-STRING> [username [groupname]] # Idem
         MISC_CHECK {                # MISC healthchecker
             misc_path <STRING>|<QUOTED-STRING>    # 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 <STRING>|<QUOTED-STRING>
+           notify_up <STRING>|<QUOTED-STRING> [username [groupname]]
            # Script to execute when healthchecker
            # considers service as down.
-           notify_down <STRING>|<QUOTED-STRING>
+           notify_down <STRING>|<QUOTED-STRING> [username [groupname]]
            uthreshold <INTEGER> # maximum number of connections to server
            lthreshold <INTEGER> # 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
SOURCES/bz1477572-fix-man-page-vrrp_ipsets.patch
New file
@@ -0,0 +1,29 @@
From 431ba58daf11771195d0b494b0b0b3655a9b25cd Mon Sep 17 00:00:00 2001
From: Quentin Armitage <quentin@armitage.org.uk>
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 <quentin@armitage.org.uk>
---
 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
SOURCES/bz1477587-exclude-mismatch-vips.patch
New file
@@ -0,0 +1,38 @@
From f42914b07166db123b55a4acd31f4a6eb280d0f8 Mon Sep 17 00:00:00 2001
From: Ryan O'Hara <rohara@redhat.com>
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
SOURCES/bz1508435-load-ip-tables-handling.patch
New file
@@ -0,0 +1,1154 @@
From dd9a0db422716dd9bbc329a6e2f23ee3d55d2008 Mon Sep 17 00:00:00 2001
From: Quentin Armitage <quentin@armitage.org.uk>
Date: Mon, 27 Mar 2017 11:26:44 +0100
Subject: [PATCH 1/3] Handle not being able to load ip_tables or ip6_tables
 modules
When running in a docker container it isn't possible to load kernel
modules, so we need to cleanly handle a failure to load the modules.
Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
---
 keepalived/core/global_data.c            |   2 -
 keepalived/include/global_data.h         |   2 -
 keepalived/include/vrrp.h                |   5 +
 keepalived/include/vrrp_ipset.h          |   4 +-
 keepalived/include/vrrp_iptables.h       |   7 +-
 keepalived/include/vrrp_iptables_calls.h |   2 +-
 keepalived/vrrp/vrrp.c                   |  53 ++++++--
 keepalived/vrrp/vrrp_daemon.c            |  13 +-
 keepalived/vrrp/vrrp_ipaddress.c         | 137 ++++++++++++++++---
 keepalived/vrrp/vrrp_ipset.c             |  73 +++++++---
 keepalived/vrrp/vrrp_iptables.c          | 225 +++++++++++++++++++------------
 keepalived/vrrp/vrrp_iptables_calls.c    | 108 +++++++--------
 12 files changed, 421 insertions(+), 210 deletions(-)
diff --git a/keepalived/core/global_data.c b/keepalived/core/global_data.c
index d934f286..21c06c1c 100644
--- a/keepalived/core/global_data.c
+++ b/keepalived/core/global_data.c
@@ -98,8 +98,6 @@ set_vrrp_defaults(data_t * data)
     data->vrrp_higher_prio_send_advert = false;
     data->vrrp_version = VRRP_VERSION_2;
     strcpy(data->vrrp_iptables_inchain, "INPUT");
-    data->block_ipv4 = false;
-    data->block_ipv6 = false;
 #ifdef _HAVE_LIBIPSET_
     data->using_ipsets = true;
     strcpy(data->vrrp_ipset_address, "keepalived");
diff --git a/keepalived/include/global_data.h b/keepalived/include/global_data.h
index 6547ddac..eea34f75 100644
--- a/keepalived/include/global_data.h
+++ b/keepalived/include/global_data.h
@@ -99,8 +99,6 @@ typedef struct _data {
     int                vrrp_version;    /* VRRP version (2 or 3) */
     char                vrrp_iptables_inchain[XT_EXTENSION_MAXNAMELEN];
     char                vrrp_iptables_outchain[XT_EXTENSION_MAXNAMELEN];
-    bool                block_ipv4;
-    bool                block_ipv6;
 #ifdef _HAVE_LIBIPSET_
     bool                using_ipsets;
     char                vrrp_ipset_address[IPSET_MAXNAMELEN];
diff --git a/keepalived/include/vrrp.h b/keepalived/include/vrrp.h
index 6e874689..ab757277 100644
--- a/keepalived/include/vrrp.h
+++ b/keepalived/include/vrrp.h
@@ -313,6 +313,10 @@ typedef struct _vrrp_t {
 #define VRRP_ISUP(V)        (VRRP_IF_ISUP(V) && VRRP_SCRIPT_ISUP(V))
+/* Global variables */
+extern bool block_ipv4;
+extern bool block_ipv6;
+
 /* prototypes */
 extern vrrphdr_t *vrrp_get_header(sa_family_t, char *, unsigned *);
 extern int open_vrrp_send_socket(sa_family_t, int, ifindex_t, bool);
@@ -327,6 +331,7 @@ extern void vrrp_state_backup(vrrp_t *, char *, ssize_t);
 extern void vrrp_state_goto_master(vrrp_t *);
 extern void vrrp_state_leave_master(vrrp_t *);
 extern bool vrrp_complete_init(void);
+extern void vrrp_restore_interfaces_startup(void);
 extern void restore_vrrp_interfaces(void);
 extern void shutdown_vrrp_instances(void);
 extern void clear_diff_vrrp(void);
diff --git a/keepalived/include/vrrp_ipset.h b/keepalived/include/vrrp_ipset.h
index 9ee1095a..6cc320ef 100644
--- a/keepalived/include/vrrp_ipset.h
+++ b/keepalived/include/vrrp_ipset.h
@@ -27,8 +27,8 @@
 #include <libipset/session.h>
 #include "vrrp_ipaddress.h"
-int add_ipsets(bool);
-int remove_ipsets(void);
+bool add_ipsets(bool);
+bool remove_ipsets(void);
 bool has_ipset_setname(struct ipset_session*, const char *);
 bool ipset_init(void);
 struct ipset_session* ipset_session_start(void);
diff --git a/keepalived/include/vrrp_iptables.h b/keepalived/include/vrrp_iptables.h
index 2a7681b3..dbbd6fe7 100644
--- a/keepalived/include/vrrp_iptables.h
+++ b/keepalived/include/vrrp_iptables.h
@@ -37,12 +37,11 @@ struct ipt_handle;
 #define    IPTABLES_MAX_TRIES    3    /* How many times to try adding/deleting when get EAGAIN */
 #ifdef _LIBIPTC_DYNAMIC_
-extern bool using_libiptc;        /* Set if using libiptc - for dynamic linking */
+extern bool using_libip4tc;        /* Set if using lib4iptc - for dynamic linking */
+extern bool using_libip6tc;        /* Set if using lib4iptc - for dynamic linking */
 #endif
-extern bool use_ip4tables;        /* Set if using iptables */
-extern bool use_ip6tables;        /* Set if using ip6tables */
-bool iptables_init_lib(void);
+void iptables_init_lib(void);
 void iptables_fini(void);
 void iptables_startup(bool);
 void iptables_cleanup(void);
diff --git a/keepalived/include/vrrp_iptables_calls.h b/keepalived/include/vrrp_iptables_calls.h
index 34052fac..ef4e0183 100644
--- a/keepalived/include/vrrp_iptables_calls.h
+++ b/keepalived/include/vrrp_iptables_calls.h
@@ -34,7 +34,6 @@
 #ifdef _HAVE_LIBIPTC_
 #ifdef _LIBXTABLES_DYNAMIC_
-extern bool xtables_load(void);
 extern void xtables_unload(void);
 #endif
 extern bool load_xtables_module(const char *, const char *);
@@ -50,6 +49,7 @@ extern int ip6tables_is_chain(struct ip6tc_handle* handle, const char* chain_nam
 extern int ip6tables_process_entry( struct ip6tc_handle* handle, const char* chain_name, unsigned int rulenum, const char* target_name, const ip_address_t* src_ip_address, const ip_address_t* dst_ip_address, const char* in_iface, const char* out_iface, uint16_t protocol, uint8_t type, int cmd, bool force);
 extern int ip4tables_add_rules(struct iptc_handle* handle, const char* chain_name, unsigned int rulenum, uint8_t dim, uint8_t src_dst, const char* target_name, const char* set_name, uint16_t protocol, uint8_t param, int cmd, bool ignore_errors);
 extern int ip6tables_add_rules(struct ip6tc_handle* handle, const char* chain_name, unsigned int rulenum, uint8_t dim, uint8_t src_dst, const char* target_name, const char* set_name, uint16_t protocol, uint8_t param, int cmd, bool ignore_errors);
+extern void check_chains_exist_lib(void);
 #ifdef _LIBIPTC_DYNAMIC_
 extern bool iptables_lib_init(void);
 #endif
diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c
index 3d2bfe41..38895af8 100644
--- a/keepalived/vrrp/vrrp.c
+++ b/keepalived/vrrp/vrrp.c
@@ -72,6 +72,10 @@
 #include <netinet/ip6.h>
 #include <stdint.h>
+/* Set if need to block ip addresses and are able to do so */
+bool block_ipv4;
+bool block_ipv6;
+
 /* add/remove Virtual IP addresses */
 static bool
 vrrp_handle_ipaddress(vrrp_t * vrrp, int cmd, int type)
@@ -124,7 +128,11 @@ vrrp_handle_accept_mode(vrrp_t *vrrp, int cmd, bool force)
 #ifdef _HAVE_LIBIPTC_
         do {
-            h = iptables_open();
+#ifdef _LIBIPTC_DYNAMIC_
+            if ((vrrp->family == AF_INET && using_libip4tc) ||
+                (vrrp->family == AF_INET6 && using_libip6tc))
+#endif
+                h = iptables_open();
 #endif
             /* As accept is false, add iptable rule to drop packets destinated to VIPs and eVIPs */
             if (!LIST_ISEMPTY(vrrp->vip))
@@ -132,7 +140,10 @@ vrrp_handle_accept_mode(vrrp_t *vrrp, int cmd, bool force)
             if (!LIST_ISEMPTY(vrrp->evip))
                 handle_iptable_rule_to_iplist(h, vrrp->evip, cmd, force);
 #ifdef _HAVE_LIBIPTC_
-            res = iptables_close(h);
+#ifdef _LIBIPTC_DYNAMIC_
+            if (h)
+#endif
+                res = iptables_close(h);
         } while (res == EAGAIN && ++tries < IPTABLES_MAX_TRIES);
 #endif
         vrrp->iptable_rules_set = (cmd == IPADDRESS_ADD);
@@ -2363,10 +2374,12 @@ vrrp_complete_instance(vrrp_t * vrrp)
     if (vrrp->base_priority != VRRP_PRIO_OWNER && !vrrp->accept) {
 //TODO = we have a problem since SNMP may change accept mode
 //it can also change priority
-        if (vrrp->saddr.ss_family == AF_INET)
-            global_data->block_ipv4 = true;
+        if (!global_data->vrrp_iptables_inchain[0])
+            log_message(LOG_INFO, "(%s): Unable to set no_accept mode since iptables chain name unset", vrrp->iname);
+        else if (vrrp->family == AF_INET)
+            block_ipv4 = true;
         else
-            global_data->block_ipv6 = true;
+            block_ipv6 = true;
     }
     if (!LIST_ISEMPTY(vrrp->vip)) {
         for (e = LIST_HEAD(vrrp->vip); e; ELEMENT_NEXT(e)) {
@@ -2390,7 +2403,6 @@ vrrp_complete_instance(vrrp_t * vrrp)
     if (!reload && interface_already_existed) {
 // TODO - consider reload
         vrrp->vipset = true;    /* Set to force address removal */
-        vrrp_restore_interface(vrrp, false, true);
     }
     /* See if we need to set promote_secondaries */
@@ -2452,12 +2464,6 @@ vrrp_complete_init(void)
     if (global_data->vrrp_garp_interval || global_data->vrrp_gna_interval)
         set_default_garp_delay();
-#ifdef _HAVE_LIBIPTC_
-    /* Make sure we don't have any old iptables/ipsets settings left around */
-    if (!reload)
-        iptables_cleanup();
-#endif
-
     /* Mark any scripts as insecure */
     check_vrrp_script_security();
@@ -2623,6 +2629,18 @@ vrrp_complete_init(void)
     return true;
 }
+void vrrp_restore_interfaces_startup(void)
+{
+    element e;
+    vrrp_t *vrrp;
+
+    for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) {
+        vrrp = ELEMENT_DATA(e);
+        if (vrrp->vipset)
+            vrrp_restore_interface(vrrp, false, true);
+    }
+}
+
 /* Try to find a VRRP instance */
 static vrrp_t *
 vrrp_exist(vrrp_t *old_vrrp)
@@ -2690,12 +2708,19 @@ clear_diff_vrrp_vip(vrrp_t *old_vrrp, vrrp_t *vrrp)
 #ifdef _HAVE_LIBIPTC_
     do {
-        h = iptables_open();
+#ifdef _LIBIPTC_DYNAMIC_
+        if ((vrrp->family == AF_INET && using_libip4tc) ||
+            (vrrp->family == AF_INET6 && using_libip6tc))
+#endif
+            h = iptables_open();
 #endif
         clear_diff_vrrp_vip_list(vrrp, h, old_vrrp->vip, vrrp->vip);
         clear_diff_vrrp_vip_list(vrrp, h, old_vrrp->evip, vrrp->evip);
 #ifdef _HAVE_LIBIPTC_
-        res = iptables_close(h);
+#ifdef _LIBIPTC_DYNAMIC_
+        if (h)
+#endif
+            res = iptables_close(h);
     } while (res == EAGAIN && ++tries < IPTABLES_MAX_TRIES);
 #endif
 }
diff --git a/keepalived/vrrp/vrrp_daemon.c b/keepalived/vrrp/vrrp_daemon.c
index 1c2f9e89..1e9282a7 100644
--- a/keepalived/vrrp/vrrp_daemon.c
+++ b/keepalived/vrrp/vrrp_daemon.c
@@ -202,8 +202,6 @@ start_vrrp(void)
     if (global_data->vrrp_no_swap)
         set_process_dont_swap(4096);    /* guess a stack size to reserve */
-    iptables_init();
-
 #ifdef _WITH_SNMP_
     if (!reload && (global_data->enable_snmp_keepalived || global_data->enable_snmp_rfcv2 || global_data->enable_snmp_rfcv3)) {
         vrrp_snmp_agent_init(global_data->snmp_socket);
@@ -266,10 +264,21 @@ start_vrrp(void)
         return;
     }
+    /* We need to delay the init of iptables to after vrrp_complete_init()
+     * has been called so we know whether we want IPv4 and/or IPv6 */
+    iptables_init();
+
+    /* Make sure we don't have any old iptables/ipsets settings left around */
 #ifdef _HAVE_LIBIPTC_
+    if (!reload)
+        iptables_cleanup();
+
     iptables_startup(reload);
 #endif
+    if (!reload)
+        vrrp_restore_interfaces_startup();
+
     /* clear_diff_vrrp must be called after vrrp_complete_init, since the latter
      * sets ifa_index on the addresses, which is used for the address comparison */
     if (reload)
diff --git a/keepalived/vrrp/vrrp_ipaddress.c b/keepalived/vrrp/vrrp_ipaddress.c
index eb332e72..c72ea736 100644
--- a/keepalived/vrrp/vrrp_ipaddress.c
+++ b/keepalived/vrrp/vrrp_ipaddress.c
@@ -27,6 +27,7 @@
 #ifdef _HAVE_LIBIPTC_
 #include "vrrp_iptables.h"
 #endif
+#include "vrrp.h"
 #include "keepalived_netlink.h"
 #include "vrrp_data.h"
 #include "logger.h"
@@ -38,11 +39,16 @@
 #if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
 #include "utils.h"
 #endif
+#ifdef _LIBIPTC_DYNAMIC_
+#include "vrrp_iptables.h"
+#endif
 #define INFINITY_LIFE_TIME      0xFFFFFFFF
-bool iptables_cmd_available = true;
-bool ip6tables_cmd_available = true;
+#if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
+static bool iptables_cmd_available;
+static bool ip6tables_cmd_available;
+#endif
 char *
 ipaddresstos(char *buf, ip_address_t *ipaddress)
@@ -250,9 +256,6 @@ handle_iptable_rule_to_vip_cmd(ip_address_t *ipaddress, int cmd, bool force)
     char *addr_str;
     char *ifname = NULL;
-    if (global_data->vrrp_iptables_inchain[0] == '\0')
-        return;
-
     if (IP_IS6(ipaddress)) {
         if (!ip6tables_cmd_available)
             return;
@@ -316,9 +319,18 @@ handle_iptable_rule_to_vip(ip_address_t *ipaddr, int cmd,
 #endif
                                                    bool force)
 {
+    if (IP_IS6(ipaddr)) {
+        if (!block_ipv6)
+            return;
+    } else {
+        if (!block_ipv4)
+            return;
+    }
+
 #ifdef _HAVE_LIBIPTC_
 #ifdef _LIBIPTC_DYNAMIC_
-    if (using_libiptc)
+    if ((IP_IS6(ipaddr) && using_libip6tc) ||
+        (!IP_IS6(ipaddr) && using_libip4tc))
 #endif
     {
         handle_iptable_rule_to_vip_lib(ipaddr, cmd, h, force);
@@ -612,31 +624,122 @@ clear_diff_saddresses(void)
     clear_diff_address(NULL, old_vrrp_data->static_addresses, vrrp_data->static_addresses);
 }
+static void
+check_chains_exist(void)
+{
+#ifdef _HAVE_LIBIPTC_
+#ifdef _LIBIPTC_DYNAMIC_
+    if (using_libip4tc || using_libip6tc)
+#endif
+        check_chains_exist_lib();
+#endif
+
+#if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
+    char *argv[4];
+
+    argv[1] = "-nL";
+    argv[2] = global_data->vrrp_iptables_inchain;
+    argv[3] = NULL;
+
+    if (block_ipv4)
+    {
+#ifdef _LIBIPTC_DYNAMIC_
+        if (!using_libip4tc)
+#endif
+        {
+            argv[0] = "iptables";
+
+            if (fork_exec(argv) < 0) {
+                log_message(LOG_INFO, "iptables chain %s does not exist", global_data->vrrp_iptables_inchain);
+                block_ipv4 = false;
+            }
+            else if (global_data->vrrp_iptables_outchain[0]) {
+                argv[2] = global_data->vrrp_iptables_outchain;
+                if (fork_exec(argv) < 0) {
+                    log_message(LOG_INFO, "iptables chain %s does not exist", global_data->vrrp_iptables_outchain);
+                    block_ipv4 = false;
+                }
+            }
+        }
+    }
+
+    if (block_ipv6)
+    {
+#ifdef _LIBIPTC_DYNAMIC_
+        if (!using_libip6tc)
+#endif
+        {
+            argv[0] = "ip6tables";
+            argv[2] = global_data->vrrp_iptables_inchain;
+
+            if (fork_exec(argv) < 0) {
+                log_message(LOG_INFO, "ip6tables chain %s does not exist", global_data->vrrp_iptables_inchain);
+                block_ipv6 = false;
+            }
+            else if (global_data->vrrp_iptables_outchain[0]) {
+                argv[2] = global_data->vrrp_iptables_outchain;
+                if (fork_exec(argv) < 0) {
+                    log_message(LOG_INFO, "ip6tables chain %s does not exist", global_data->vrrp_iptables_outchain);
+                    block_ipv6 = false;
+                }
+            }
+        }
+    }
+#endif
+}
+
 void
 iptables_init(void)
 {
-#ifdef _HAVE_LIBIPTC_
-    if (iptables_init_lib())
+    if (!block_ipv4 && !block_ipv6) {
+#ifdef _HAVE_LIBIPSET_
+        global_data->using_ipsets = false;
+#endif
         return;
+    }
+
+#ifdef _HAVE_LIBIPTC_
+    iptables_init_lib();
 #endif
 #if !defined _HAVE_LIBIPTC_ || defined _LIBIPTC_DYNAMIC_
     char *argv[3];
-    /* We can't use libiptc, so check iptables command available */
-    argv[0] = "iptables";
+    /* If can't use libiptc, check iptables command available */
     argv[1] = "-V";
     argv[2] = NULL;
-    if (fork_exec(argv) < 0) {
-        log_message(LOG_INFO, "iptables command not available - can't filter IPv4 VIP address destinations");
-        iptables_cmd_available = false;
+    if (block_ipv4
+#ifdef _LIBIPTC_DYNAMIC_
+               && !using_libip4tc
+#endif
+                       )
+    {
+        argv[0] = "iptables";
+        if (!(iptables_cmd_available = (fork_exec(argv) >= 0))) {
+            log_message(LOG_INFO, "iptables command not available - can't filter IPv4 VIP address destinations");
+            block_ipv4 = false;
+        }
     }
-    argv[0] = "ip6tables";
-    if (fork_exec(argv) < 0) {
-        log_message(LOG_INFO, "ip6tables command not available - can't filter IPv6 VIP address destinations");
-        ip6tables_cmd_available = false;
+    if (block_ipv6
+#ifdef _LIBIPTC_DYNAMIC_
+               && !using_libip6tc
+#endif
+                     )
+    {
+        argv[0] = "ip6tables";
+        if (!(ip6tables_cmd_available = (fork_exec(argv) >= 0))) {
+            log_message(LOG_INFO, "ip6tables command not available - can't filter IPv6 VIP address destinations");
+            block_ipv6 = false;
+        }
     }
 #endif
+
+    if (block_ipv4 || block_ipv6)
+        check_chains_exist();
+#ifdef _HAVE_LIBIPSET_
+    else
+        global_data->using_ipsets = false;
+#endif
 }
diff --git a/keepalived/vrrp/vrrp_ipset.c b/keepalived/vrrp/vrrp_ipset.c
index 194809f0..1c3e4990 100644
--- a/keepalived/vrrp/vrrp_ipset.c
+++ b/keepalived/vrrp/vrrp_ipset.c
@@ -38,12 +38,14 @@
 #include <linux/types.h>        /* For __beXX types in userland */
 #include <linux/netfilter.h>    /* For nf_inet_addr */
 #include <stdint.h>
+#include <stdio.h>
 #include "logger.h"
 #include "global_data.h"
 #include "vrrp_iptables.h"
 #include "vrrp_ipset.h"
 #include "vrrp_ipaddress.h"
+#include "vrrp.h"
 #include "main.h"
 #ifdef _LIBIPSET_DYNAMIC_
@@ -146,7 +148,7 @@ has_ipset_setname(struct ipset_session* session, const char *setname)
     return ipset_cmd1(session, IPSET_CMD_HEADER, 0) == 0;
 }
-static int create_sets(const char* addr4, const char* addr6, const char* addr_if6, bool reload)
+static bool create_sets(const char* addr4, const char* addr6, const char* addr_if6, bool reload)
 {
     struct ipset_session *session;
@@ -161,12 +163,12 @@ static int create_sets(const char* addr4, const char* addr6, const char* addr_if
     if (!reload)
         ipset_envopt_parse(session, IPSET_ENV_EXIST, NULL);
-    if (use_ip4tables) {
+    if (block_ipv4) {
         if (!reload || !has_ipset_setname(session, addr4))
             ipset_create(session, addr4, "hash:ip", NFPROTO_IPV4);
     }
-    if (use_ip6tables) {
+    if (block_ipv6) {
         if (!reload || !has_ipset_setname(session, addr6))
             ipset_create(session, addr6, "hash:ip", NFPROTO_IPV6);
         if (!reload || !has_ipset_setname(session, addr_if6)) {
@@ -184,6 +186,30 @@ static int create_sets(const char* addr4, const char* addr6, const char* addr_if
     return true;
 }
+static
+bool set_match_loaded(void)
+{
+    char buf[XT_FUNCTION_MAXNAMELEN+1];
+    FILE *fp;
+    bool found = false;
+
+    fp = fopen( "/proc/net/ip_tables_matches", "r");
+    if (!fp)
+        return false;
+
+    while (fgets(buf, sizeof(buf), fp)) {
+        if ((buf[3] == '\0' || buf[3] == '\n') &&
+            !strncmp(buf, "set", 3)) {
+            found = true;
+            break;
+        }
+    }
+
+    fclose(fp);
+
+    return found;
+}
+
 bool ipset_init(void)
 {
 #ifdef _LIBIPSET_DYNAMIC_
@@ -213,44 +239,47 @@ bool ipset_init(void)
         return false;
     }
-    int err = false;
-    if (!(ipset_session_init_addr = dlsym(libipset_handle, "ipset_session_init"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_init"); err = true;}
-    if (!(ipset_session_fini_addr = dlsym(libipset_handle, "ipset_session_fini"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_fini"); err = true;}
-    if (!(ipset_session_data_addr = dlsym(libipset_handle,"ipset_session_data"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_data"); err = true;}
-    if (!(ipset_session_error_addr = dlsym(libipset_handle,"ipset_session_error"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_session_error"); err = true;}
-    if (!(ipset_envopt_parse_addr = dlsym(libipset_handle,"ipset_envopt_parse"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_envopt_parse"); err = true;}
-    if (!(ipset_type_get_addr = dlsym(libipset_handle,"ipset_type_get"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_type_get"); err = true;}
-    if (!(ipset_data_set_addr = dlsym(libipset_handle,"ipset_data_set"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_data_set"); err = true;}
-    if (!(ipset_cmd_addr = dlsym(libipset_handle,"ipset_cmd"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_cmd"); err = true;}
-    if (!(ipset_load_types_addr = dlsym(libipset_handle,"ipset_load_types"))) {log_message(LOG_INFO, "Failed to dynamic link ipset_load_types"); err = true;}
-    if (err) {
-        log_message(LOG_INFO, "Failed to dynamic link an ipset function");
+    if (!(ipset_session_init_addr = dlsym(libipset_handle, "ipset_session_init")) ||
+        !(ipset_session_fini_addr = dlsym(libipset_handle, "ipset_session_fini")) ||
+        !(ipset_session_data_addr = dlsym(libipset_handle,"ipset_session_data")) ||
+        !(ipset_session_error_addr = dlsym(libipset_handle,"ipset_session_error")) ||
+        !(ipset_envopt_parse_addr = dlsym(libipset_handle,"ipset_envopt_parse")) ||
+        !(ipset_type_get_addr = dlsym(libipset_handle,"ipset_type_get")) ||
+        !(ipset_data_set_addr = dlsym(libipset_handle,"ipset_data_set")) ||
+        !(ipset_cmd_addr = dlsym(libipset_handle,"ipset_cmd")) ||
+        !(ipset_load_types_addr = dlsym(libipset_handle,"ipset_load_types"))) {
+        log_message(LOG_INFO, "Failed to dynamic link an ipset function - %s", dlerror());
         return false;
     }
 #endif
     ipset_load_types();
-    if (!load_xtables_module("xt_set", "ipsets"))
+    if (!set_match_loaded() && !load_xtables_module("xt_set", "ipsets")) {
+        log_message(LOG_INFO, "Unable to load module xt_set - not using ipsets");
         return false;
+    }
     return true;
 }
-int remove_ipsets(void)
+bool remove_ipsets(void)
 {
     struct ipset_session *session;
+    if (!global_data->using_ipsets)
+        return true;
+
     session = ipset_session_init(printf);
     if (!session) {
         log_message(LOG_INFO, "Cannot initialize ipset session.");
         return false;
     }
-    if (use_ip4tables)
+    if (block_ipv4)
         ipset_destroy(session, global_data->vrrp_ipset_address);
-    if (use_ip6tables) {
+    if (block_ipv6) {
         ipset_destroy(session, global_data->vrrp_ipset_address6);
         ipset_destroy(session, global_data->vrrp_ipset_address_iface6);
     }
@@ -260,7 +289,7 @@ int remove_ipsets(void)
     return true;
 }
-int add_ipsets(bool reload)
+bool add_ipsets(bool reload)
 {
     return create_sets(global_data->vrrp_ipset_address, global_data->vrrp_ipset_address6, global_data->vrrp_ipset_address_iface6, reload);
 }
@@ -281,12 +310,12 @@ void ipset_entry(struct ipset_session* session, int cmd, const ip_address_t* add
     char *iface = NULL;
     if (addr->ifa.ifa_family == AF_INET) {
-        if (!use_ip4tables)
+        if (!block_ipv4)
             return;
         set = global_data->vrrp_ipset_address;
     }
     else if (IN6_IS_ADDR_LINKLOCAL(&addr->u.sin6_addr)) {
-        if (!use_ip6tables)
+        if (!block_ipv6)
             return;
         set = global_data->vrrp_ipset_address_iface6;
diff --git a/keepalived/vrrp/vrrp_iptables.c b/keepalived/vrrp/vrrp_iptables.c
index 2c218cac..60ff6c8c 100644
--- a/keepalived/vrrp/vrrp_iptables.c
+++ b/keepalived/vrrp/vrrp_iptables.c
@@ -59,6 +59,10 @@
 #include <xtables.h>
 #include <libipset/linux_ip_set.h>
 #endif
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <linux/magic.h>
+#include <stdbool.h>
 #include "vrrp_iptables.h"
 #include "vrrp_iptables_calls.h"
@@ -81,10 +85,9 @@ struct ipt_handle {
 /* If the chains don't exist, or modules not loaded, we can't use iptables/ip6tables */
 #ifdef _LIBIPTC_DYNAMIC_
-bool using_libiptc = true;
+bool using_libip4tc = false;
+bool using_libip6tc = false;
 #endif
-bool use_ip4tables = true;
-bool use_ip6tables = true;
 #ifdef _HAVE_LIBIPSET_
 static
@@ -105,10 +108,13 @@ void add_del_rules(int cmd, bool ignore_errors)
     struct iptc_handle *h4;
     struct ip6tc_handle *h6;
-    if (use_ip4tables &&
-        global_data->block_ipv4 &&
+    if (block_ipv4 &&
         (global_data->vrrp_iptables_inchain[0] ||
-         global_data->vrrp_iptables_outchain[0])) {
+         global_data->vrrp_iptables_outchain[0])
+#ifdef _LIBIPTC_DYNAMIC_
+        && using_libip4tc
+#endif
+                  ) {
         if ((h4 = ip4tables_open("filter"))) {
             if (global_data->vrrp_iptables_inchain[0])
                 ip4tables_add_rules(h4, global_data->vrrp_iptables_inchain, APPEND_RULE, IPSET_DIM_ONE, 0, XTC_LABEL_DROP, global_data->vrrp_ipset_address, IPPROTO_NONE, 0, cmd, ignore_errors);
@@ -118,10 +124,13 @@ void add_del_rules(int cmd, bool ignore_errors)
         }
     }
-    if (use_ip6tables &&
-        global_data->block_ipv6 &&
+    if (block_ipv6 &&
         (global_data->vrrp_iptables_inchain[0] ||
-         global_data->vrrp_iptables_outchain[0])) {
+         global_data->vrrp_iptables_outchain[0])
+#ifdef _LIBIPTC_DYNAMIC_
+        && using_libip6tc
+#endif
+                 ) {
         if ((h6 = ip6tables_open("filter"))) {
             if (global_data->vrrp_iptables_inchain[0]) {
 #ifdef HAVE_IPSET_ATTR_IFACE
@@ -185,58 +194,64 @@ int iptables_close(struct ipt_handle* h)
     return res;
 }
-static void check_chains_exist(void)
+void check_chains_exist_lib(void)
 {
     struct iptc_handle *h4;
     struct ip6tc_handle *h6;
-    if (global_data->block_ipv4) {
-        h4 = ip4tables_open("filter");
-
-        if (!h4) {
-            log_message(LOG_INFO, "WARNING, ip_tables module not installed - can't filter IPv4 addresses");
-            use_ip4tables = false;
-        } else {
-            if (global_data->vrrp_iptables_inchain[0] &&
-                !ip4tables_is_chain(h4, global_data->vrrp_iptables_inchain)) {
-                log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
-                use_ip4tables = false;
-            }
-            if (global_data->vrrp_iptables_outchain[0] &&
-                !ip4tables_is_chain(h4, global_data->vrrp_iptables_outchain)) {
-                log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
-                use_ip4tables = false;
+    if (block_ipv4) {
+#ifdef _LIBIPTC_DYNAMIC_
+        if (using_libip4tc)
+#endif
+        {
+            h4 = ip4tables_open("filter");
+
+            if (!h4) {
+                log_message(LOG_INFO, "WARNING, ip_tables module not installed - can't filter IPv4 addresses");
+                block_ipv4 = false;
+            } else {
+                if (global_data->vrrp_iptables_inchain[0] &&
+                    !ip4tables_is_chain(h4, global_data->vrrp_iptables_inchain)) {
+                    log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
+                    block_ipv4 = false;
+                }
+                if (global_data->vrrp_iptables_outchain[0] &&
+                    !ip4tables_is_chain(h4, global_data->vrrp_iptables_outchain)) {
+                    log_message(LOG_INFO, "iptables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
+                    block_ipv4 = false;
+                }
+
+                ip4tables_close(h4, false);
             }
-
-            ip4tables_close(h4, false);
         }
     }
-    else
-        use_ip4tables = false;
-
-    if (global_data->block_ipv6) {
-        h6 = ip6tables_open("filter");
-
-        if (!h6) {
-            log_message(LOG_INFO, "WARNING, ip6_tables module not installed - can't filter IPv6 addresses");
-            use_ip6tables = false;
-        } else {
-            if (global_data->vrrp_iptables_inchain[0] &&
-                !ip6tables_is_chain(h6, global_data->vrrp_iptables_inchain)) {
-                log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
-                use_ip6tables = false;
-            }
-            if (global_data->vrrp_iptables_outchain[0] &&
-                !ip6tables_is_chain(h6, global_data->vrrp_iptables_outchain)) {
-                log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
-                use_ip6tables = false;
-            }
-            ip6tables_close(h6, false);
+    if (block_ipv6) {
+#ifdef _LIBIPTC_DYNAMIC_
+        if (using_libip6tc)
+#endif
+        {
+            h6 = ip6tables_open("filter");
+
+            if (!h6) {
+                log_message(LOG_INFO, "WARNING, ip6_tables module not installed - can't filter IPv6 addresses");
+                block_ipv6 = false;
+            } else {
+                if (global_data->vrrp_iptables_inchain[0] &&
+                    !ip6tables_is_chain(h6, global_data->vrrp_iptables_inchain)) {
+                    log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_inchain);
+                    block_ipv6 = false;
+                }
+                if (global_data->vrrp_iptables_outchain[0] &&
+                    !ip6tables_is_chain(h6, global_data->vrrp_iptables_outchain)) {
+                    log_message(LOG_INFO, "ip6tables chain %s doesn't exist", global_data->vrrp_iptables_outchain);
+                    block_ipv6 = false;
+                }
+
+                ip6tables_close(h6, false);
+            }
         }
     }
-    else
-        use_ip6tables = false;
 }
 static int iptables_entry(struct ipt_handle* h, const char* chain_name, unsigned int rulenum, char* target_name, const ip_address_t* src_ip_address, const ip_address_t* dst_ip_address, const char* in_iface, const char* out_iface, uint16_t protocol, uint8_t type, int cmd, bool force)
@@ -303,11 +318,8 @@ handle_iptable_rule_to_vip_lib(ip_address_t *ipaddress, int cmd, struct ipt_hand
     char *ifname = NULL;
     /* If iptables for the address family isn't in use, skip */
-    if ((ipaddress->ifa.ifa_family == AF_INET && !use_ip4tables) ||
-        (ipaddress->ifa.ifa_family == AF_INET6 && !use_ip6tables))
-        return;
-
-    if (global_data->vrrp_iptables_inchain[0] == '\0')
+    if ((ipaddress->ifa.ifa_family == AF_INET && !block_ipv4) ||
+        (ipaddress->ifa.ifa_family == AF_INET6 && !block_ipv6))
         return;
 #ifdef _HAVE_LIBIPSET_
@@ -343,33 +355,28 @@ handle_iptable_rule_to_vip_lib(ip_address_t *ipaddress, int cmd, struct ipt_hand
             IPPROTO_NONE, 0, cmd, force);
 }
+#ifdef _HAVE_LIBIPSET_
 static void
-iptables_remove_structure(
-#ifndef _HAVE_LIBIPSET_
-              __attribute__((unused))
-#endif
-                         bool ignore_errors)
+iptables_remove_structure(bool ignore_errors)
 {
-#ifdef _HAVE_LIBIPSET_
     if (global_data->using_ipsets) {
         add_del_rules(IPADDRESS_DEL, ignore_errors);
         add_del_sets(IPADDRESS_DEL, false);
     }
-#endif
 }
+#endif
 void
-iptables_startup(bool reload)
+iptables_startup(
+#ifndef _HAVE_LIBIPSET_
+         __attribute__((unused))
+#endif
+                     bool reload)
 {
-    if (!reload) {
-        check_chains_exist();
 #ifdef _HAVE_LIBIPSET_
-        if (!use_ip4tables && !use_ip6tables)
-            global_data->using_ipsets = false;
-#endif
-    }
+    if (!block_ipv4 && !block_ipv6)
+        global_data->using_ipsets = false;
-#ifdef _HAVE_LIBIPSET_
     if (global_data->using_ipsets) {
         add_del_sets(IPADDRESS_ADD, reload);
         add_del_rules(IPADDRESS_ADD, false);
@@ -380,50 +387,94 @@ iptables_startup(bool reload)
 void
 iptables_cleanup(void)
 {
+#ifdef _HAVE_LIBIPSET_
     iptables_remove_structure(true);
+#endif
+}
+
+/* return true if a given file exists within procfs */
+/* Taken from iptables code */
+static
+bool proc_file_exists(const char *filename)
+{
+    struct stat s;
+    struct statfs f;
+
+    if (lstat(filename, &s))
+        return false;
+    if (!S_ISREG(s.st_mode))
+        return false;
+    if (statfs(filename, &f))
+        return false;
+    if (f.f_type != PROC_SUPER_MAGIC)
+        return false;
+
+    return true;
 }
-bool
+void
 iptables_init_lib(void)
 {
-#ifdef _LIBXTABLES_DYNAMIC_
-    xtables_load();
+    if (block_ipv4) {
+        if (!proc_file_exists("/proc/net/ip_tables_names") &&
+            !load_xtables_module("ip_tables", "iptables"))
+#ifdef _LIBIPTC_DYNAMIC_
+            using_libip4tc = false;
+        else
+            using_libip4tc = true;
+#else
+        {
+            block_ipv4 = false;
+            log_message(LOG_INFO, "Unable to load module ip_tables");
+        }
 #endif
+    }
+    if (block_ipv6) {
+        if (!proc_file_exists("/proc/net/ip6_tables_names") &&
+            !load_xtables_module("ip6_tables", "ip6tables"))
 #ifdef _LIBIPTC_DYNAMIC_
-    if (!iptables_lib_init()) {
-        using_libiptc = false;
-#ifdef _LIBXTABLES_DYNAMIC_
-        xtables_unload();
+            using_libip6tc = false;
+        else
+            using_libip6tc = true;
+#else
+        {
+            block_ipv6 = false;
+            log_message(LOG_INFO, "Unable to load module ip_tables");
+        }
 #endif
-        return false;
     }
-#endif
-    if (!load_xtables_module("ip_tables", "iptables")) {
 #ifdef _LIBIPTC_DYNAMIC_
-        using_libiptc = false;
-#endif
+    if ((!block_ipv4 && !block_ipv6) ||
+        (!using_libip4tc && !using_libip6tc) ||
+        !iptables_lib_init()) {
 #ifdef _LIBXTABLES_DYNAMIC_
         xtables_unload();
 #endif
-        return false;
+
+#ifdef _HAVE_LIBIPSET_
+        global_data->using_ipsets = false;
+#endif
+
+        return;
     }
+#endif
 #ifdef _HAVE_LIBIPSET_
-    if (!ipset_init())
+    if (global_data->using_ipsets && !ipset_init())
         global_data->using_ipsets = false;
 #endif
 #ifdef _LIBXTABLES_DYNAMIC_
     xtables_unload();
 #endif
-
-    return true;
 }
 void
 iptables_fini(void)
 {
+#ifdef _HAVE_LIBIPSET_
     iptables_remove_structure(false);
+#endif
 }
diff --git a/keepalived/vrrp/vrrp_iptables_calls.c b/keepalived/vrrp/vrrp_iptables_calls.c
index fb5c98df..ff6b7e6e 100644
--- a/keepalived/vrrp/vrrp_iptables_calls.c
+++ b/keepalived/vrrp/vrrp_iptables_calls.c
@@ -37,22 +37,18 @@
 #include <xtables.h>
 #include <libiptc/libiptc.h>
 #include <libiptc/libip6tc.h>
-#ifdef _HAVE_LIBIPSET_
 #include <libipset/linux_ip_set.h>
 #if defined XT_SET_H_ADD_IP_SET_H_GUARD
 #define _IP_SET_H
 #elif defined XT_SET_H_ADD_UAPI_IP_SET_H_GUARD
 #define _UAPI_IP_SET_H
 #endif
+#ifdef _HAVE_LIBIPSET_
 #include <linux/netfilter/xt_set.h>
 #endif
 #include <unistd.h>
 #include <signal.h>
 #include <stdint.h>
-#ifdef _LIBXTABLES_DYNAMIC_
-#include <sys/types.h>
-#include <sys/stat.h>
-#endif
 #include "vrrp_iptables_calls.h"
 #include "memory.h"
@@ -63,6 +59,7 @@
 #ifdef _LIBIPTC_DYNAMIC_
 #include "global_data.h"
 #endif
+#include "vrrp_iptables.h"
 /* We sometimes get a resource_busy on iptc_commit. This appears to happen
  * when someone else is also updating it.
@@ -406,6 +403,7 @@ int ip6tables_process_entry( struct ip6tc_handle* handle, const char* chain_name
 #ifdef _HAVE_LIBIPTC_
 #ifdef _LIBXTABLES_DYNAMIC_
+static
 bool xtables_load(void)
 {
     if (libxtables_handle)
@@ -418,7 +416,7 @@ bool xtables_load(void)
     }
     if (!(xtables_insmod_addr = dlsym(libxtables_handle, "xtables_insmod"))) {
-        log_message(LOG_INFO, "Failed to dynamic link xtables_insmod");
+        log_message(LOG_INFO, "Failed to dynamic link xtables_insmod - %s", dlerror());
         dlclose(libxtables_handle);
         libxtables_handle = NULL;
@@ -438,25 +436,18 @@ void xtables_unload(void)
 }
 #endif
-bool load_xtables_module(const char *module,
+bool
+load_xtables_module(const char *module,
 #ifndef _LIBXTABLES_DYNAMIC_
-                        __attribute__((unused))
+                    __attribute__((unused))
 #endif
-                                    const char *function)
+                                const char *function)
 {
     struct sigaction act, old_act;
     bool res = true;
-#ifdef _LIBXTABLES_DYNAMIC_
-    struct stat stat_buf;
-    char module_path[32] = "/sys/module/";
-
-    if (!libxtables_handle) {
-        /* See if the module is loaded anyway */
-        strcat(module_path, module);
-        if (!stat(module_path, &stat_buf) &&
-            (stat_buf.st_mode & S_IFDIR))
-            return true;
+#ifdef _LIBXTABLES_DYNAMIC_
+    if (!libxtables_handle && !xtables_load()) {
         log_message(LOG_INFO, "Module %s cannot be loaded; not using %s", module, function);
         return false;
     }
@@ -882,47 +873,50 @@ int ip6tables_add_rules(struct ip6tc_handle* handle, const char* chain_name, uns
 #ifdef _LIBIPTC_DYNAMIC_
 bool iptables_lib_init(void)
 {
-    if (libip4tc_handle)
-        return true;
-
-    /* Attempt to open the ip4tc library */
-    if (!(libip4tc_handle = dlopen("libip4tc.so", RTLD_NOW)) &&
-        !(libip4tc_handle = dlopen(IP4TC_LIB_NAME, RTLD_NOW))) {
-        log_message(LOG_INFO, "Unable to load ip4tc library - %s", dlerror());
-        return false;
-    }
-
-    if (!(iptc_init_addr = dlsym(libip4tc_handle, "iptc_init")) ||
-        !(iptc_free_addr = dlsym(libip4tc_handle, "iptc_free")) ||
-        !(iptc_is_chain_addr = dlsym(libip4tc_handle,"iptc_is_chain")) ||
-        !(iptc_insert_entry_addr = dlsym(libip4tc_handle,"iptc_insert_entry")) ||
-        !(iptc_append_entry_addr = dlsym(libip4tc_handle,"iptc_append_entry")) ||
-        !(iptc_delete_entry_addr = dlsym(libip4tc_handle,"iptc_delete_entry")) ||
-        !(iptc_commit_addr = dlsym(libip4tc_handle,"iptc_commit")) ||
-        !(iptc_strerror_addr = dlsym(libip4tc_handle,"iptc_strerror")))
-        log_message(LOG_INFO, "Failed to dynamic link an iptc function");
-
-    /* Attempt to open the ip6tc library */
-    if (!(libip6tc_handle = dlopen("libip6tc.so", RTLD_NOW)) &&
-        !(libip6tc_handle = dlopen(IP6TC_LIB_NAME, RTLD_NOW))) {
-        log_message(LOG_INFO, "Unable to load ip6tc library - %s", dlerror());
-
-        if (global_data->block_ipv4)
+    if (!libip4tc_handle && block_ipv4) {
+        /* Attempt to open the ip4tc library */
+        if (!(libip4tc_handle = dlopen("libip4tc.so", RTLD_NOW)) &&
+            !(libip4tc_handle = dlopen(IP4TC_LIB_NAME, RTLD_NOW))) {
+            log_message(LOG_INFO, "Unable to load ip4tc library - %s", dlerror());
+            using_libip4tc = false;
+        }
+        else if (!(iptc_init_addr = dlsym(libip4tc_handle, "iptc_init")) ||
+             !(iptc_free_addr = dlsym(libip4tc_handle, "iptc_free")) ||
+             !(iptc_is_chain_addr = dlsym(libip4tc_handle,"iptc_is_chain")) ||
+             !(iptc_insert_entry_addr = dlsym(libip4tc_handle,"iptc_insert_entry")) ||
+             !(iptc_append_entry_addr = dlsym(libip4tc_handle,"iptc_append_entry")) ||
+             !(iptc_delete_entry_addr = dlsym(libip4tc_handle,"iptc_delete_entry")) ||
+             !(iptc_commit_addr = dlsym(libip4tc_handle,"iptc_commit")) ||
+             !(iptc_strerror_addr = dlsym(libip4tc_handle,"iptc_strerror"))) {
+            log_message(LOG_INFO, "Failed to dynamic link an iptc function - %s", dlerror());
+            using_libip4tc = false;
             dlclose(libip4tc_handle);
-
-        return false;
+            libip4tc_handle = NULL;
+        }
     }
-    if (!(ip6tc_init_addr = dlsym(libip6tc_handle, "ip6tc_init")) ||
-        !(ip6tc_free_addr = dlsym(libip6tc_handle, "ip6tc_free")) ||
-        !(ip6tc_is_chain_addr = dlsym(libip6tc_handle,"ip6tc_is_chain")) ||
-        !(ip6tc_insert_entry_addr = dlsym(libip6tc_handle,"ip6tc_insert_entry")) ||
-        !(ip6tc_append_entry_addr = dlsym(libip6tc_handle,"ip6tc_append_entry")) ||
-        !(ip6tc_delete_entry_addr = dlsym(libip6tc_handle,"ip6tc_delete_entry")) ||
-        !(ip6tc_commit_addr = dlsym(libip6tc_handle,"ip6tc_commit")) ||
-        !(ip6tc_strerror_addr = dlsym(libip6tc_handle,"ip6tc_strerror")))
-        log_message(LOG_INFO, "Failed to dynamic link an ip6tc function");
+    if (!libip6tc_handle && block_ipv6) {
+        /* Attempt to open the ip6tc library */
+        if (!(libip6tc_handle = dlopen("libip6tc.so", RTLD_NOW)) &&
+            !(libip6tc_handle = dlopen(IP6TC_LIB_NAME, RTLD_NOW))) {
+            log_message(LOG_INFO, "Unable to load ip6tc library - %s", dlerror());
+            using_libip6tc = false;
+        }
+        else if (!(ip6tc_init_addr = dlsym(libip6tc_handle, "ip6tc_init")) ||
+             !(ip6tc_free_addr = dlsym(libip6tc_handle, "ip6tc_free")) ||
+             !(ip6tc_is_chain_addr = dlsym(libip6tc_handle,"ip6tc_is_chain")) ||
+             !(ip6tc_insert_entry_addr = dlsym(libip6tc_handle,"ip6tc_insert_entry")) ||
+             !(ip6tc_append_entry_addr = dlsym(libip6tc_handle,"ip6tc_append_entry")) ||
+             !(ip6tc_delete_entry_addr = dlsym(libip6tc_handle,"ip6tc_delete_entry")) ||
+             !(ip6tc_commit_addr = dlsym(libip6tc_handle,"ip6tc_commit")) ||
+             !(ip6tc_strerror_addr = dlsym(libip6tc_handle,"ip6tc_strerror"))) {
+            log_message(LOG_INFO, "Failed to dynamic link an ip6tc function - %s", dlerror());
+            using_libip6tc = false;
+            dlclose(libip6tc_handle);
+            libip6tc_handle = NULL;
+        }
+    }
-    return true;
+    return libip4tc_handle || libip6tc_handle;
 }
 #endif
--
2.13.5
SOURCES/bz1508435-no-segfault-ip_vs-load.patch
New file
@@ -0,0 +1,168 @@
From 19d0482859d9068b893104b9f8beeaba709aec2d Mon Sep 17 00:00:00 2001
From: Quentin Armitage <quentin@armitage.org.uk>
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 <quentin@armitage.org.uk>
---
 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
SOURCES/bz1508435-remove-ipset-handling.patch
New file
@@ -0,0 +1,30 @@
From dcb5af32ea618c42e353f399962bdd6dc1c8a7d9 Mon Sep 17 00:00:00 2001
From: Quentin Armitage <quentin@armitage.org.uk>
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 <quentin@armitage.org.uk>
---
 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
SOURCES/keepalived.service
New file
@@ -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
SPECS/keepalived.spec
New file
@@ -0,0 +1,384 @@
%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: 6%{?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
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
%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
* Wed Jan 31 2018 Ryan O'Hara <rohara@redhat.com> - 1.3.5-6
- Add net-snmp as BuildRequires (#1536252)
* Mon Dec 11 2017 Ryan O'Hara <rohara@redhat.com> - 1.3.5-5
- Exclude VIPs of non-matching address family (#1477587)
* Thu Nov 16 2017 Ryan O'Hara <rohara@redhat.com> - 1.3.5-4
- Fix bugs related to failures when load modules and/or segfaults (#1508435)
* Wed Aug 02 2017 Ryan O'Hara <rohara@redhat.com> - 1.3.5-3
- Don't complain about keepalived_script user if not needed (#1477563)
* Wed Aug 02 2017 Ryan O'Hara <rohara@redhat.com> - 1.3.5-2
- Fix ipset-libs dependency and vrrp_ipset in man page (#1477572)
* Wed Mar 22 2017 Ryan O'Hara <rohara@redhat.com> - 1.3.5-1
- Rebase to upstream version 1.3.5 (#1419049)
* Thu Mar 16 2017 Ryan O'Hara <rohara@redhat.com> - 1.3.4-2
- Start keepalived after network-online.target (#1425828)
* Wed Mar 15 2017 Ryan O'Hara <rohara@redhat.com> - 1.3.4-1
- Rebase to upstream version 1.3.4 (#1419049)
* Fri Jul 01 2016 Ryan O'Hara <rohara@redhat.com> - 1.2.13-8
- Add PIDFile to systemd unit file (#1336190)
* Thu Jun 25 2015 Ryan O'Hara <rohara@redhat.com> - 1.2.13-7
- Set global default values after parsing config file (#1181107)
* Tue Nov 18 2014 Ryan O'Hara <rohara@redhat.com> - 1.2.13-6
- Fix typo in changelog
* Mon Nov 10 2014 Ryan O'Hara <rohara@redhat.com> - 1.2.13-5
- Bump release number (#1158114)
* Thu Nov 06 2014 Ryan O'Hara <rohara@redhat.com> - 1.2.13-4
- Create /usr/libexec/keepalived directory (#1158114)
* Tue Sep 30 2014 Ryan O'Hara <rohara@redhat.com> - 1.2.13-3
- Minor spec file modifications (#1067693, #1067145)
* Tue Sep 30 2014 Ryan O'Hara <rohara@redhat.com> - 1.2.13-2
- Add SNMP subsystem option to man page (#1085535)
* Thu Aug 07 2014 Ryan O'Hara <rohara@redhat.com> - 1.2.13-1
- Rebase to upstream version 1.2.13 (#1111716)
* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 1.2.10-2
- Mass rebuild 2014-01-24
* Tue Jan 14 2014 Ryan O'Hara <rohara@redhat.com> - 1.2.10-1
- Rebase to upstream version 1.2.10 (#1052359)
* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 1.2.8-2
- Mass rebuild 2013-12-27
* Thu Sep 05 2013 Ryan O'Hara <rohara@redhat.com> - 1.2.8-1
- Update to 1.2.8.
* Mon Jul 22 2013 Ryan O'Hara <rohara@redhat.com> - 1.2.7-8
- Fix macro in keepalived.conf.5 man page.
* Mon Jul 22 2013 Ryan O'Hara <rohara@redhat.com> - 1.2.7-7
- Fix systemd requirements.
* Mon Jul 22 2013 Ryan O'Hara <rohara@redhat.com> - 1.2.7-6
- Install the systemd unit file, not the init script.
* Mon Apr 22 2013 Ryan O'Hara <rohara@redhat.com> - 1.2.7-5
- Build with PIE flags (#955150)
* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.7-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
* Wed Jan 2 2013 Ryan O'Hara <rohara@redhat.com> - 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 <vpavlin@redhat.com> - 1.2.7-2
- Scriptlets replaced with new systemd macros (#850173).
* Tue Sep 04 2012 Ryan O'Hara <rohara@redhat.com> - 1.2.7-1
- Update to 1.2.7.
- Fix systemd service file (#769726).
* Mon Aug 20 2012 Ryan O'Hara <rohara@redhat.com> - 1.2.6-1
- Update to 1.2.6.
* Tue Aug 14 2012 Ryan O'Hara <rohara@redhat.com> - 1.2.5-2
- Install KEEPALIVED-MIB as KEEPALIVED-MIB.txt.
* Mon Aug 13 2012 Ryan O'Hara <rohara@redhat.com> - 1.2.5-1
- Update to 1.2.5.
* Wed Aug 01 2012 Ryan O'Hara <rohara@redhat.com> - 1.2.4-1
- Update to 1.2.4.
* Mon Jul 23 2012 Ryan O'Hara <rohara@redhat.com> - 1.2.3-1
- Update to 1.2.3.
* Thu Jul 19 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.2-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
* Tue May 08 2012 Ryan O'Hara <rohara@redhat.com> - 1.2.2-5
- Fix IPv4 address comparison (#768119).
* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.2-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
* Mon Sep 19 2011 Tom Callaway <spot@fedoraproject.org> - 1.2.2-3
- convert to systemd
- fix ip_vs.h path searching in configure
* Sat Jul 23 2011 Matthias Saou <http://freshrpms.net/> 1.2.2-2
- Build against libnl for Fedora. RHEL's libnl is too old.
* Sat May 21 2011 Matthias Saou <http://freshrpms.net/> 1.2.2-1
- Update to 1.2.2.
* Mon Feb 07 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.20-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
* Sun Jan 16 2011 Dan Horák <dan[at]danny.cz> 1.1.20-2
- exclude arches where we don't provide 32-bit kernel
* Tue Jan 11 2011 Matthias Saou <http://freshrpms.net/> 1.2.1-1
- Update to 1.2.1, now with IPv6 support.
* Sun May 23 2010 Matthias Saou <http://freshrpms.net/> 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 <http://freshrpms.net/> 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 <http://freshrpms.net/> 1.1.19-2
- Include patch to remove obsolete -k option to modprobe (#528465).
* Wed Oct 21 2009 Matthias Saou <http://freshrpms.net/> 1.1.19-1
- Update to 1.1.19.
* Fri Aug 21 2009 Tomas Mraz <tmraz@redhat.com> - 1.1.17-3
- rebuilt with new openssl
* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.17-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
* Sun Apr 12 2009 Matthias Saou <http://freshrpms.net/> 1.1.17-1
- Update to 1.1.17.
- Update init script all the way.
* Wed Feb 25 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org>
- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
* Sat Jan 17 2009 Tomas Mraz <tmraz@redhat.com> 1.1.15-7
- rebuild with new openssl
* Mon Dec 22 2008 Matthias Saou <http://freshrpms.net/> 1.1.15-6
- Fork the init script to be (mostly for now) LSB compliant (#246966).
* Thu Apr 24 2008 Matthias Saou <http://freshrpms.net/> 1.1.15-5
- Add glob to the kerneldir location, since it contains the arch for F9+.
* Tue Feb 19 2008 Fedora Release Engineering <rel-eng@fedoraproject.org>
- Autorebuild for GCC 4.3
* Wed Dec 05 2007 Release Engineering <rel-eng at fedoraproject dot org>
- Rebuild for deps
* Mon Oct 22 2007 Matthias Saou <http://freshrpms.net/> 1.1.15-2
- Update to latest upstream sources, identical except for the included spec.
* Mon Sep 17 2007 Matthias Saou <http://freshrpms.net/> 1.1.15-1
- Update to 1.1.15.
- Remove merged genhashman and include patches.
* Fri Sep 14 2007 Matthias Saou <http://freshrpms.net/> 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 <http://freshrpms.net/> 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 <http://freshrpms.net/> 1.1.13-8
- Rebuild for new BuildID feature.
* Sun Aug  5 2007 Matthias Saou <http://freshrpms.net/> 1.1.13-7
- Update License field.
* Mon Mar 26 2007 Matthias Saou <http://freshrpms.net/> 1.1.13-6
- Fix doc/samples/sample.misccheck.smbcheck.sh mode (600 -> 644).
* Thu Mar 22 2007 Matthias Saou <http://freshrpms.net/> 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 <http://freshrpms.net/> 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 <http://freshrpms.net/> 1.1.13-3
- Add %%check section to make sure any build without LVS support will fail.
* Mon Feb  5 2007 Matthias Saou <http://freshrpms.net/> 1.1.13-2
- Use our own init script, include a sysconfig entry used by it for options.
* Thu Jan 25 2007 Matthias Saou <http://freshrpms.net/> 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 <dries@ulyssis.org> - 1.1.12-1.2
- Rebuild for Fedora Core 5.
* Sun Mar 12 2006 Dag Wieers <dag@wieers.com> - 1.1.12-1
- Updated to release 1.1.12.
* Fri Mar 04 2005 Dag Wieers <dag@wieers.com> - 1.1.11-1
- Updated to release 1.1.11.
* Wed Feb 23 2005 Dag Wieers <dag@wieers.com> - 1.1.10-2
- Fixed IPVS/LVS support. (Joe Sauer)
* Tue Feb 15 2005 Dag Wieers <dag@wieers.com> - 1.1.10-1
- Updated to release 1.1.10.
* Mon Feb 07 2005 Dag Wieers <dag@wieers.com> - 1.1.9-1
- Updated to release 1.1.9.
* Sun Oct 17 2004 Dag Wieers <dag@wieers.com> - 1.1.7-2
- Fixes to build with kernel IPVS support. (Tim Verhoeven)
* Fri Sep 24 2004 Dag Wieers <dag@wieers.com> - 1.1.7-1
- Updated to release 1.1.7. (Mathieu Lubrano)
* Mon Feb 23 2004 Dag Wieers <dag@wieers.com> - 1.1.6-0
- Updated to release 1.1.6.
* Mon Jan 26 2004 Dag Wieers <dag@wieers.com> - 1.1.5-0
- Updated to release 1.1.5.
* Mon Dec 29 2003 Dag Wieers <dag@wieers.com> - 1.1.4-0
- Updated to release 1.1.4.
* Fri Jun 06 2003 Dag Wieers <dag@wieers.com> - 1.0.3-0
- Initial package. (using DAR)