You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
328 lines
9.1 KiB
328 lines
9.1 KiB
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;
|
|
|