Blob Blame History Raw
From 2ab4d4188670356dcb82a80f2fc4598f5145c77d Mon Sep 17 00:00:00 2001
From: Jan Friesse <jfriesse@redhat.com>
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 <jfriesse@redhat.com>
Reviewed-by: Fabio M. Di Nitto <fdinitto@redhat.com>
---
 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