From ef63de224b0a1b63213a4e13754013541ea66e20 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 24 Nov 2024 14:28:25 +0000 Subject: [PATCH 1/4] vrrp: Don't segfault if open_sockpool_socket() fails to open sockets If a unicast VRRP instance is configured and the unicast_src_ip does not exist on the system, then the bind() fails and the sockets are not opened. This commit ensures that in that case vrrp->sockets is not dereferenced. This is not a real fix to the problem. We need to track the addition and removal of unicast_src_ip addresses, and enter fault state if the address in not configured, or when it is removed. Signed-off-by: Quentin Armitage --- keepalived/vrrp/vrrp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c index 4b06e387ac..f460c5edb6 100644 --- a/keepalived/vrrp/vrrp.c +++ b/keepalived/vrrp/vrrp.c @@ -1536,6 +1536,9 @@ vrrp_send_adv(vrrp_t * vrrp, uint8_t prio) { unicast_peer_t *peer; + if (!vrrp->sockets) + return; + #ifdef _HAVE_VRRP_VMAC_ if (vrrp->saddr.ss_family == AF_UNSPEC && vrrp->family == AF_INET6 && From 0400738d9f50341dfe5c3af0dfd1ef88c94e8973 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 24 Nov 2024 14:33:14 +0000 Subject: [PATCH 2/4] vrrp: don't allow unicast instance without interface to have a VMAC If the interface is not configured, we can't know what interface to add the VMAC to. Signed-off-by: Quentin Armitage --- keepalived/vrrp/vrrp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c index f460c5edb6..6ab76b5142 100644 --- a/keepalived/vrrp/vrrp.c +++ b/keepalived/vrrp/vrrp.c @@ -2394,9 +2394,15 @@ chk_min_cfg(vrrp_t *vrrp) report_config_error(CONFIG_GENERAL_ERROR, "(%s) the virtual router id must be set", vrrp->iname); return false; } - if (!vrrp->ifp && !__test_bit(VRRP_FLAG_UNICAST_CONFIGURED, &vrrp->flags)) { - report_config_error(CONFIG_GENERAL_ERROR, "(%s) Unknown interface!", vrrp->iname); - return false; + if (!vrrp->ifp) { + if (!__test_bit(VRRP_FLAG_UNICAST_CONFIGURED, &vrrp->flags)) { + report_config_error(CONFIG_GENERAL_ERROR, "(%s) Unknown interface!", vrrp->iname); + return false; + } + if (__test_bit(VRRP_VMAC_BIT, &vrrp->flags)) { + report_config_error(CONFIG_GENERAL_ERROR, "(%s) cannot use VMAC if no interface specified", vrrp->iname); + return false; + } } return true; From 6b3c80f3bd0c09215b9aa04de9c52ae471cd11b8 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Sun, 24 Nov 2024 14:40:43 +0000 Subject: [PATCH 3/4] vrrp: test for _HAVE_VRRP_VMAC_ before using VRRP_VMAC_BIT Commit 0400738 - "vrrp: don't allow unicast instance without interface to have a VMAC" caused keepalived to fail to compile if VMACs were not enabled. --- keepalived/vrrp/vrrp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c index 6ab76b5142..89fa6176e8 100644 --- a/keepalived/vrrp/vrrp.c +++ b/keepalived/vrrp/vrrp.c @@ -2399,10 +2399,12 @@ chk_min_cfg(vrrp_t *vrrp) report_config_error(CONFIG_GENERAL_ERROR, "(%s) Unknown interface!", vrrp->iname); return false; } +#ifdef _HAVE_VRRP_VMAC_ if (__test_bit(VRRP_VMAC_BIT, &vrrp->flags)) { report_config_error(CONFIG_GENERAL_ERROR, "(%s) cannot use VMAC if no interface specified", vrrp->iname); return false; } +#endif } return true; From b48f005a88a5002c7dd1bcb40b4e22a74f409a1d Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Mon, 9 Dec 2024 11:35:28 +0000 Subject: [PATCH 4/4] vrrp: Add setting IP_FREEBIND/IPV6_FREEBIND socket option This allows creating and configuring unicast sockets before the configured source address is added to the system. Signed-off-by: Quentin Armitage --- configure.ac | 9 +++++++++ keepalived/vrrp/vrrp.c | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/configure.ac b/configure.ac index 464cb95596..142c744070 100644 --- a/configure.ac +++ b/configure.ac @@ -1419,6 +1419,15 @@ AC_CHECK_DECLS([ETHERTYPE_IPV6], [], ], [[#include ]]) +# IPV6_FREEBIND - added Linux v4.15 +AS_IF([test .$enable_vrrp != .no], + [ + AC_CHECK_DECLS([IPV6_FREEBIND], + [add_system_opt([IPV6_FREEBIND])], + [], + [[#include ]]) + ]) + # IPV6_MULTICAST_ALL - added Linux v4.20 AC_CHECK_DECLS([IPV6_MULTICAST_ALL], [ diff --git a/keepalived/vrrp/vrrp.c b/keepalived/vrrp/vrrp.c index 89fa6176e8..e87b6ff881 100644 --- a/keepalived/vrrp/vrrp.c +++ b/keepalived/vrrp/vrrp.c @@ -2536,6 +2536,16 @@ open_vrrp_read_socket(sa_family_t family, int proto, const interface_t *ifp, } #endif + /* Allow binding even if the address doesn't exist yet */ +#if !HAVE_DECL_IPV6_FREEBIND + if (family == AF_INET6) { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, &on, sizeof on)) + log_message(LOG_INFO, "IPV6_TRANSPARENT failed %d - %m", errno); + } else +#endif + if (setsockopt(fd, family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6, family == AF_INET ? IP_FREEBIND : IPV6_FREEBIND, &on, sizeof on)) + log_message(LOG_INFO, "IP%s_FREEBIND failed %d - %m", family == AF_INET ? "" : "V6", errno); + /* Bind to the local unicast address */ if (bind(fd, PTR_CAST_CONST(struct sockaddr, unicast_src), unicast_src->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) { log_message(LOG_INFO, "bind unicast_src %s failed %d - %m", inet_sockaddrtos(unicast_src), errno);