From 305dad8388ea27b4d1bf1202e90ad6947ae0ab26 Mon Sep 17 00:00:00 2001 From: Pavan Balaji Date: Thu, 21 Jan 2016 17:01:42 -0600 Subject: [PATCH] hydra: improve localhost detection. Be more forgiving for systems that do not resolve "localhost" or equivalent names very well (e.g., they are not added to /etc/hosts). Try them out, and if nothing works, fallback to "is not local" mode. Thanks to Orion Poplawski for the suggestion. --- src/pm/hydra/utils/sock/sock.c | 89 +++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/src/pm/hydra/utils/sock/sock.c b/src/pm/hydra/utils/sock/sock.c index 86b25077aac2..dc56c767f544 100644 --- a/src/pm/hydra/utils/sock/sock.c +++ b/src/pm/hydra/utils/sock/sock.c @@ -492,7 +492,7 @@ HYD_status HYDU_sock_get_iface_ip(char *iface, char **ip) HYD_status HYDU_sock_is_local(char *host, int *is_local) { struct hostent *ht; - char *host_ip = NULL, *local_ip = NULL, *lhost_ip = NULL; + char *host_ip = NULL, *lhost_ip = NULL; char lhost[MAX_HOSTNAME_LEN]; struct sockaddr_in sa; struct ifaddrs *ifaddr, *ifa; @@ -516,54 +516,63 @@ HYD_status HYDU_sock_is_local(char *host, int *is_local) /* STEP 1: If "host" matches the local host name, return */ if (gethostname(lhost, MAX_HOSTNAME_LEN) < 0) { - HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "gethostname returned an error\n"); + /* We can't figure out what my localhost name is. *sigh*. We + * could return an error here, but we will just punt it to the + * upper layer saying that we don't know if it is local. We + * cannot try steps 2 and 3 either, since we don't have our + * local hostname. */ + goto fn_exit; } else if (!strcmp(lhost, host)) { *is_local = 1; goto fn_exit; } + else { + /* we have our local hostname, but that does not match the + * provided hostname. Let's try to get our remote IP address + * first. If we can't get that, we can give up. */ + /* If we are unable to resolve the remote host name, it need + * not be an error. It could mean that the user is using an + * alias for the hostname (e.g., an ssh config alias) */ + if ((ht = gethostbyname(host)) == NULL) + goto fn_exit; + memset((char *) &sa, 0, sizeof(struct sockaddr_in)); + memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length); - /* STEP 2: If the IP address associated with "host" and the IP address local - * host resolves to match, return */ - - if ((ht = gethostbyname(lhost)) == NULL) { - HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "gethostbyname error on %s: %s\n", - lhost, hstrerror(h_errno)); + /* Find the IP address of the host */ + host_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf, + MAX_HOSTNAME_LEN)); + HYDU_ASSERT(host_ip, status); } - memset((char *) &sa, 0, sizeof(struct sockaddr_in)); - memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length); - - /* Find the IP address of the host */ - lhost_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf, - MAX_HOSTNAME_LEN)); - HYDU_ASSERT(lhost_ip, status); + /* OK, if we are here, we got the remote IP. We have two ways of + * getting the local IP: gethostbyname or getifaddrs. We'll try + * both. */ - /* If we are unable to resolve the remote host name, it need not be an - * error. It could mean that the user is using an alias for the hostname - * (e.g., an ssh config alias) */ - if ((ht = gethostbyname(host)) == NULL) - goto fn_exit; + /* STEP 2: Let's try the gethostbyname model */ - memset((char *) &sa, 0, sizeof(struct sockaddr_in)); - memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length); + if ((ht = gethostbyname(lhost))) { + memset((char *) &sa, 0, sizeof(struct sockaddr_in)); + memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length); - /* Find the IP address of the host */ - host_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf, - MAX_HOSTNAME_LEN)); - HYDU_ASSERT(host_ip, status); + /* Find the IP address of the host */ + lhost_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf, + MAX_HOSTNAME_LEN)); + HYDU_ASSERT(lhost_ip, status); - /* See if the IP address of the hostname we got matches the IP address - * to which the local host resolves */ - if (!strcmp(lhost_ip, host_ip)) { - *is_local = 1; - goto fn_exit; + /* See if the IP address of the hostname we got matches the IP + * address to which the local host resolves */ + if (!strcmp(lhost_ip, host_ip)) { + *is_local = 1; + goto fn_exit; + } } + /* Either gethostbyname didn't resolve or we didn't find a match. + * Either way, let's try the getifaddr model. */ - /* STEP 3: Find all local IP addresses and try to match the host IP - * with it. */ + /* STEP 3: Let's try the getifaddr model */ if (getifaddrs(&ifaddr) == -1) HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "getifaddrs failed\n"); @@ -573,21 +582,21 @@ HYD_status HYDU_sock_is_local(char *host, int *is_local) if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *sa_ptr = (struct sockaddr_in *) ifa->ifa_addr; - local_ip = HYDU_strdup((char *) + lhost_ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &(sa_ptr->sin_addr), buf, MAX_HOSTNAME_LEN)); - HYDU_ASSERT(local_ip, status); + HYDU_ASSERT(lhost_ip, status); - /* STEP 3: For each local IP address, see if it matches the "host" + /* For each local IP address, see if it matches the "host" * IP address */ - if (!strcmp(host_ip, local_ip)) { + if (!strcmp(host_ip, lhost_ip)) { *is_local = 1; freeifaddrs(ifaddr); goto fn_exit; } - HYDU_FREE(local_ip); - local_ip = NULL; + HYDU_FREE(lhost_ip); + lhost_ip = NULL; } } @@ -596,8 +605,6 @@ HYD_status HYDU_sock_is_local(char *host, int *is_local) fn_exit: if (host_ip) HYDU_FREE(host_ip); - if (local_ip) - HYDU_FREE(local_ip); if (lhost_ip) HYDU_FREE(lhost_ip); return status; -- 1.9.1