forked from rpms/glibc
8549c41db6
Resolves: RHEL-2426
329 lines
9.1 KiB
Diff
329 lines
9.1 KiB
Diff
commit 5914a1d55b468ccf0fb6d997a7a4e378339df735
|
|
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
|
Date: Mon Mar 7 15:53:45 2022 +0530
|
|
|
|
gaih_inet: Split nscd lookup code into its own function.
|
|
|
|
Add a new member got_ipv6 to indicate if the results have an IPv6
|
|
result and use it instead of the local got_ipv6.
|
|
|
|
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
|
Reviewed-by: DJ Delorie <dj@redhat.com>
|
|
(cherry picked from commit e7e5315b7fa065a9c8bf525ca9a32f46fa4837e5)
|
|
|
|
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
|
|
index 3870b2dc2edc89cd..7c497a88f8b5b9f8 100644
|
|
--- a/sysdeps/posix/getaddrinfo.c
|
|
+++ b/sysdeps/posix/getaddrinfo.c
|
|
@@ -121,6 +121,7 @@ struct gaih_result
|
|
struct gaih_addrtuple *at;
|
|
char *canon;
|
|
bool free_at;
|
|
+ bool got_ipv6;
|
|
};
|
|
|
|
/* Values for `protoflag'. */
|
|
@@ -316,7 +317,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
|
|
res.canon = canonbuf; \
|
|
} \
|
|
if (_family == AF_INET6 && *pat != NULL) \
|
|
- got_ipv6 = true; \
|
|
+ res.got_ipv6 = true; \
|
|
} \
|
|
}
|
|
|
|
@@ -467,6 +468,128 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
|
|
return 0;
|
|
}
|
|
|
|
+#ifdef USE_NSCD
|
|
+/* Query addresses from nscd cache, returning a non-zero value on error.
|
|
+ RES members have the lookup result; RES->AT is NULL if there were no errors
|
|
+ but also no results. */
|
|
+
|
|
+static int
|
|
+get_nscd_addresses (const char *name, const struct addrinfo *req,
|
|
+ struct gaih_result *res)
|
|
+{
|
|
+ if (__nss_not_use_nscd_hosts > 0
|
|
+ && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
|
|
+ __nss_not_use_nscd_hosts = 0;
|
|
+
|
|
+ res->at = NULL;
|
|
+
|
|
+ if (__nss_not_use_nscd_hosts || __nss_database_custom[NSS_DBSIDX_hosts])
|
|
+ return 0;
|
|
+
|
|
+ /* Try to use nscd. */
|
|
+ struct nscd_ai_result *air = NULL;
|
|
+ int err = __nscd_getai (name, &air, &h_errno);
|
|
+
|
|
+ if (__glibc_unlikely (air == NULL))
|
|
+ {
|
|
+ /* The database contains a negative entry. */
|
|
+ if (err == 0)
|
|
+ return -EAI_NONAME;
|
|
+ if (__nss_not_use_nscd_hosts == 0)
|
|
+ {
|
|
+ if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
|
|
+ return -EAI_MEMORY;
|
|
+ if (h_errno == TRY_AGAIN)
|
|
+ return -EAI_AGAIN;
|
|
+ return -EAI_SYSTEM;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Transform into gaih_addrtuple list. */
|
|
+ int result = 0;
|
|
+ char *addrs = air->addrs;
|
|
+
|
|
+ struct gaih_addrtuple *addrfree = calloc (air->naddrs, sizeof (*addrfree));
|
|
+ struct gaih_addrtuple *at = calloc (air->naddrs, sizeof (*at));
|
|
+ if (at == NULL)
|
|
+ {
|
|
+ result = -EAI_MEMORY;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ res->free_at = true;
|
|
+
|
|
+ int count = 0;
|
|
+ for (int i = 0; i < air->naddrs; ++i)
|
|
+ {
|
|
+ socklen_t size = (air->family[i] == AF_INET
|
|
+ ? INADDRSZ : IN6ADDRSZ);
|
|
+
|
|
+ if (!((air->family[i] == AF_INET
|
|
+ && req->ai_family == AF_INET6
|
|
+ && (req->ai_flags & AI_V4MAPPED) != 0)
|
|
+ || req->ai_family == AF_UNSPEC
|
|
+ || air->family[i] == req->ai_family))
|
|
+ {
|
|
+ /* Skip over non-matching result. */
|
|
+ addrs += size;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (air->family[i] == AF_INET && req->ai_family == AF_INET6
|
|
+ && (req->ai_flags & AI_V4MAPPED))
|
|
+ {
|
|
+ at[count].family = AF_INET6;
|
|
+ at[count].addr[3] = *(uint32_t *) addrs;
|
|
+ at[count].addr[2] = htonl (0xffff);
|
|
+ }
|
|
+ else if (req->ai_family == AF_UNSPEC
|
|
+ || air->family[count] == req->ai_family)
|
|
+ {
|
|
+ at[count].family = air->family[count];
|
|
+ memcpy (at[count].addr, addrs, size);
|
|
+ if (air->family[count] == AF_INET6)
|
|
+ res->got_ipv6 = true;
|
|
+ }
|
|
+ at[count].next = at + count + 1;
|
|
+ count++;
|
|
+ addrs += size;
|
|
+ }
|
|
+
|
|
+ if ((req->ai_flags & AI_CANONNAME) && air->canon != NULL)
|
|
+ {
|
|
+ char *canonbuf = __strdup (air->canon);
|
|
+ if (canonbuf == NULL)
|
|
+ {
|
|
+ result = -EAI_MEMORY;
|
|
+ goto out;
|
|
+ }
|
|
+ res->canon = canonbuf;
|
|
+ }
|
|
+
|
|
+ if (count == 0)
|
|
+ {
|
|
+ result = -EAI_NONAME;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ at[count - 1].next = NULL;
|
|
+
|
|
+ res->at = at;
|
|
+
|
|
+out:
|
|
+ free (air);
|
|
+ if (result != 0)
|
|
+ {
|
|
+ free (at);
|
|
+ res->free_at = false;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+#endif
|
|
+
|
|
/* Convert numeric addresses to binary into RES. On failure, RES->AT is set to
|
|
NULL and an error code is returned. If AI_NUMERIC_HOST is not requested and
|
|
the function cannot determine a result, RES->AT is set to NULL and 0
|
|
@@ -630,7 +753,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
|
|
/ sizeof (struct gaih_typeproto)] = {0};
|
|
|
|
- bool got_ipv6 = false;
|
|
const char *orig_name = name;
|
|
|
|
/* Reserve stack memory for the scratch buffer in the getaddrinfo
|
|
@@ -672,6 +794,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
else if (res.at != NULL)
|
|
goto process_list;
|
|
|
|
+#ifdef USE_NSCD
|
|
+ if ((result = get_nscd_addresses (name, req, &res)) != 0)
|
|
+ goto free_and_return;
|
|
+ else if (res.at != NULL)
|
|
+ goto process_list;
|
|
+#endif
|
|
+
|
|
int no_data = 0;
|
|
int no_inet6_data = 0;
|
|
nss_action_list nip;
|
|
@@ -681,115 +810,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
struct resolv_context *res_ctx = NULL;
|
|
bool do_merge = false;
|
|
|
|
-#ifdef USE_NSCD
|
|
- if (__nss_not_use_nscd_hosts > 0
|
|
- && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
|
|
- __nss_not_use_nscd_hosts = 0;
|
|
-
|
|
- if (!__nss_not_use_nscd_hosts
|
|
- && !__nss_database_custom[NSS_DBSIDX_hosts])
|
|
- {
|
|
- /* Try to use nscd. */
|
|
- struct nscd_ai_result *air = NULL;
|
|
- int err = __nscd_getai (name, &air, &h_errno);
|
|
- if (air != NULL)
|
|
- {
|
|
- /* Transform into gaih_addrtuple list. */
|
|
- bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
|
|
- char *addrs = air->addrs;
|
|
-
|
|
- addrmem = calloc (air->naddrs, sizeof (*addrmem));
|
|
- if (addrmem == NULL)
|
|
- {
|
|
- result = -EAI_MEMORY;
|
|
- goto free_and_return;
|
|
- }
|
|
-
|
|
- struct gaih_addrtuple *addrfree = addrmem;
|
|
- struct gaih_addrtuple **pat = &res.at;
|
|
-
|
|
- for (int i = 0; i < air->naddrs; ++i)
|
|
- {
|
|
- socklen_t size = (air->family[i] == AF_INET
|
|
- ? INADDRSZ : IN6ADDRSZ);
|
|
-
|
|
- if (!((air->family[i] == AF_INET
|
|
- && req->ai_family == AF_INET6
|
|
- && (req->ai_flags & AI_V4MAPPED) != 0)
|
|
- || req->ai_family == AF_UNSPEC
|
|
- || air->family[i] == req->ai_family))
|
|
- {
|
|
- /* Skip over non-matching result. */
|
|
- addrs += size;
|
|
- continue;
|
|
- }
|
|
-
|
|
- if (*pat == NULL)
|
|
- {
|
|
- *pat = addrfree++;
|
|
- (*pat)->scopeid = 0;
|
|
- }
|
|
- uint32_t *pataddr = (*pat)->addr;
|
|
- (*pat)->next = NULL;
|
|
- if (added_canon || air->canon == NULL)
|
|
- (*pat)->name = NULL;
|
|
- else if (res.canon == NULL)
|
|
- {
|
|
- char *canonbuf = __strdup (air->canon);
|
|
- if (canonbuf == NULL)
|
|
- {
|
|
- result = -EAI_MEMORY;
|
|
- goto free_and_return;
|
|
- }
|
|
- res.canon = (*pat)->name = canonbuf;
|
|
- }
|
|
-
|
|
- if (air->family[i] == AF_INET
|
|
- && req->ai_family == AF_INET6
|
|
- && (req->ai_flags & AI_V4MAPPED))
|
|
- {
|
|
- (*pat)->family = AF_INET6;
|
|
- pataddr[3] = *(uint32_t *) addrs;
|
|
- pataddr[2] = htonl (0xffff);
|
|
- pataddr[1] = 0;
|
|
- pataddr[0] = 0;
|
|
- pat = &((*pat)->next);
|
|
- added_canon = true;
|
|
- }
|
|
- else if (req->ai_family == AF_UNSPEC
|
|
- || air->family[i] == req->ai_family)
|
|
- {
|
|
- (*pat)->family = air->family[i];
|
|
- memcpy (pataddr, addrs, size);
|
|
- pat = &((*pat)->next);
|
|
- added_canon = true;
|
|
- if (air->family[i] == AF_INET6)
|
|
- got_ipv6 = true;
|
|
- }
|
|
- addrs += size;
|
|
- }
|
|
-
|
|
- free (air);
|
|
-
|
|
- goto process_list;
|
|
- }
|
|
- else if (err == 0)
|
|
- /* The database contains a negative entry. */
|
|
- goto free_and_return;
|
|
- else if (__nss_not_use_nscd_hosts == 0)
|
|
- {
|
|
- if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
|
|
- result = -EAI_MEMORY;
|
|
- else if (h_errno == TRY_AGAIN)
|
|
- result = -EAI_AGAIN;
|
|
- else
|
|
- result = -EAI_SYSTEM;
|
|
-
|
|
- goto free_and_return;
|
|
- }
|
|
- }
|
|
-#endif
|
|
-
|
|
no_more = !__nss_database_get (nss_database_hosts, &nip);
|
|
|
|
/* If we are looking for both IPv4 and IPv6 address we don't
|
|
@@ -897,7 +917,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
|
|
no_data = 0;
|
|
if (req->ai_family == AF_INET6)
|
|
- got_ipv6 = true;
|
|
+ res.got_ipv6 = true;
|
|
}
|
|
else
|
|
*pat = ((*pat)->next);
|
|
@@ -940,7 +960,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
&& (req->ai_flags & AI_V4MAPPED)
|
|
/* Avoid generating the mapped addresses if we
|
|
know we are not going to need them. */
|
|
- && ((req->ai_flags & AI_ALL) || !got_ipv6)))
|
|
+ && ((req->ai_flags & AI_ALL) || !res.got_ipv6)))
|
|
{
|
|
gethosts (AF_INET);
|
|
|
|
@@ -1091,7 +1111,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
|
|
/* If we looked up IPv4 mapped address discard them here if
|
|
the caller isn't interested in all address and we have
|
|
found at least one IPv6 address. */
|
|
- if (got_ipv6
|
|
+ if (res.got_ipv6
|
|
&& (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
|
|
&& IN6_IS_ADDR_V4MAPPED (at2->addr))
|
|
goto ignore;
|