From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2206) id 5DA323858408; Tue, 1 Mar 2022 02:41:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5DA323858408 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Siddhesh Poyarekar To: glibc-cvs@sourceware.org Subject: [glibc/siddhesh/gai-cleanup2] gaih_inet: separate nss lookup loop into its own function X-Act-Checkin: glibc X-Git-Author: Siddhesh Poyarekar X-Git-Refname: refs/heads/siddhesh/gai-cleanup2 X-Git-Oldrev: 84fc40f6b2dea9e0b455675ea9123d03699830ef X-Git-Newrev: 98f728a01610bb31622c2ccff18795853dd849d1 Message-Id: <20220301024112.5DA323858408@sourceware.org> Date: Tue, 1 Mar 2022 02:41:12 +0000 (GMT) X-BeenThere: glibc-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Glibc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 01 Mar 2022 02:41:12 -0000 https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=98f728a01610bb31622c2ccff18795853dd849d1 commit 98f728a01610bb31622c2ccff18795853dd849d1 Author: Siddhesh Poyarekar Date: Mon Feb 28 20:20:41 2022 +0530 gaih_inet: separate nss lookup loop into its own function Signed-off-by: Siddhesh Poyarekar Diff: --- sysdeps/posix/getaddrinfo.c | 529 +++++++++++++++++++++++--------------------- 1 file changed, 274 insertions(+), 255 deletions(-) diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index ea3fa76748..59109d0a35 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -297,7 +297,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, break; \ if (!scratch_buffer_grow (tmpbuf)) \ { \ - __resolv_context_put (res_ctx); \ result = -EAI_MEMORY; \ goto free_and_return; \ } \ @@ -307,7 +306,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, { \ if (h_errno == NETDB_INTERNAL) \ { \ - __resolv_context_put (res_ctx); \ result = -EAI_SYSTEM; \ goto free_and_return; \ } \ @@ -321,11 +319,10 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, struct gaih_addrtuple *addrmem = NULL; \ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \ { \ - __resolv_context_put (res_ctx); \ result = -EAI_SYSTEM; \ goto free_and_return; \ } \ - if (addrmem && !gaih_lookup_result_push_alloc (&res, addrmem)) \ + if (addrmem && !gaih_lookup_result_push_alloc (res, addrmem)) \ { \ free (addrmem); \ result = -EAI_MEMORY; \ @@ -339,14 +336,13 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, char *canonbuf = __strdup (localcanon); \ if (canonbuf == NULL) \ { \ - __resolv_context_put (res_ctx); \ result = -EAI_SYSTEM; \ goto free_and_return; \ } \ canon = canonbuf; \ } \ if (_family == AF_INET6 && addrmem != NULL) \ - got_ipv6 = true; \ + res->got_ipv6 = true; \ } \ } @@ -768,6 +764,271 @@ simple_gethostbyname (const char *name, const struct addrinfo *req, return -EAI_NODATA; } +static int +get_nss_addresses (const char *name, const struct addrinfo *req, + struct scratch_buffer *tmpbuf, + struct gaih_lookup_result *res) +{ + struct gaih_addrtuple *at = NULL; + + /* Use PAT to track the end of the tuple list so that multiple lookups append + to the end of the latest list. */ + struct gaih_addrtuple **pat = &at; + int no_data = 0; + int no_inet6_data = 0; + nss_action_list nip; + enum nss_status inet6_status = NSS_STATUS_UNAVAIL; + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; + struct resolv_context *res_ctx = NULL; + char *canon = NULL; + int result = 0; + + res->at = NULL; + + no_more = !__nss_database_get (nss_database_hosts, &nip); + + /* If we are looking for both IPv4 and IPv6 address we don't + want the lookup functions to automatically promote IPv4 + addresses to IPv6 addresses, so we use the no_inet6 + function variant. */ + res_ctx = __resolv_context_get (); + if (res_ctx == NULL) + no_more = 1; + + while (!no_more) + { + no_data = 0; + nss_gethostbyname4_r *fct4 = NULL; + + /* gethostbyname4_r sends out parallel A and AAAA queries and + is thus only suitable for PF_UNSPEC. */ + if (req->ai_family == PF_UNSPEC) + fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); + + if (fct4 != NULL) + { + size_t length = 1024; + char *buf = malloc (length); + + while (1) + { + *pat = NULL; + status = DL_CALL_FCT (fct4, (name, pat, buf, length, &errno, + &h_errno, NULL)); + if (status == NSS_STATUS_SUCCESS) + break; + if (status != NSS_STATUS_TRYAGAIN + || errno != ERANGE || h_errno != NETDB_INTERNAL) + { + if (h_errno == TRY_AGAIN) + no_data = EAI_AGAIN; + else + no_data = h_errno == NO_DATA; + break; + } + + length *= 2; + free (buf); + if ((buf = malloc (length)) == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } + } + + if (!gaih_lookup_result_push_alloc (res, buf)) + { + free (buf); + result = -EAI_MEMORY; + goto free_and_return; + } + + if (status == NSS_STATUS_SUCCESS) + { + assert (!no_data); + no_data = 1; + + if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) + { + char *canonbuf = __strdup ((*pat)->name); + if (canonbuf == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } + canon = canonbuf; + } + + while (*pat != NULL) + { + if ((*pat)->family == AF_INET && req->ai_family == AF_INET6 + && (req->ai_flags & AI_V4MAPPED) != 0) + { + uint32_t *pataddr = (*pat)->addr; + (*pat)->family = AF_INET6; + pataddr[3] = pataddr[0]; + pataddr[2] = htonl (0xffff); + pataddr[1] = 0; + pataddr[0] = 0; + pat = &((*pat)->next); + no_data = 0; + } + else if (req->ai_family == AF_UNSPEC + || (*pat)->family == req->ai_family) + { + pat = &((*pat)->next); + + no_data = 0; + if (req->ai_family == AF_INET6) + res->got_ipv6 = true; + } + else + *pat = ((*pat)->next); + } + } + + no_inet6_data = no_data; + } + else + { + nss_gethostbyname3_r *fct = NULL; + if (req->ai_flags & AI_CANONNAME) + /* No need to use this function if we do not look for + the canonical name. The function does not exist in + all NSS modules and therefore the lookup would + often fail. */ + fct = __nss_lookup_function (nip, "gethostbyname3_r"); + if (fct == NULL) + /* We are cheating here. The gethostbyname2_r + function does not have the same interface as + gethostbyname3_r but the extra arguments the + latter takes are added at the end. So the + gethostbyname2_r code will just ignore them. */ + fct = __nss_lookup_function (nip, "gethostbyname2_r"); + + if (fct != NULL) + { + if (req->ai_family == AF_INET6 || req->ai_family == AF_UNSPEC) + { + gethosts (AF_INET6); + no_inet6_data = no_data; + inet6_status = status; + } + if (req->ai_family == AF_INET || req->ai_family == AF_UNSPEC + || (req->ai_family == AF_INET6 + && (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) || !res->got_ipv6))) + { + gethosts (AF_INET); + + if (req->ai_family == AF_INET) + { + no_inet6_data = no_data; + inet6_status = status; + } + } + + /* If we found one address for AF_INET or AF_INET6, + don't continue the search. */ + if (inet6_status == NSS_STATUS_SUCCESS + || status == NSS_STATUS_SUCCESS) + { + if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) + { + char *canonbuf = getcanonname (nip, at, name); + if (canonbuf == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } + canon = canonbuf; + } + status = NSS_STATUS_SUCCESS; + } + else + { + /* We can have different states for AF_INET and + AF_INET6. Try to find a useful one for both. */ + if (inet6_status == NSS_STATUS_TRYAGAIN) + status = NSS_STATUS_TRYAGAIN; + else if (status == NSS_STATUS_UNAVAIL + && inet6_status != NSS_STATUS_UNAVAIL) + status = inet6_status; + } + } + else + { + /* Could not locate any of the lookup functions. + The NSS lookup code does not consistently set + errno, so we need to supply our own error + code here. The root cause could either be a + resource allocation failure, or a missing + service function in the DSO (so it should not + be listed in /etc/nsswitch.conf). Assume the + former, and return EBUSY. */ + status = NSS_STATUS_UNAVAIL; + __set_h_errno (NETDB_INTERNAL); + __set_errno (EBUSY); + } + } + + if (nss_next_action (nip, status) == NSS_ACTION_RETURN) + break; + + /* Discard all previous results on CONTINUE. Allocations will get + freed at the end of gaih_cleanup, so only adjust PAT and free + CANONBUF if it was allocated. */ + if (nss_next_action (nip, status) == NSS_ACTION_CONTINUE) + { + at = NULL; + pat = &at; + free (canon); + canon = NULL; + } + + nip++; + if (nip->module == NULL) + no_more = -1; + } + + /* If we have a failure which sets errno, report it using + EAI_SYSTEM. */ + if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) + && h_errno == NETDB_INTERNAL) + { + result = -EAI_SYSTEM; + goto free_and_return; + } + + if (no_data != 0 && no_inet6_data != 0) + { + /* If both requests timed out report this. */ + if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) + result = -EAI_AGAIN; + else + /* We made requests but they turned out no data. The name + is known, though. */ + result = -EAI_NODATA; + } + +free_and_return: + __resolv_context_put (res_ctx); + + if (result != 0) + at = NULL; + + if (at == NULL) + free (canon); + else + at->name = canon; + + res->at = at; + return result; +} + static int process_canonname (const struct addrinfo *req, const char *orig_name, char **canonp) @@ -876,259 +1137,17 @@ gaih_inet (const char *name, const struct gaih_service *service, } #endif - /* For NSS lookups, use PAT to track the end of the tuple list so that - multiple lookups append to the end of the latest list. */ - struct gaih_addrtuple **pat = &at; - int no_data = 0; - int no_inet6_data = 0; - nss_action_list nip; - enum nss_status inet6_status = NSS_STATUS_UNAVAIL; - enum nss_status status = NSS_STATUS_UNAVAIL; - int no_more; - struct resolv_context *res_ctx = NULL; - - no_more = !__nss_database_get (nss_database_hosts, &nip); - - /* If we are looking for both IPv4 and IPv6 address we don't - want the lookup functions to automatically promote IPv4 - addresses to IPv6 addresses, so we use the no_inet6 - function variant. */ - res_ctx = __resolv_context_get (); - if (res_ctx == NULL) - no_more = 1; - - while (!no_more) - { - no_data = 0; - nss_gethostbyname4_r *fct4 = NULL; - - /* gethostbyname4_r sends out parallel A and AAAA queries and - is thus only suitable for PF_UNSPEC. */ - if (req->ai_family == PF_UNSPEC) - fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); - - if (fct4 != NULL) - { - size_t length = 1024; - char *buf = malloc (length); - - while (1) - { - *pat = NULL; - status = DL_CALL_FCT (fct4, (name, pat, - buf, length, - &errno, &h_errno, - NULL)); - if (status == NSS_STATUS_SUCCESS) - break; - if (status != NSS_STATUS_TRYAGAIN - || errno != ERANGE || h_errno != NETDB_INTERNAL) - { - if (h_errno == TRY_AGAIN) - no_data = EAI_AGAIN; - else - no_data = h_errno == NO_DATA; - break; - } - - length *= 2; - free (buf); - if ((buf = malloc (length)) == NULL) - { - __resolv_context_put (res_ctx); - result = -EAI_MEMORY; - goto free_and_return; - } - } - - if (!gaih_lookup_result_push_alloc (&res, buf)) - { - result = -EAI_MEMORY; - goto free_and_return; - } - - if (status == NSS_STATUS_SUCCESS) - { - assert (!no_data); - no_data = 1; - - if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) - { - char *canonbuf = __strdup ((*pat)->name); - if (canonbuf == NULL) - { - __resolv_context_put (res_ctx); - result = -EAI_MEMORY; - goto free_and_return; - } - canon = canonbuf; - } - - while (*pat != NULL) - { - if ((*pat)->family == AF_INET - && req->ai_family == AF_INET6 - && (req->ai_flags & AI_V4MAPPED) != 0) - { - uint32_t *pataddr = (*pat)->addr; - (*pat)->family = AF_INET6; - pataddr[3] = pataddr[0]; - pataddr[2] = htonl (0xffff); - pataddr[1] = 0; - pataddr[0] = 0; - pat = &((*pat)->next); - no_data = 0; - } - else if (req->ai_family == AF_UNSPEC - || (*pat)->family == req->ai_family) - { - pat = &((*pat)->next); - - no_data = 0; - if (req->ai_family == AF_INET6) - got_ipv6 = true; - } - else - *pat = ((*pat)->next); - } - } - - no_inet6_data = no_data; - } - else - { - nss_gethostbyname3_r *fct = NULL; - if (req->ai_flags & AI_CANONNAME) - /* No need to use this function if we do not look for - the canonical name. The function does not exist in - all NSS modules and therefore the lookup would - often fail. */ - fct = __nss_lookup_function (nip, "gethostbyname3_r"); - if (fct == NULL) - /* We are cheating here. The gethostbyname2_r - function does not have the same interface as - gethostbyname3_r but the extra arguments the - latter takes are added at the end. So the - gethostbyname2_r code will just ignore them. */ - fct = __nss_lookup_function (nip, "gethostbyname2_r"); - - if (fct != NULL) - { - if (req->ai_family == AF_INET6 - || req->ai_family == AF_UNSPEC) - { - gethosts (AF_INET6); - no_inet6_data = no_data; - inet6_status = status; - } - if (req->ai_family == AF_INET - || req->ai_family == AF_UNSPEC - || (req->ai_family == AF_INET6 - && (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))) - { - gethosts (AF_INET); - - if (req->ai_family == AF_INET) - { - no_inet6_data = no_data; - inet6_status = status; - } - } - - /* If we found one address for AF_INET or AF_INET6, - don't continue the search. */ - if (inet6_status == NSS_STATUS_SUCCESS - || status == NSS_STATUS_SUCCESS) - { - if ((req->ai_flags & AI_CANONNAME) != 0 - && canon == NULL) - { - char *canonbuf = getcanonname (nip, at, name); - if (canonbuf == NULL) - { - __resolv_context_put (res_ctx); - result = -EAI_MEMORY; - goto free_and_return; - } - canon = canonbuf; - } - status = NSS_STATUS_SUCCESS; - } - else - { - /* We can have different states for AF_INET and - AF_INET6. Try to find a useful one for both. */ - if (inet6_status == NSS_STATUS_TRYAGAIN) - status = NSS_STATUS_TRYAGAIN; - else if (status == NSS_STATUS_UNAVAIL - && inet6_status != NSS_STATUS_UNAVAIL) - status = inet6_status; - } - } - else - { - /* Could not locate any of the lookup functions. - The NSS lookup code does not consistently set - errno, so we need to supply our own error - code here. The root cause could either be a - resource allocation failure, or a missing - service function in the DSO (so it should not - be listed in /etc/nsswitch.conf). Assume the - former, and return EBUSY. */ - status = NSS_STATUS_UNAVAIL; - __set_h_errno (NETDB_INTERNAL); - __set_errno (EBUSY); - } - } - - if (nss_next_action (nip, status) == NSS_ACTION_RETURN) - break; - - /* Discard the previous result on CONTINUE. Allocations will get - freed at the end with func_cleanup, so only adjust PAT and free - CANONBUF if it was allocated. */ - if (nss_next_action (nip, status) == NSS_ACTION_CONTINUE) - { - at = NULL; - pat = &at; - free (canon); - canon = NULL; - } - - nip++; - if (nip->module == NULL) - no_more = -1; - } - - __resolv_context_put (res_ctx); - - /* If we have a failure which sets errno, report it using - EAI_SYSTEM. */ - if ((status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) - && h_errno == NETDB_INTERNAL) - { - result = -EAI_SYSTEM; - goto free_and_return; - } - - if (no_data != 0 && no_inet6_data != 0) + if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0) + goto free_and_return; + else if (res.at != NULL) { - /* If both requests timed out report this. */ - if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) - result = -EAI_AGAIN; - else - /* We made requests but they turned out no data. The name - is known, though. */ - result = -EAI_NODATA; - - goto free_and_return; + at = res.at; + canon = at->name; + got_ipv6 = res.got_ipv6; } process_list: - if (at == NULL || at->family == AF_UNSPEC) + if (at == NULL) { result = -EAI_NONAME; goto free_and_return;