From 2ab4d4188670356dcb82a80f2fc4598f5145c77d Mon Sep 17 00:00:00 2001 From: Jan Friesse Date: Thu, 10 Jan 2019 15:06:20 +0100 Subject: [PATCH] totemip: Use AF_UNSPEC for ipv4-6 and ipv6-4 AF_UNSPEC returns different results than AF_INET/AF_INET6, because of nsswitch.conf search is in order and it stops asking other modules once current module success. Example of difference between previous and new code when ipv6-4 is used: - /etc/hosts contains test_name with an ipv4 - previous code called AF_INET6 where /etc/hosts failed so other methods were used which may return IPv6 addr -> result was ether fail or IPv6 address. - new code calls AF_UNSPEC returning IPv4 defined in /etc/hosts -> result is IPv4 address New code behavior should solve problems caused by nss-myhostname. Signed-off-by: Jan Friesse Reviewed-by: Fabio M. Di Nitto --- exec/totemip.c | 106 +++++++++++++++++++++++++++----------- include/corosync/totem/totemip.h | 6 +- man/corosync.conf.5 | 8 ++- 3 files changed, 83 insertions(+), 37 deletions(-) diff --git a/exec/totemip.c b/exec/totemip.c index 9d96e1b..36d0a72 100644 --- a/exec/totemip.c +++ b/exec/totemip.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2011 Red Hat, Inc. + * Copyright (c) 2005-2019 Red Hat, Inc. * * All rights reserved. * @@ -288,69 +288,113 @@ int totemip_parse(struct totem_ip_address *totemip, const char *addr, enum totem_ip_version_enum ip_version) { struct addrinfo *ainfo; + struct addrinfo *ainfo_iter; + struct addrinfo *ainfo_ipv4; + struct addrinfo *ainfo_ipv6; + struct addrinfo *ainfo_final; struct addrinfo ahints; struct sockaddr_in *sa; struct sockaddr_in6 *sa6; int ret; int debug_ip_family; - int ai_family1, ai_family2; + int ai_family; memset(&ahints, 0, sizeof(ahints)); ahints.ai_socktype = SOCK_DGRAM; ahints.ai_protocol = IPPROTO_UDP; - ai_family1 = ai_family2 = -1; + ai_family = AF_UNSPEC; + debug_ip_family = 0; switch (ip_version) { case TOTEM_IP_VERSION_4: - ai_family1 = AF_INET; + ai_family = AF_INET; + debug_ip_family = 4; break; case TOTEM_IP_VERSION_6: - ai_family1 = AF_INET6; - break; - case TOTEM_IP_VERSION_4_6: - ai_family1 = AF_INET; - ai_family2 = AF_INET6; + ai_family = AF_INET6; + debug_ip_family = 6; break; case TOTEM_IP_VERSION_6_4: - ai_family1 = AF_INET6; - ai_family2 = AF_INET; + case TOTEM_IP_VERSION_4_6: + /* + * ai_family and debug_ip_family are already set correctly + */ break; } - ahints.ai_family = ai_family1; + ahints.ai_family = ai_family; + ret = getaddrinfo(addr, NULL, &ahints, &ainfo); - if (ret && ai_family2 != -1) { - ahints.ai_family = ai_family2; - ret = getaddrinfo(addr, NULL, &ahints, &ainfo); - } - debug_ip_family = 4; - if (ahints.ai_family == AF_INET6) { - debug_ip_family = 6; - } + if (ret == 0 && ai_family == AF_UNSPEC) { + ainfo_ipv4 = ainfo_ipv6 = NULL; - if (ret) { - log_printf (LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s not resolvable", - debug_ip_family, addr); + /* + * Walk thru results and store first AF_INET and AF_INET6 + */ + for (ainfo_iter = ainfo; ainfo_iter != NULL; ainfo_iter = ainfo_iter->ai_next) { + if (ainfo_iter->ai_family == AF_INET && ainfo_ipv4 == NULL) { + ainfo_ipv4 = ainfo_iter; + } - return -1; + if (ainfo_iter->ai_family == AF_INET6 && ainfo_ipv6 == NULL) { + ainfo_ipv6 = ainfo_iter; + } + } + + if (ip_version == TOTEM_IP_VERSION_6_4) { + if (ainfo_ipv6 != NULL) { + ainfo_final = ainfo_ipv6; + } else { + ainfo_final = ainfo_ipv4; + } + } else { + if (ainfo_ipv4 != NULL) { + ainfo_final = ainfo_ipv4; + } else { + ainfo_final = ainfo_ipv6; + } + } + } else if (ret == 0) { + ainfo_final = ainfo; + } else { + ainfo_final = NULL; } - sa = (struct sockaddr_in *)ainfo->ai_addr; - sa6 = (struct sockaddr_in6 *)ainfo->ai_addr; - totemip->family = ainfo->ai_family; + if (ainfo_final == NULL) { + if (ret == 0) { + freeaddrinfo(ainfo); + } + + if (debug_ip_family == 0) { + log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IP address of %s not resolvable", + addr); + } else { + log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s not resolvable", + debug_ip_family, addr); + } + + return (-1); + } - if (ainfo->ai_family == AF_INET) + totemip->family = ainfo_final->ai_family; + if (ainfo_final->ai_family == AF_INET) { + sa = (struct sockaddr_in *)ainfo_final->ai_addr; memcpy(totemip->addr, &sa->sin_addr, sizeof(struct in_addr)); - else + debug_ip_family = 4; + } else { + sa6 = (struct sockaddr_in6 *)ainfo_final->ai_addr; memcpy(totemip->addr, &sa6->sin6_addr, sizeof(struct in6_addr)); + debug_ip_family = 6; + } - log_printf (LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s resolved as %s", + log_printf(LOGSYS_LEVEL_DEBUG, "totemip_parse: IPv%u address of %s resolved as %s", debug_ip_family, addr, totemip_print(totemip)); freeaddrinfo(ainfo); - return 0; + + return (0); } /* Make a sockaddr_* into a totem_ip_address */ diff --git a/include/corosync/totem/totemip.h b/include/corosync/totem/totemip.h index de22461..b8da3c9 100644 --- a/include/corosync/totem/totemip.h +++ b/include/corosync/totem/totemip.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2010 Red Hat, Inc. + * Copyright (c) 2005-2019 Red Hat, Inc. * * All rights reserved. * @@ -70,8 +70,8 @@ struct totem_ip_address enum totem_ip_version_enum { TOTEM_IP_VERSION_4, /* Use only AF_INET */ TOTEM_IP_VERSION_6, /* Use only AF_INET6 */ - TOTEM_IP_VERSION_4_6, /* Use AF_INET and if it fails, use AF_INET6 */ - TOTEM_IP_VERSION_6_4 /* Use AF_INET6 and if it fails, use AF_INET */ + TOTEM_IP_VERSION_4_6, /* Use AF_UNSPEC and filter result preferring AF_INET */ + TOTEM_IP_VERSION_6_4 /* Use AF_UNSPEC and filter result preferring AF_INET6 */ }; struct totem_ip_if_address diff --git a/man/corosync.conf.5 b/man/corosync.conf.5 index 790f434..0e752bc 100644 --- a/man/corosync.conf.5 +++ b/man/corosync.conf.5 @@ -32,7 +32,7 @@ .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ -.TH COROSYNC_CONF 5 2018-12-14 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual" +.TH COROSYNC_CONF 5 2019-01-10 "corosync Man Page" "Corosync Cluster Engine Programmer's Manual" .SH NAME corosync.conf - corosync executive configuration file @@ -314,9 +314,11 @@ The value can be one of (check only IPv6 address) , .B ipv4-6 -(first check IPv4 address, if that fails then look for an IPv6 address) and +(look for all address families and use first IPv4 address found in the list if there is such address, +otherwise use first IPv6 address) and .B ipv6-4 -(first check IPv6 address, if that fails then look for an IPv4 address). +(look for all address families and use first IPv6 address found in the list if there is such address, +otherwise use first IPv4 address). Default (if unspecified) is ipv6-4 for knet and udpu transports and ipv4 for udp. -- 1.7.1