* [PATCH 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 13:52 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 02/12] gaih_inet: Simplify canon name resolution Siddhesh Poyarekar
` (13 subsequent siblings)
14 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Allocations for address tuples is currently a bit confusing because of
the pointer chasing through PAT, making it hard to observe the sequence
in which allocations have been made. Narrow scope of the pointer
chasing through PAT so that it is only used where necessary.
This also tightens actions behaviour with the hosts database in
getaddrinfo to comply with the manual text. The "continue" action
discards previous results and the "merge" action results in an immedate
lookup failure. Consequently, chaining of allocations across modules is
no longer necessary, thus opening up cleanup opportunities.
A test has been added that checks some combinations to ensure that they
work correctly. The "dns [SUCCESS=continue] dns" for example results in
a segfault without this fix.
Resolves: BZ #28931
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
nss/Makefile | 1 +
nss/tst-nss-gai-actions.c | 242 ++++++++++++++++++++++++++++++++++++
sysdeps/posix/getaddrinfo.c | 142 +++++++++++++--------
3 files changed, 333 insertions(+), 52 deletions(-)
create mode 100644 nss/tst-nss-gai-actions.c
diff --git a/nss/Makefile b/nss/Makefile
index 552e5d03e1..43a0b9defe 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -78,6 +78,7 @@ tests += tst-nss-files-hosts-multi
tests += tst-nss-files-hosts-getent
tests += tst-nss-files-alias-leak
tests += tst-nss-files-alias-truncated
+tests += tst-nss-gai-actions
endif
# If we have a thread library then we can test cancellation against
diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
new file mode 100644
index 0000000000..b5ba5f0138
--- /dev/null
+++ b/nss/tst-nss-gai-actions.c
@@ -0,0 +1,242 @@
+/* Test continue and merge NSS actions for getaddrinfo.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+enum
+{
+ ACTION_MERGE = 0,
+ ACTION_CONTINUE,
+};
+
+enum
+{
+ DB_FILES = 0,
+ DB_DNS,
+};
+
+struct test_params
+{
+ int db;
+ int action;
+ int family;
+ bool canon;
+};
+
+struct support_chroot *chroot_env;
+
+static void
+prepare (int argc, char **argv)
+{
+ chroot_env = support_chroot_create
+ ((struct support_chroot_configuration)
+ {
+ .resolv_conf = "",
+ .hosts = "",
+ .host_conf = "multi on\n",
+ });
+}
+
+/* Create the /etc/hosts file from outside the chroot. */
+static void
+write_hosts (void)
+{
+ const int count = 512;
+
+ FILE *fp = xfopen (chroot_env->path_hosts, "w");
+ fputs ("127.0.0.1 localhost localhost.localdomain\n"
+ "::1 localhost localhost.localdomain\n",
+ fp);
+ for (int i = 1; i < count; ++i)
+ fprintf (fp, "192.0.%d.%d gnu.org\n", (i / 256) & 0xff, i & 0xff);
+ xfclose (fp);
+}
+
+static const char *
+family_str (int family)
+{
+ switch (family)
+ {
+ case AF_UNSPEC:
+ return "AF_UNSPEC";
+ case AF_INET:
+ return "AF_INET";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static const char *
+db_str (int db)
+{
+ switch (db)
+ {
+ case DB_DNS:
+ return "dns";
+ case DB_FILES:
+ return "files";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static const char *
+action_str (int action)
+{
+ switch (action)
+ {
+ case ACTION_MERGE:
+ return "merge";
+ case ACTION_CONTINUE:
+ return "continue";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+/* getaddrinfo test. To be run from a subprocess. */
+static void
+test_gai (void *closure)
+{
+ struct test_params *params = closure;
+
+ struct addrinfo hints =
+ {
+ .ai_family = params->family,
+ };
+
+ struct addrinfo *ai;
+
+ if (params->canon)
+ hints.ai_flags = AI_CANONNAME;
+
+ /* Use /etc/hosts in the chroot. */
+ if (params->db == DB_FILES)
+ xchroot (chroot_env->path_chroot);
+
+ printf ("***** Testing \"%s [SUCCESS=%s] %s\" for family %s, %s\n",
+ db_str (params->db), action_str (params->action),
+ db_str (params->db), family_str (params->family),
+ params->canon ? "AI_CANONNAME" : "");
+
+ int ret = getaddrinfo ("gnu.org", "80", &hints, &ai);
+
+ switch (params->action)
+ {
+ case ACTION_MERGE:
+ if (ret == 0)
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ printf ("merge unexpectedly succeeded:\n %s\n", formatted);
+ support_record_failure ();
+ free (formatted);
+ }
+ else
+ return;
+ case ACTION_CONTINUE:
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ if (params->db == DB_FILES)
+ {
+ /* Verify that the result appears exactly once. */
+ const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
+ "address: DGRAM/UDP 192.0.0.1 80\n"
+ "address: RAW/IP 192.0.0.1 80\n";
+
+ const char *contains = strstr (formatted, expected);
+ const char *contains2 = NULL;
+
+ if (contains != NULL)
+ contains2 = strstr (contains + strlen (expected), expected);
+
+ if (contains == NULL || contains2 != NULL)
+ {
+ printf ("continue failed:\n%s\n", formatted);
+ support_record_failure ();
+ }
+ }
+ else if (ret != 0)
+ {
+ printf ("continue unexpectedly failed:\n%s\n", formatted);
+ support_record_failure ();
+ }
+
+ free (formatted);
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+test_in_subprocess (int db, int action)
+{
+ char buf[32];
+
+ snprintf (buf, sizeof (buf), "%s [SUCCESS=%s] %s",
+ db_str (db), action_str (action), db_str (db));
+ __nss_configure_lookup ("hosts", buf);
+
+ struct test_params params =
+ {
+ .db = db,
+ .action = action,
+ .family = AF_UNSPEC,
+ .canon = false,
+ };
+ support_isolate_in_subprocess (test_gai, ¶ms);
+ params.family = AF_INET;
+ support_isolate_in_subprocess (test_gai, ¶ms);
+ params.canon = true;
+ support_isolate_in_subprocess (test_gai, ¶ms);
+}
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ if (!support_can_chroot ())
+ FAIL_UNSUPPORTED ("Cannot chroot\n");
+
+ write_hosts ();
+ test_in_subprocess (DB_FILES, ACTION_CONTINUE);
+ test_in_subprocess (DB_FILES, ACTION_MERGE);
+ test_in_subprocess (DB_DNS, ACTION_CONTINUE);
+ test_in_subprocess (DB_DNS, ACTION_MERGE);
+
+ support_chroot_free (chroot_env);
+ return 0;
+}
+
+#define PREPARE prepare
+#include <support/test-driver.c>
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 18dccd5924..454a27eb2f 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -458,11 +458,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (name != NULL)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->family = AF_UNSPEC;
- at->scopeid = 0;
- at->next = NULL;
-
if (req->ai_flags & AI_IDN)
{
char *out;
@@ -473,13 +468,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ uint32_t addr[4];
+ if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
{
+ at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- at->family = AF_INET;
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET;
+ }
else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
{
- at->addr[3] = at->addr[0];
+ at->addr[3] = addr[0];
at->addr[2] = htonl (0xffff);
at->addr[1] = 0;
at->addr[0] = 0;
@@ -493,49 +496,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_flags & AI_CANONNAME)
canon = name;
+
+ goto process_list;
}
- else if (at->family == AF_UNSPEC)
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
+
+ if (e > 0)
{
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, at->addr);
+ at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET6;
+ }
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (addr))
+ {
+ at->addr[0] = addr[3];
+ at->addr[1] = addr[1];
+ at->addr[2] = addr[2];
+ at->addr[3] = addr[3];
+ at->family = AF_INET;
+ }
else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name,
- at->addr);
- if (e > 0)
{
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- at->family = AF_INET6;
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (at->addr))
- {
- at->addr[0] = at->addr[3];
- at->family = AF_INET;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
-
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_ADDRFAMILY;
+ goto free_and_return;
+ }
- if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1,
+ &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto free_and_return;
}
+
+ if (req->ai_flags & AI_CANONNAME)
+ canon = name;
+
+ goto process_list;
}
- if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
+ if ((req->ai_flags & AI_NUMERICHOST) == 0)
{
- struct gaih_addrtuple **pat = &at;
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -543,6 +559,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
enum nss_status status = NSS_STATUS_UNAVAIL;
int no_more;
struct resolv_context *res_ctx = NULL;
+ bool do_merge = false;
/* If we do not have to look for IPv6 addresses or the canonical
name, use the simple, old functions, which do not support
@@ -579,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
result = -EAI_MEMORY;
goto free_and_return;
}
- *pat = addrmem;
+ at = addrmem;
}
else
{
@@ -632,6 +649,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &at;
+
for (int i = 0; i < air->naddrs; ++i)
{
socklen_t size = (air->family[i] == AF_INET
@@ -695,12 +714,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
free (air);
- if (at->family == AF_UNSPEC)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
-
goto process_list;
}
else if (err == 0)
@@ -732,6 +745,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ at = NULL;
+ free (canonbuf);
+ free (addrmem);
+ canon = canonbuf = NULL;
+ addrmem = NULL;
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
no_data = 0;
nss_gethostbyname4_r *fct4 = NULL;
@@ -744,12 +772,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
while (1)
{
- status = DL_CALL_FCT (fct4, (name, pat,
+ status = DL_CALL_FCT (fct4, (name, &at,
tmpbuf->data, tmpbuf->length,
&errno, &h_errno,
NULL));
if (status == NSS_STATUS_SUCCESS)
break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ at = NULL;
if (status != NSS_STATUS_TRYAGAIN
|| errno != ERANGE || h_errno != NETDB_INTERNAL)
{
@@ -774,7 +804,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = (*pat)->name;
+ canon = at->name;
+
+ struct gaih_addrtuple **pat = &at;
while (*pat != NULL)
{
@@ -826,6 +858,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (fct != NULL)
{
+ struct gaih_addrtuple **pat = &at;
+
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
@@ -899,6 +933,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
nip++;
if (nip->module == NULL)
no_more = -1;
@@ -930,7 +968,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
process_list:
- if (at->family == AF_UNSPEC)
+ if (at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-08 10:07 ` [PATCH 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
@ 2022-03-08 13:52 ` Siddhesh Poyarekar
2022-03-08 21:12 ` Carlos O'Donell
0 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 13:52 UTC (permalink / raw)
To: Siddhesh Poyarekar, libc-alpha; +Cc: fweimer
On 08/03/2022 15:37, Siddhesh Poyarekar via Libc-alpha wrote:
> Allocations for address tuples is currently a bit confusing because of
> the pointer chasing through PAT, making it hard to observe the sequence
> in which allocations have been made. Narrow scope of the pointer
> chasing through PAT so that it is only used where necessary.
>
> This also tightens actions behaviour with the hosts database in
> getaddrinfo to comply with the manual text. The "continue" action
> discards previous results and the "merge" action results in an immedate
> lookup failure. Consequently, chaining of allocations across modules is
> no longer necessary, thus opening up cleanup opportunities.
>
> A test has been added that checks some combinations to ensure that they
> work correctly. The "dns [SUCCESS=continue] dns" for example results in
> a segfault without this fix.
>
> Resolves: BZ #28931
>
> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
> ---
> nss/Makefile | 1 +
> nss/tst-nss-gai-actions.c | 242 ++++++++++++++++++++++++++++++++++++
> sysdeps/posix/getaddrinfo.c | 142 +++++++++++++--------
> 3 files changed, 333 insertions(+), 52 deletions(-)
> create mode 100644 nss/tst-nss-gai-actions.c
>
> diff --git a/nss/Makefile b/nss/Makefile
> index 552e5d03e1..43a0b9defe 100644
> --- a/nss/Makefile
> +++ b/nss/Makefile
> @@ -78,6 +78,7 @@ tests += tst-nss-files-hosts-multi
> tests += tst-nss-files-hosts-getent
> tests += tst-nss-files-alias-leak
> tests += tst-nss-files-alias-truncated
> +tests += tst-nss-gai-actions
> endif
>
> # If we have a thread library then we can test cancellation against
> diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
> new file mode 100644
> index 0000000000..b5ba5f0138
> --- /dev/null
> +++ b/nss/tst-nss-gai-actions.c
> @@ -0,0 +1,242 @@
> +/* Test continue and merge NSS actions for getaddrinfo.
Looks like DNS tests don't work under the patchwork trybot container.
I'll mark the "dns [SUCCESS=continue] dns" tests as FAIL_UNSUPPORTED
when it encounters a temporary failure in name resolution.
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-08 13:52 ` Siddhesh Poyarekar
@ 2022-03-08 21:12 ` Carlos O'Donell
2022-03-09 17:13 ` Siddhesh Poyarekar
0 siblings, 1 reply; 68+ messages in thread
From: Carlos O'Donell @ 2022-03-08 21:12 UTC (permalink / raw)
To: Siddhesh Poyarekar, Siddhesh Poyarekar, libc-alpha, DJ Delorie; +Cc: fweimer
On 3/8/22 08:52, Siddhesh Poyarekar wrote:
> On 08/03/2022 15:37, Siddhesh Poyarekar via Libc-alpha wrote:
>> Allocations for address tuples is currently a bit confusing because of
>> the pointer chasing through PAT, making it hard to observe the sequence
>> in which allocations have been made. Narrow scope of the pointer
>> chasing through PAT so that it is only used where necessary.
>>
>> This also tightens actions behaviour with the hosts database in
>> getaddrinfo to comply with the manual text. The "continue" action
>> discards previous results and the "merge" action results in an immedate
>> lookup failure. Consequently, chaining of allocations across modules is
>> no longer necessary, thus opening up cleanup opportunities.
>>
>> A test has been added that checks some combinations to ensure that they
>> work correctly. The "dns [SUCCESS=continue] dns" for example results in
>> a segfault without this fix.
>>
>> Resolves: BZ #28931
>>
>> Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
>> ---
>> nss/Makefile | 1 +
>> nss/tst-nss-gai-actions.c | 242 ++++++++++++++++++++++++++++++++++++
>> sysdeps/posix/getaddrinfo.c | 142 +++++++++++++--------
>> 3 files changed, 333 insertions(+), 52 deletions(-)
>> create mode 100644 nss/tst-nss-gai-actions.c
>>
>> diff --git a/nss/Makefile b/nss/Makefile
>> index 552e5d03e1..43a0b9defe 100644
>> --- a/nss/Makefile
>> +++ b/nss/Makefile
>> @@ -78,6 +78,7 @@ tests += tst-nss-files-hosts-multi
>> tests += tst-nss-files-hosts-getent
>> tests += tst-nss-files-alias-leak
>> tests += tst-nss-files-alias-truncated
>> +tests += tst-nss-gai-actions
>> endif
>> # If we have a thread library then we can test cancellation against
>> diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
>> new file mode 100644
>> index 0000000000..b5ba5f0138
>> --- /dev/null
>> +++ b/nss/tst-nss-gai-actions.c
>> @@ -0,0 +1,242 @@
>> +/* Test continue and merge NSS actions for getaddrinfo.
>
> Looks like DNS tests don't work under the patchwork trybot container.
> I'll mark the "dns [SUCCESS=continue] dns" tests as FAIL_UNSUPPORTED
> when it encounters a temporary failure in name resolution.
No new tests should rely on external DNS being available during testing.
The trybots must be able to run disconnected and fully isolated from the network
from an operational security perspective.
You can and should provide either a stub NSS resolver that returns results for DNS
that just feeds that data back to you.
This is an indication of an incomplete test, in that we need to be able to control
all inputs to the test, otherwise this test is unreliable at best and will spurious
fail when DNS goes down.
--
Cheers,
Carlos.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-08 21:12 ` Carlos O'Donell
@ 2022-03-09 17:13 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-09 17:13 UTC (permalink / raw)
To: Carlos O'Donell, libc-alpha, DJ Delorie; +Cc: fweimer
[Sorry, I thought I responded to this, but I clearly didn't]
On 09/03/2022 02:42, Carlos O'Donell wrote:
> No new tests should rely on external DNS being available during testing.
>
> The trybots must be able to run disconnected and fully isolated from the network
> from an operational security perspective.
>
> You can and should provide either a stub NSS resolver that returns results for DNS
> that just feeds that data back to you.
>
> This is an indication of an incomplete test, in that we need to be able to control
> all inputs to the test, otherwise this test is unreliable at best and will spurious
> fail when DNS goes down.
I'll just drop the dns tests. I had put it in there because "dns
[SUCCESS=continue] dns" would segfault in nss_dns, but that's only a
symptom of the problem in gaih_inet. The remaining nss_files tests in
tst-nss-gai-actions.c test that core problem, so we have the coverage we
need.
Thanks,
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 02/12] gaih_inet: Simplify canon name resolution
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
` (12 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Simplify logic for allocation of canon to remove the canonbuf variable;
canon now always points to an allocated block. Also pull the canon name
set into a separate function.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 130 +++++++++++++++++++++---------------
1 file changed, 75 insertions(+), 55 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 454a27eb2f..df164a3e96 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -285,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
\
if (localcanon != NULL && canon == NULL) \
{ \
- canonbuf = __strdup (localcanon); \
+ char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
@@ -323,6 +323,41 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
return __strdup (name);
}
+/* Process looked up canonical name and if necessary, decode to IDNA. Result
+ is a new string written to CANONP and the earlier string is freed. */
+
+static int
+process_canonname (const struct addrinfo *req, const char *orig_name,
+ char **canonp)
+{
+ char *canon = *canonp;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0)
+ {
+ bool do_idn = req->ai_flags & AI_CANONIDN;
+ if (do_idn)
+ {
+ char *out;
+ int rc = __idna_from_dns_encoding (canon ?: orig_name, &out);
+ if (rc == 0)
+ {
+ free (canon);
+ canon = out;
+ }
+ else if (rc == EAI_IDN_ENCODE)
+ /* Use the punycode name as a fallback. */
+ do_idn = false;
+ else
+ return -rc;
+ }
+ if (!do_idn && canon == NULL && (canon = __strdup (orig_name)) == NULL)
+ return -EAI_MEMORY;
+ }
+
+ *canonp = canon;
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -332,7 +367,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
- const char *canon = NULL;
+ char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -453,7 +488,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
- char *canonbuf = NULL;
int result = 0;
if (name != NULL)
@@ -495,7 +529,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -545,7 +587,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -676,9 +726,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
(*pat)->next = NULL;
if (added_canon || air->canon == NULL)
(*pat)->name = NULL;
- else if (canonbuf == NULL)
+ else if (canon == NULL)
{
- canonbuf = __strdup (air->canon);
+ char *canonbuf = __strdup (air->canon);
if (canonbuf == NULL)
{
result = -EAI_MEMORY;
@@ -748,9 +798,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
/* Always start afresh; continue should discard previous results
and the hosts database does not support merge. */
at = NULL;
- free (canonbuf);
+ free (canon);
free (addrmem);
- canon = canonbuf = NULL;
+ canon = NULL;
addrmem = NULL;
if (do_merge)
@@ -804,7 +854,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = at->name;
+ {
+ char *canonbuf = __strdup (at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
struct gaih_addrtuple **pat = &at;
@@ -892,7 +951,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((req->ai_flags & AI_CANONNAME) != 0
&& canon == NULL)
{
- canonbuf = getcanonname (nip, at, name);
+ char *canonbuf = getcanonname (nip, at, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
@@ -1003,6 +1062,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
{
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &canon)) != 0)
+ goto free_and_return;
+
struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
@@ -1013,48 +1076,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
*/
while (at2 != NULL)
{
- /* Only the first entry gets the canonical name. */
- if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
- {
- if (canon == NULL)
- /* If the canonical name cannot be determined, use
- the passed in string. */
- canon = orig_name;
-
- bool do_idn = req->ai_flags & AI_CANONIDN;
- if (do_idn)
- {
- char *out;
- int rc = __idna_from_dns_encoding (canon, &out);
- if (rc == 0)
- canon = out;
- else if (rc == EAI_IDN_ENCODE)
- /* Use the punycode name as a fallback. */
- do_idn = false;
- else
- {
- result = -rc;
- goto free_and_return;
- }
- }
- if (!do_idn)
- {
- if (canonbuf != NULL)
- /* We already allocated the string using malloc, but
- the buffer is now owned by canon. */
- canonbuf = NULL;
- else
- {
- canon = __strdup (canon);
- if (canon == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
- }
- }
-
family = at2->family;
if (family == AF_INET6)
{
@@ -1077,7 +1098,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
if (ai == NULL)
{
- free ((char *) canon);
result = -EAI_MEMORY;
goto free_and_return;
}
@@ -1137,7 +1157,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canonbuf);
+ free (canon);
return result;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852]
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 02/12] gaih_inet: Simplify canon name resolution Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 11:00 ` Andreas Schwab
2022-03-08 10:07 ` [PATCH 04/12] gaih_inet: Simplify service resolution Siddhesh Poyarekar
` (11 subsequent siblings)
14 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Use realloc in convert_hostent_to_gaih_addrtuple and fix up pointers in
the result list so that a single block is maintained for
hostbyname3_r/hostbyname2_r and freed in gaih_inet. This result is
never merged with any other results, since the hosts database does not
permit merging.
Resolves BZ #28852.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index df164a3e96..0ec85dc4bd 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -199,9 +199,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
struct hostent *h,
struct gaih_addrtuple **result)
{
- while (*result)
- result = &(*result)->next;
-
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
for (char **p = h->h_addr_list; *p != NULL; ++p)
@@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = calloc (count, sizeof (*array));
+ struct gaih_addrtuple *array = *result;
+ size_t old = 0;
+
+ while (array)
+ {
+ old++;
+ array = array->next;
+ }
+
+ array = realloc (*result, (old + count) * sizeof (*array));
+
if (array == NULL)
return false;
+ *result = array;
+
+ /* Update the next pointers on reallocation. */
+ for (size_t i = 0; i < old; i++)
+ array[i].next = array + i + 1;
+
+ array += old;
+
+ memset (array, 0, count * sizeof (*array));
+
for (size_t i = 0; i < count; ++i)
{
if (family == AF_INET && req->ai_family == AF_INET6)
@@ -235,7 +252,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array[0].name = h->h_name;
array[count - 1].next = NULL;
- *result = array;
return true;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852]
2022-03-08 10:07 ` [PATCH 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
@ 2022-03-08 11:00 ` Andreas Schwab
2022-03-08 13:45 ` Siddhesh Poyarekar
0 siblings, 1 reply; 68+ messages in thread
From: Andreas Schwab @ 2022-03-08 11:00 UTC (permalink / raw)
To: Siddhesh Poyarekar via Libc-alpha; +Cc: Siddhesh Poyarekar, fweimer
On Mär 08 2022, Siddhesh Poyarekar via Libc-alpha wrote:
> @@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
> if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
> return true;
>
> - struct gaih_addrtuple *array = calloc (count, sizeof (*array));
> + struct gaih_addrtuple *array = *result;
> + size_t old = 0;
> +
> + while (array)
array != NULL
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1
"And now for something completely different."
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852]
2022-03-08 11:00 ` Andreas Schwab
@ 2022-03-08 13:45 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 13:45 UTC (permalink / raw)
To: Andreas Schwab, Siddhesh Poyarekar via Libc-alpha; +Cc: fweimer
On 08/03/2022 16:30, Andreas Schwab wrote:
> On Mär 08 2022, Siddhesh Poyarekar via Libc-alpha wrote:
>
>> @@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
>> if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
>> return true;
>>
>> - struct gaih_addrtuple *array = calloc (count, sizeof (*array));
>> + struct gaih_addrtuple *array = *result;
>> + size_t old = 0;
>> +
>> + while (array)
>
> array != NULL
>
Thanks, fixed locally.
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 04/12] gaih_inet: Simplify service resolution
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (2 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 05/12] gaih_inet: make numeric lookup a separate routine Siddhesh Poyarekar
` (10 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Refactor the code to split out the service resolution code into a
separate function. Allocate the service tuples array just once to the
size of the typeproto array, thus avoiding the unnecessary pointer
chasing and stack allocations.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 178 ++++++++++++++++--------------------
1 file changed, 78 insertions(+), 100 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 0ec85dc4bd..6bc1d6b8d2 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -100,14 +100,12 @@ struct gaih_service
struct gaih_servtuple
{
- struct gaih_servtuple *next;
int socktype;
int protocol;
int port;
+ bool set;
};
-static const struct gaih_servtuple nullserv;
-
struct gaih_typeproto
{
@@ -180,11 +178,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
while (r);
- st->next = NULL;
st->socktype = tp->socktype;
st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
? req->ai_protocol : tp->protocol);
st->port = s->s_port;
+ st->set = true;
return 0;
}
@@ -375,20 +373,11 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
}
static int
-gaih_inet (const char *name, const struct gaih_service *service,
- const struct addrinfo *req, struct addrinfo **pai,
- unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
+ struct gaih_servtuple *st, struct scratch_buffer *tmpbuf)
{
+ int i;
const struct gaih_typeproto *tp = gaih_inet_typeproto;
- struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
- struct gaih_addrtuple *at = NULL;
- bool got_ipv6 = false;
- char *canon = NULL;
- const char *orig_name = name;
-
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
if (req->ai_protocol || req->ai_socktype)
{
@@ -410,98 +399,88 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
- int port = 0;
- if (service != NULL)
+ if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ return -EAI_SERVICE;
+
+ if (service == NULL || service->num >= 0)
{
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- return -EAI_SERVICE;
+ int port = service != NULL ? htons (service->num) : 0;
- if (service->num < 0)
+ if (req->ai_socktype || req->ai_protocol)
{
- if (tp->name[0])
- {
- st = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple), alloca_used);
-
- int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- if (__glibc_unlikely (rc != 0))
- return rc;
- }
- else
- {
- struct gaih_servtuple **pst = &st;
- for (tp++; tp->name[0]; tp++)
- {
- struct gaih_servtuple *newp;
+ st[0].socktype = tp->socktype;
+ st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+ ? req->ai_protocol : tp->protocol);
+ st[0].port = port;
+ st[0].set = true;
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- continue;
+ return 0;
+ }
- if (req->ai_socktype != 0
- && req->ai_socktype != tp->socktype)
- continue;
- if (req->ai_protocol != 0
- && !(tp->protoflag & GAI_PROTO_PROTOANY)
- && req->ai_protocol != tp->protocol)
- continue;
+ /* Neither socket type nor protocol is set. Return all socket types
+ we know about. */
+ for (i = 0, ++tp; tp->name[0]; ++tp)
+ if (tp->defaultflag)
+ {
+ st[i].socktype = tp->socktype;
+ st[i].protocol = tp->protocol;
+ st[i].port = port;
+ st[i++].set = true;
+ }
- newp = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
+ return 0;
+ }
- if (gaih_inet_serv (service->name,
- tp, req, newp, tmpbuf) != 0)
- continue;
+ if (tp->name[0])
+ return gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- *pst = newp;
- pst = &(newp->next);
- }
- if (st == (struct gaih_servtuple *) &nullserv)
- return -EAI_SERVICE;
- }
- }
- else
- {
- port = htons (service->num);
- goto got_port;
- }
- }
- else
+ for (i = 0, tp++; tp->name[0]; tp++)
{
- got_port:
+ if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ continue;
- if (req->ai_socktype || req->ai_protocol)
- {
- st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
- st->next = NULL;
- st->socktype = tp->socktype;
- st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
- ? req->ai_protocol : tp->protocol);
- st->port = port;
- }
- else
- {
- /* Neither socket type nor protocol is set. Return all socket types
- we know about. */
- struct gaih_servtuple **lastp = &st;
- for (++tp; tp->name[0]; ++tp)
- if (tp->defaultflag)
- {
- struct gaih_servtuple *newp;
+ if (req->ai_socktype != 0
+ && req->ai_socktype != tp->socktype)
+ continue;
+ if (req->ai_protocol != 0
+ && !(tp->protoflag & GAI_PROTO_PROTOANY)
+ && req->ai_protocol != tp->protocol)
+ continue;
- newp = alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
- newp->next = NULL;
- newp->socktype = tp->socktype;
- newp->protocol = tp->protocol;
- newp->port = port;
+ if (gaih_inet_serv (service->name,
+ tp, req, &st[i], tmpbuf) != 0)
+ continue;
- *lastp = newp;
- lastp = &newp->next;
- }
- }
+ i++;
}
+ if (!st[0].set)
+ return -EAI_SERVICE;
+
+ return 0;
+}
+
+static int
+gaih_inet (const char *name, const struct gaih_service *service,
+ const struct addrinfo *req, struct addrinfo **pai,
+ unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+{
+ struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
+ / sizeof (struct gaih_typeproto)] = {0};
+
+ struct gaih_addrtuple *at = NULL;
+ bool got_ipv6 = false;
+ char *canon = NULL;
+ const char *orig_name = name;
+
+ /* Reserve stack memory for the scratch buffer in the getaddrinfo
+ function. */
+ size_t alloca_used = sizeof (struct scratch_buffer);
+
+ int rc;
+ if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
+ return rc;
+
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
@@ -1082,7 +1061,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((result = process_canonname (req, orig_name, &canon)) != 0)
goto free_and_return;
- struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
sa_family_t family;
@@ -1108,7 +1086,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
socklen = sizeof (struct sockaddr_in);
- for (st2 = st; st2 != NULL; st2 = st2->next)
+ for (int i = 0; st[i].set; i++)
{
struct addrinfo *ai;
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
@@ -1120,8 +1098,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_flags = req->ai_flags;
ai->ai_family = family;
- ai->ai_socktype = st2->socktype;
- ai->ai_protocol = st2->protocol;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
ai->ai_addrlen = socklen;
ai->ai_addr = (void *) (ai + 1);
@@ -1143,7 +1121,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) ai->ai_addr;
- sin6p->sin6_port = st2->port;
+ sin6p->sin6_port = st[i].port;
sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr));
@@ -1153,7 +1131,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
struct sockaddr_in *sinp =
(struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st2->port;
+ sinp->sin_port = st[i].port;
memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr));
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 05/12] gaih_inet: make numeric lookup a separate routine
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (3 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 04/12] gaih_inet: Simplify service resolution Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 06/12] gaih_inet: Split simple gethostbyname into its own function Siddhesh Poyarekar
` (9 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Introduce the gaih_result structure and general paradigm for cleanups
that follow to process the lookup request and return a result. A lookup
function (like text_to_binary_address), should return an integer error
code and set members of gaih_result based on what it finds. If the
function does not have a result and no errors have occurred during the
lookup, it should return 0 and res.at should be set to NULL, allowing a
subsequent function to do the lookup until we run out of options.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 889 ++++++++++++++++++------------------
1 file changed, 451 insertions(+), 438 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 6bc1d6b8d2..868c7d222f 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -116,6 +116,12 @@ struct gaih_typeproto
char name[8];
};
+struct gaih_result
+{
+ struct gaih_addrtuple *at;
+ char *canon;
+};
+
/* Values for `protoflag'. */
#define GAI_PROTO_NOSERVICE 1
#define GAI_PROTO_PROTOANY 2
@@ -297,7 +303,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
*pat = addrmem; \
\
- if (localcanon != NULL && canon == NULL) \
+ if (localcanon != NULL && res.canon == NULL) \
{ \
char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
@@ -306,7 +312,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
result = -EAI_SYSTEM; \
goto free_and_return; \
} \
- canon = canonbuf; \
+ res.canon = canonbuf; \
} \
if (_family == AF_INET6 && *pat != NULL) \
got_ipv6 = true; \
@@ -342,9 +348,9 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
static int
process_canonname (const struct addrinfo *req, const char *orig_name,
- char **canonp)
+ struct gaih_result *res)
{
- char *canon = *canonp;
+ char *canon = res->canon;
if ((req->ai_flags & AI_CANONNAME) != 0)
{
@@ -368,7 +374,7 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
return -EAI_MEMORY;
}
- *canonp = canon;
+ res->canon = canon;
return 0;
}
@@ -460,6 +466,105 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
return 0;
}
+/* 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
+ returned. */
+
+static int
+text_to_binary_address (const char *name, const struct addrinfo *req,
+ struct gaih_result *res)
+{
+ struct gaih_addrtuple *at = res->at;
+ int result = 0;
+
+ assert (at != NULL);
+
+ memset (at->addr, 0, sizeof (at->addr));
+ if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ {
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+ at->family = AF_INET;
+ else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
+ {
+ at->addr[3] = at->addr[0];
+ at->addr[2] = htonl (0xffff);
+ at->addr[1] = 0;
+ at->addr[0] = 0;
+ at->family = AF_INET6;
+ }
+ else
+ {
+ result = -EAI_ADDRFAMILY;
+ goto out;
+ }
+
+ if (req->ai_flags & AI_CANONNAME)
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+ return 0;
+ }
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, at->addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, at->addr);
+
+ if (e > 0)
+ {
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ at->family = AF_INET6;
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ {
+ at->addr[0] = at->addr[3];
+ at->family = AF_INET;
+ }
+ else
+ {
+ result = -EAI_ADDRFAMILY;
+ goto out;
+ }
+
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1, &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto out;
+ }
+
+ if (req->ai_flags & AI_CANONNAME)
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+ return 0;
+ }
+
+ if ((req->ai_flags & AI_NUMERICHOST))
+ result = -EAI_NONAME;
+
+out:
+ res->at = NULL;
+ return result;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -468,9 +573,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
/ sizeof (struct gaih_typeproto)] = {0};
- struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
- char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -485,6 +588,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
+ struct gaih_result res = {0};
if (name != NULL)
{
if (req->ai_flags & AI_IDN)
@@ -497,532 +601,440 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- uint32_t addr[4];
- if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
+ res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ res.at->scopeid = 0;
+ res.at->next = NULL;
+
+ if ((result = text_to_binary_address (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+
+ 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;
+ bool do_merge = false;
+
+ /* If we do not have to look for IPv6 addresses or the canonical
+ name, use the simple, old functions, which do not support
+ IPv6 scope ids, nor retrieving the canonical name. */
+ if (req->ai_family == AF_INET
+ && (req->ai_flags & AI_CANONNAME) == 0)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->scopeid = 0;
- at->next = NULL;
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- {
- memcpy (at->addr, addr, sizeof (at->addr));
- at->family = AF_INET;
- }
- else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
- {
- at->addr[3] = addr[0];
- at->addr[2] = htonl (0xffff);
- at->addr[1] = 0;
- at->addr[0] = 0;
- at->family = AF_INET6;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
+ int rc;
+ struct hostent th;
+ struct hostent *h;
- if (req->ai_flags & AI_CANONNAME)
+ while (1)
{
- char *canonbuf = __strdup (name);
- if (canonbuf == NULL)
+ rc = __gethostbyname2_r (name, AF_INET, &th,
+ tmpbuf->data, tmpbuf->length,
+ &h, &h_errno);
+ if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
{
result = -EAI_MEMORY;
goto free_and_return;
}
- canon = canonbuf;
}
- goto process_list;
- }
-
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
-
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, addr);
- else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
-
- if (e > 0)
- {
- at = alloca_account (sizeof (struct gaih_addrtuple),
- alloca_used);
- at->scopeid = 0;
- at->next = NULL;
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- {
- memcpy (at->addr, addr, sizeof (at->addr));
- at->family = AF_INET6;
- }
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (addr))
+ if (rc == 0)
{
- at->addr[0] = addr[3];
- at->addr[1] = addr[1];
- at->addr[2] = addr[2];
- at->addr[3] = addr[3];
- at->family = AF_INET;
+ if (h != NULL)
+ {
+ /* We found data, convert it. */
+ if (!convert_hostent_to_gaih_addrtuple
+ (req, AF_INET, h, &addrmem))
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ res.at = addrmem;
+ }
+ else
+ {
+ if (h_errno == NO_DATA)
+ result = -EAI_NODATA;
+ else
+ result = -EAI_NONAME;
+ goto free_and_return;
+ }
}
else
{
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
+ if (h_errno == NETDB_INTERNAL)
+ result = -EAI_SYSTEM;
+ else if (h_errno == TRY_AGAIN)
+ result = -EAI_AGAIN;
+ else
+ /* We made requests but they turned out no data.
+ The name is known, though. */
+ result = -EAI_NODATA;
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
goto free_and_return;
}
- if (req->ai_flags & AI_CANONNAME)
+ goto process_list;
+ }
+
+#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)
{
- char *canonbuf = __strdup (name);
- if (canonbuf == 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;
}
- canon = canonbuf;
- }
- goto process_list;
- }
-
- if ((req->ai_flags & AI_NUMERICHOST) == 0)
- {
- 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;
- bool do_merge = false;
-
- /* If we do not have to look for IPv6 addresses or the canonical
- name, use the simple, old functions, which do not support
- IPv6 scope ids, nor retrieving the canonical name. */
- if (req->ai_family == AF_INET
- && (req->ai_flags & AI_CANONNAME) == 0)
- {
- int rc;
- struct hostent th;
- struct hostent *h;
+ struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &res.at;
- while (1)
+ for (int i = 0; i < air->naddrs; ++i)
{
- rc = __gethostbyname2_r (name, AF_INET, &th,
- tmpbuf->data, tmpbuf->length,
- &h, &h_errno);
- if (rc != ERANGE || h_errno != NETDB_INTERNAL)
- break;
- if (!scratch_buffer_grow (tmpbuf))
+ 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))
{
- result = -EAI_MEMORY;
- goto free_and_return;
+ /* Skip over non-matching result. */
+ addrs += size;
+ continue;
}
- }
- if (rc == 0)
- {
- if (h != NULL)
+ 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)
{
- /* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple
- (req, AF_INET, h, &addrmem))
+ char *canonbuf = __strdup (air->canon);
+ if (canonbuf == NULL)
{
result = -EAI_MEMORY;
goto free_and_return;
}
- at = addrmem;
+ res.canon = (*pat)->name = canonbuf;
}
- else
+
+ if (air->family[i] == AF_INET
+ && req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED))
{
- if (h_errno == NO_DATA)
- result = -EAI_NODATA;
- else
- result = -EAI_NONAME;
- goto free_and_return;
+ (*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;
}
- else
- {
- if (h_errno == NETDB_INTERNAL)
- result = -EAI_SYSTEM;
- else if (h_errno == TRY_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;
- }
+ 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;
-#ifdef USE_NSCD
- if (__nss_not_use_nscd_hosts > 0
- && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
- __nss_not_use_nscd_hosts = 0;
+ goto free_and_return;
+ }
+ }
+#endif
+
+ no_more = !__nss_database_get (nss_database_hosts, &nip);
- if (!__nss_not_use_nscd_hosts
- && !__nss_database_custom[NSS_DBSIDX_hosts])
+ /* 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)
+ {
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ res.at = NULL;
+ free (res.canon);
+ free (addrmem);
+ res.canon = NULL;
+ addrmem = NULL;
+
+ if (do_merge)
{
- /* Try to use nscd. */
- struct nscd_ai_result *air = NULL;
- int err = __nscd_getai (name, &air, &h_errno);
- if (air != NULL)
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
+ 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)
+ {
+ while (1)
{
- /* Transform into gaih_addrtuple list. */
- bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
- char *addrs = air->addrs;
+ status = DL_CALL_FCT (fct4, (name, &res.at,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno,
+ NULL));
+ if (status == NSS_STATUS_SUCCESS)
+ break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ res.at = NULL;
+ 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;
+ }
- addrmem = calloc (air->naddrs, sizeof (*addrmem));
- if (addrmem == NULL)
+ if (!scratch_buffer_grow (tmpbuf))
{
+ __resolv_context_put (res_ctx);
result = -EAI_MEMORY;
goto free_and_return;
}
+ }
- struct gaih_addrtuple *addrfree = addrmem;
- struct gaih_addrtuple **pat = &at;
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ assert (!no_data);
+ no_data = 1;
- for (int i = 0; i < air->naddrs; ++i)
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL)
{
- 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))
+ char *canonbuf = __strdup (res.at->name);
+ if (canonbuf == NULL)
{
- /* Skip over non-matching result. */
- addrs += size;
- continue;
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto free_and_return;
}
+ res.canon = canonbuf;
+ }
- 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 (canon == NULL)
- {
- char *canonbuf = __strdup (air->canon);
- if (canonbuf == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- canon = (*pat)->name = canonbuf;
- }
+ struct gaih_addrtuple **pat = &res.at;
- if (air->family[i] == AF_INET
+ while (*pat != NULL)
+ {
+ if ((*pat)->family == AF_INET
&& req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED))
+ && (req->ai_flags & AI_V4MAPPED) != 0)
{
+ uint32_t *pataddr = (*pat)->addr;
(*pat)->family = AF_INET6;
- pataddr[3] = *(uint32_t *) addrs;
+ pataddr[3] = pataddr[0];
pataddr[2] = htonl (0xffff);
pataddr[1] = 0;
pataddr[0] = 0;
pat = &((*pat)->next);
- added_canon = true;
+ no_data = 0;
}
else if (req->ai_family == AF_UNSPEC
- || air->family[i] == req->ai_family)
+ || (*pat)->family == req->ai_family)
{
- (*pat)->family = air->family[i];
- memcpy (pataddr, addrs, size);
pat = &((*pat)->next);
- added_canon = true;
- if (air->family[i] == AF_INET6)
+
+ no_data = 0;
+ if (req->ai_family == AF_INET6)
got_ipv6 = true;
}
- addrs += size;
+ else
+ *pat = ((*pat)->next);
}
-
- 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;
- }
+ no_inet6_data = no_data;
}
-#endif
-
- 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)
+ else
{
- /* Always start afresh; continue should discard previous results
- and the hosts database does not support merge. */
- at = NULL;
- free (canon);
- free (addrmem);
- canon = NULL;
- addrmem = NULL;
-
- if (do_merge)
+ 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)
{
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- break;
- }
-
- 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");
+ struct gaih_addrtuple **pat = &res.at;
- if (fct4 != NULL)
- {
- while (1)
+ if (req->ai_family == AF_INET6
+ || req->ai_family == AF_UNSPEC)
{
- status = DL_CALL_FCT (fct4, (name, &at,
- tmpbuf->data, tmpbuf->length,
- &errno, &h_errno,
- NULL));
- if (status == NSS_STATUS_SUCCESS)
- break;
- /* gethostbyname4_r may write into AT, so reset it. */
- at = NULL;
- 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;
- }
+ 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 (!scratch_buffer_grow (tmpbuf))
+ if (req->ai_family == AF_INET)
{
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
+ no_inet6_data = no_data;
+ inet6_status = status;
}
}
- if (status == NSS_STATUS_SUCCESS)
+ /* 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)
{
- assert (!no_data);
- no_data = 1;
-
- if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
+ if ((req->ai_flags & AI_CANONNAME) != 0
+ && res.canon == NULL)
{
- char *canonbuf = __strdup (at->name);
+ char *canonbuf = getcanonname (nip, res.at, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
result = -EAI_MEMORY;
goto free_and_return;
}
- canon = canonbuf;
- }
-
- struct gaih_addrtuple **pat = &at;
-
- 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)
- {
- struct gaih_addrtuple **pat = &at;
-
- 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;
+ res.canon = canonbuf;
}
+ status = NSS_STATUS_SUCCESS;
}
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);
+ /* 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;
+ if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+ break;
- /* The hosts database does not support MERGE. */
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
- do_merge = true;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
- nip++;
- if (nip->module == NULL)
- no_more = -1;
- }
+ nip++;
+ if (nip->module == NULL)
+ no_more = -1;
+ }
- __resolv_context_put (res_ctx);
+ __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 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;
+ 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;
- goto free_and_return;
- }
+ goto free_and_return;
}
process_list:
- if (at == NULL)
+ if (res.at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;
@@ -1031,21 +1043,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
{
struct gaih_addrtuple *atr;
- atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- memset (at, '\0', sizeof (struct gaih_addrtuple));
+ atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ memset (res.at, '\0', sizeof (struct gaih_addrtuple));
if (req->ai_family == AF_UNSPEC)
{
- at->next = __alloca (sizeof (struct gaih_addrtuple));
- memset (at->next, '\0', sizeof (struct gaih_addrtuple));
+ res.at->next = __alloca (sizeof (struct gaih_addrtuple));
+ memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
}
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
{
- at->family = AF_INET6;
+ res.at->family = AF_INET6;
if ((req->ai_flags & AI_PASSIVE) == 0)
- memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
- atr = at->next;
+ memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+ atr = res.at->next;
}
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
@@ -1058,10 +1071,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
/* Set up the canonical name if we need it. */
- if ((result = process_canonname (req, orig_name, &canon)) != 0)
+ if ((result = process_canonname (req, orig_name, &res)) != 0)
goto free_and_return;
- struct gaih_addrtuple *at2 = at;
+ struct gaih_addrtuple *at2 = res.at;
size_t socklen;
sa_family_t family;
@@ -1104,8 +1117,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_addr = (void *) (ai + 1);
/* We only add the canonical name once. */
- ai->ai_canonname = (char *) canon;
- canon = NULL;
+ ai->ai_canonname = res.canon;
+ res.canon = NULL;
#ifdef _HAVE_SA_LEN
ai->ai_addr->sa_len = socklen;
@@ -1151,7 +1164,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canon);
+ free (res.canon);
return result;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 06/12] gaih_inet: Split simple gethostbyname into its own function
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (4 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 05/12] gaih_inet: make numeric lookup a separate routine Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 07/12] gaih_inet: Split nscd lookup code " Siddhesh Poyarekar
` (8 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Add a free_at flag in gaih_result to indicate if res.at needs to be
freed by the caller.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 125 ++++++++++++++++++------------------
1 file changed, 62 insertions(+), 63 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 868c7d222f..2024464f52 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -120,6 +120,7 @@ struct gaih_result
{
struct gaih_addrtuple *at;
char *canon;
+ bool free_at;
};
/* Values for `protoflag'. */
@@ -565,6 +566,60 @@ out:
return result;
}
+/* If possible, call the simple, old functions, which do not support IPv6 scope
+ ids, nor retrieving the canonical name. */
+
+static int
+try_simple_gethostbyname (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf,
+ struct gaih_result *res)
+{
+ res->at = NULL;
+
+ if (req->ai_family != AF_INET || (req->ai_flags & AI_CANONNAME) != 0)
+ return 0;
+
+ int rc;
+ struct hostent th;
+ struct hostent *h;
+
+ while (1)
+ {
+ rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf->data,
+ tmpbuf->length, &h, &h_errno);
+ if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+
+ if (rc == 0)
+ {
+ if (h != NULL)
+ {
+ /* We found data, convert it. */
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ return -EAI_MEMORY;
+
+ res->free_at = true;
+ return 0;
+ }
+ if (h_errno == NO_DATA)
+ return -EAI_NODATA;
+
+ return -EAI_NONAME;
+ }
+
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ return -EAI_AGAIN;
+
+ /* We made requests but they turned out no data.
+ The name is known, though. */
+ return -EAI_NODATA;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -610,6 +665,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
else if (res.at != NULL)
goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -619,69 +679,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct resolv_context *res_ctx = NULL;
bool do_merge = false;
- /* If we do not have to look for IPv6 addresses or the canonical
- name, use the simple, old functions, which do not support
- IPv6 scope ids, nor retrieving the canonical name. */
- if (req->ai_family == AF_INET
- && (req->ai_flags & AI_CANONNAME) == 0)
- {
- int rc;
- struct hostent th;
- struct hostent *h;
-
- while (1)
- {
- rc = __gethostbyname2_r (name, AF_INET, &th,
- tmpbuf->data, tmpbuf->length,
- &h, &h_errno);
- if (rc != ERANGE || h_errno != NETDB_INTERNAL)
- break;
- if (!scratch_buffer_grow (tmpbuf))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
-
- if (rc == 0)
- {
- if (h != NULL)
- {
- /* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple
- (req, AF_INET, h, &addrmem))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.at = addrmem;
- }
- else
- {
- if (h_errno == NO_DATA)
- result = -EAI_NODATA;
- else
- result = -EAI_NONAME;
- goto free_and_return;
- }
- }
- else
- {
- if (h_errno == NETDB_INTERNAL)
- result = -EAI_SYSTEM;
- else if (h_errno == TRY_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;
- }
-
- goto process_list;
- }
-
#ifdef USE_NSCD
if (__nss_not_use_nscd_hosts > 0
&& ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
@@ -1164,6 +1161,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
+ if (res.free_at)
+ free (res.at);
free (res.canon);
return result;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 07/12] gaih_inet: Split nscd lookup code into its own function.
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (5 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 06/12] gaih_inet: Split simple gethostbyname into its own function Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
` (7 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
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>
---
sysdeps/posix/getaddrinfo.c | 248 +++++++++++++++++++-----------------
1 file changed, 134 insertions(+), 114 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 2024464f52..2ec5a7d76f 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
@@ -628,7 +751,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
@@ -670,6 +792,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;
@@ -679,115 +808,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
@@ -894,7 +914,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);
@@ -937,7 +957,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);
@@ -1088,7 +1108,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;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 08/12] gaih_inet: separate nss lookup loop into its own function
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (6 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 07/12] gaih_inet: Split nscd lookup code " Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 09/12] gaih_inet: make gethosts into a function Siddhesh Poyarekar
` (6 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 566 ++++++++++++++++++------------------
1 file changed, 288 insertions(+), 278 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 2ec5a7d76f..b30af6bb7b 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -159,6 +159,14 @@ static const struct addrinfo default_hints =
.ai_next = NULL
};
+static void
+gaih_result_reset (struct gaih_result *res)
+{
+ if (res->free_at)
+ free (res->at);
+ free (res->canon);
+ memset (res, 0, sizeof (*res));
+}
static int
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
@@ -195,15 +203,13 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
return 0;
}
-/* Convert struct hostent to a list of struct gaih_addrtuple objects.
- h_name is not copied, and the struct hostent object must not be
- deallocated prematurely. *RESULT must be NULL or a pointer to a
- linked-list. The new addresses are appended at the end. */
+/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
+ is not copied, and the struct hostent object must not be deallocated
+ prematurely. *RESULT must be NULL or a pointer to a linked-list. The new
+ addresses are appended at the end. */
static bool
-convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
- int family,
- struct hostent *h,
- struct gaih_addrtuple **result)
+convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
+ struct hostent *h, struct gaih_result *res)
{
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
@@ -215,7 +221,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = *result;
+ struct gaih_addrtuple *array = res->at;
size_t old = 0;
while (array)
@@ -224,12 +230,13 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array = array->next;
}
- array = realloc (*result, (old + count) * sizeof (*array));
+ array = res->at = realloc (res->at, (old + count) * sizeof (*array));
if (array == NULL)
return false;
- *result = array;
+ res->got_ipv6 = family == AF_INET6;
+ res->free_at = true;
/* Update the next pointers on reallocation. */
for (size_t i = 0; i < old; i++)
@@ -278,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_MEMORY; \
- goto free_and_return; \
+ goto out; \
} \
} \
if (status == NSS_STATUS_NOTFOUND \
@@ -288,7 +295,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
if (h_errno == TRY_AGAIN) \
no_data = EAI_AGAIN; \
@@ -297,27 +304,24 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
else if (status == NSS_STATUS_SUCCESS) \
{ \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \
+ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- *pat = addrmem; \
\
- if (localcanon != NULL && res.canon == NULL) \
+ if (localcanon != NULL && res->canon == NULL) \
{ \
char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- res.canon = canonbuf; \
+ res->canon = canonbuf; \
} \
- if (_family == AF_INET6 && *pat != NULL) \
- res.got_ipv6 = true; \
} \
}
@@ -590,6 +594,260 @@ out:
}
#endif
+static int
+get_nss_addresses (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf, struct gaih_result *res)
+{
+ 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;
+ bool do_merge = false;
+ int result = 0;
+
+ 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)
+ {
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ gaih_result_reset (res);
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
+ 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)
+ {
+ while (1)
+ {
+ status = DL_CALL_FCT (fct4, (name, &res->at,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno,
+ NULL));
+ if (status == NSS_STATUS_SUCCESS)
+ break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ res->at = NULL;
+ 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;
+ }
+
+ if (!scratch_buffer_grow (tmpbuf))
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ assert (!no_data);
+ no_data = 1;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (res->at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+
+ struct gaih_addrtuple **pat = &res->at;
+
+ 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
+ && res->canon == NULL)
+ {
+ char *canonbuf = getcanonname (nip, res->at, name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->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;
+
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
+ 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 out;
+ }
+
+ 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;
+ }
+
+out:
+ if (result != 0)
+ gaih_result_reset (res);
+ return result;
+}
+
/* 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
@@ -721,7 +979,7 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
if (h != NULL)
{
/* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, res))
return -EAI_MEMORY;
res->free_at = true;
@@ -799,263 +1057,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto process_list;
#endif
- 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;
- bool do_merge = false;
-
- 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)
- {
- /* Always start afresh; continue should discard previous results
- and the hosts database does not support merge. */
- res.at = NULL;
- free (res.canon);
- free (addrmem);
- res.canon = NULL;
- addrmem = NULL;
-
- if (do_merge)
- {
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- break;
- }
-
- 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)
- {
- while (1)
- {
- status = DL_CALL_FCT (fct4, (name, &res.at,
- tmpbuf->data, tmpbuf->length,
- &errno, &h_errno,
- NULL));
- if (status == NSS_STATUS_SUCCESS)
- break;
- /* gethostbyname4_r may write into AT, so reset it. */
- res.at = NULL;
- 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;
- }
-
- if (!scratch_buffer_grow (tmpbuf))
- {
- __resolv_context_put (res_ctx);
- 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 && res.canon == NULL)
- {
- char *canonbuf = __strdup (res.at->name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.canon = canonbuf;
- }
-
- struct gaih_addrtuple **pat = &res.at;
-
- 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)
- {
- struct gaih_addrtuple **pat = &res.at;
-
- 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
- && res.canon == NULL)
- {
- char *canonbuf = getcanonname (nip, res.at, name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.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;
-
- /* The hosts database does not support MERGE. */
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
- do_merge = true;
-
- 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 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;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- process_list:
- if (res.at == NULL)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
}
else
{
@@ -1086,6 +1095,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
+process_list:
{
/* Set up the canonical name if we need it. */
if ((result = process_canonname (req, orig_name, &res)) != 0)
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 09/12] gaih_inet: make gethosts into a function
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (7 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 10/12] gaih_inet: split loopback lookup into its own function Siddhesh Poyarekar
` (5 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
The macro is quite a pain to debug, so make gethosts into a function to
make it easier to maintain.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 117 ++++++++++++++++++------------------
1 file changed, 59 insertions(+), 58 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index b30af6bb7b..81710632cb 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -268,63 +268,54 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
return true;
}
-#define gethosts(_family) \
- { \
- struct hostent th; \
- char *localcanon = NULL; \
- no_data = 0; \
- while (1) \
- { \
- status = DL_CALL_FCT (fct, (name, _family, &th, \
- tmpbuf->data, tmpbuf->length, \
- &errno, &h_errno, NULL, &localcanon)); \
- if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \
- || errno != ERANGE) \
- break; \
- if (!scratch_buffer_grow (tmpbuf)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_MEMORY; \
- goto out; \
- } \
- } \
- if (status == NSS_STATUS_NOTFOUND \
- || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \
- { \
- if (h_errno == NETDB_INTERNAL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- if (h_errno == TRY_AGAIN) \
- no_data = EAI_AGAIN; \
- else \
- no_data = h_errno == NO_DATA; \
- } \
- else if (status == NSS_STATUS_SUCCESS) \
- { \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- \
- if (localcanon != NULL && res->canon == NULL) \
- { \
- char *canonbuf = __strdup (localcanon); \
- if (canonbuf == NULL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- res->canon = canonbuf; \
- } \
- } \
- }
+static int
+gethosts (nss_gethostbyname3_r fct, int family, const char *name,
+ const struct addrinfo *req, struct scratch_buffer *tmpbuf,
+ struct gaih_result *res, enum nss_status *statusp, int *no_datap)
+{
+ struct hostent th;
+ char *localcanon = NULL;
+ enum nss_status status;
+
+ *no_datap = 0;
+ while (1)
+ {
+ *statusp = status = DL_CALL_FCT (fct, (name, family, &th,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno, NULL,
+ &localcanon));
+ if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL
+ || errno != ERANGE)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+ if (status == NSS_STATUS_NOTFOUND
+ || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
+ {
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ *no_datap = EAI_AGAIN;
+ else
+ *no_datap = h_errno == NO_DATA;
+ }
+ else if (status == NSS_STATUS_SUCCESS)
+ {
+ if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
+ return -EAI_SYSTEM;
+
+ if (localcanon != NULL && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (localcanon);
+ if (canonbuf == NULL)
+ return -EAI_SYSTEM;
+ res->canon = canonbuf;
+ }
+ }
+ return 0;
+}
/* This function is called if a canonical name is requested, but if
the service function did not provide it. It tries to obtain the
@@ -741,7 +732,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
- gethosts (AF_INET6);
+ if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
no_inet6_data = no_data;
inet6_status = status;
}
@@ -753,7 +749,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
know we are not going to need them. */
&& ((req->ai_flags & AI_ALL) || !res->got_ipv6)))
{
- gethosts (AF_INET);
+ if ((result = gethosts (fct, AF_INET, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
if (req->ai_family == AF_INET)
{
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 10/12] gaih_inet: split loopback lookup into its own function
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (8 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 09/12] gaih_inet: make gethosts into a function Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 11/12] gaih_inet: Split result generation " Siddhesh Poyarekar
` (4 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Flatten the condition nesting and replace the alloca for RET.AT/ATR with
a single array LOCAL_AT[2]. This gets rid of alloca and alloca
accounting.
`git diff -b` is probably the best way to view this change since much of
the diff is whitespace changes.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 127 ++++++++++++++++++------------------
1 file changed, 62 insertions(+), 65 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 81710632cb..7258fa6f7e 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1002,6 +1002,32 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
return -EAI_NODATA;
}
+/* Add local address information into RES. RES->AT is assumed to have enough
+ space for two tuples and is zeroed out. */
+
+static void
+get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
+{
+ struct gaih_addrtuple *atr = res->at;
+ if (req->ai_family == AF_UNSPEC)
+ res->at->next = res->at + 1;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ res->at->family = AF_INET6;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ memcpy (res->at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+ atr = res->at->next;
+ }
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+ {
+ atr->family = AF_INET;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ atr->addr[0] = htonl (INADDR_LOOPBACK);
+ }
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1012,10 +1038,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
const char *orig_name = name;
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
-
int rc;
if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
return rc;
@@ -1025,76 +1047,51 @@ gaih_inet (const char *name, const struct gaih_service *service,
int result = 0;
struct gaih_result res = {0};
- if (name != NULL)
+ struct gaih_addrtuple local_at[2] = {0};
+
+ res.at = local_at;
+
+ if (__glibc_unlikely (name == NULL))
{
- if (req->ai_flags & AI_IDN)
- {
- char *out;
- result = __idna_to_dns_encoding (name, &out);
- if (result != 0)
- return -result;
- name = out;
- malloc_name = true;
- }
+ get_local_addresses (req, &res);
+ goto process_list;
+ }
- res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- res.at->scopeid = 0;
- res.at->next = NULL;
+ if (req->ai_flags & AI_IDN)
+ {
+ char *out;
+ result = __idna_to_dns_encoding (name, &out);
+ if (result != 0)
+ return -result;
+ name = out;
+ malloc_name = true;
+ }
- if ((result = text_to_binary_address (name, req, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = text_to_binary_address (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ 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;
+ if ((result = get_nscd_addresses (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
#endif
- if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
-
- /* None of the lookups worked, so name not found. */
- result = -EAI_NONAME;
- goto free_and_return;
- }
- else
- {
- struct gaih_addrtuple *atr;
- atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
- alloca_used);
- memset (res.at, '\0', sizeof (struct gaih_addrtuple));
-
- if (req->ai_family == AF_UNSPEC)
- {
- res.at->next = __alloca (sizeof (struct gaih_addrtuple));
- memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
- }
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- {
- res.at->family = AF_INET6;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
- atr = res.at->next;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- {
- atr->family = AF_INET;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- atr->addr[0] = htonl (INADDR_LOOPBACK);
- }
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
process_list:
{
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 11/12] gaih_inet: Split result generation into its own function
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (9 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 10/12] gaih_inet: split loopback lookup into its own function Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-08 10:07 ` [PATCH 12/12] gethosts: Return EAI_MEMORY on allocation failure Siddhesh Poyarekar
` (3 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
Simplify the loop a wee bit and clean up variable names too.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 176 ++++++++++++++++++------------------
1 file changed, 86 insertions(+), 90 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 7258fa6f7e..6cbbd5dac1 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1028,6 +1028,87 @@ get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
}
}
+/* Generate results in PAI and its count in NADDRS. Return 0 on success or an
+ error code on failure. */
+
+static int
+generate_addrinfo (const struct addrinfo *req, struct gaih_result *res,
+ const struct gaih_servtuple *st, struct addrinfo **pai,
+ unsigned int *naddrs)
+{
+ size_t socklen;
+ sa_family_t family;
+
+ /* Buffer is the size of an unformatted IPv6 address in printable format. */
+ for (struct gaih_addrtuple *at = res->at; at != NULL; at = at->next)
+ {
+ family = at->family;
+ if (family == AF_INET6)
+ {
+ socklen = sizeof (struct sockaddr_in6);
+
+ /* 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 (res->got_ipv6
+ && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ continue;
+ }
+ else
+ socklen = sizeof (struct sockaddr_in);
+
+ for (int i = 0; st[i].set; i++)
+ {
+ struct addrinfo *ai;
+ ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
+ if (ai == NULL)
+ return -EAI_MEMORY;
+
+ ai->ai_flags = req->ai_flags;
+ ai->ai_family = family;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
+ ai->ai_addrlen = socklen;
+ ai->ai_addr = (void *) (ai + 1);
+
+ /* We only add the canonical name once. */
+ ai->ai_canonname = res->canon;
+ res->canon = NULL;
+
+#ifdef _HAVE_SA_LEN
+ ai->ai_addr->sa_len = socklen;
+#endif /* _HAVE_SA_LEN */
+ ai->ai_addr->sa_family = family;
+
+ /* In case of an allocation error the list must be NULL
+ terminated. */
+ ai->ai_next = NULL;
+
+ if (family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) ai->ai_addr;
+ sin6p->sin6_port = st[i].port;
+ sin6p->sin6_flowinfo = 0;
+ memcpy (&sin6p->sin6_addr, at->addr, sizeof (struct in6_addr));
+ sin6p->sin6_scope_id = at->scopeid;
+ }
+ else
+ {
+ struct sockaddr_in *sinp = (struct sockaddr_in *) ai->ai_addr;
+ sinp->sin_port = st[i].port;
+ memcpy (&sinp->sin_addr, at->addr, sizeof (struct in_addr));
+ memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+ }
+
+ pai = &(ai->ai_next);
+ }
+
+ ++*naddrs;
+ }
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1094,98 +1175,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto free_and_return;
process_list:
- {
- /* Set up the canonical name if we need it. */
- if ((result = process_canonname (req, orig_name, &res)) != 0)
- goto free_and_return;
-
- struct gaih_addrtuple *at2 = res.at;
- size_t socklen;
- sa_family_t family;
-
- /*
- buffer is the size of an unformatted IPv6 address in printable format.
- */
- while (at2 != NULL)
- {
- family = at2->family;
- if (family == AF_INET6)
- {
- socklen = sizeof (struct sockaddr_in6);
-
- /* 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 (res.got_ipv6
- && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
- && IN6_IS_ADDR_V4MAPPED (at2->addr))
- goto ignore;
- }
- else
- socklen = sizeof (struct sockaddr_in);
-
- for (int i = 0; st[i].set; i++)
- {
- struct addrinfo *ai;
- ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
- if (ai == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
-
- ai->ai_flags = req->ai_flags;
- ai->ai_family = family;
- ai->ai_socktype = st[i].socktype;
- ai->ai_protocol = st[i].protocol;
- ai->ai_addrlen = socklen;
- ai->ai_addr = (void *) (ai + 1);
-
- /* We only add the canonical name once. */
- ai->ai_canonname = res.canon;
- res.canon = NULL;
-
-#ifdef _HAVE_SA_LEN
- ai->ai_addr->sa_len = socklen;
-#endif /* _HAVE_SA_LEN */
- ai->ai_addr->sa_family = family;
-
- /* In case of an allocation error the list must be NULL
- terminated. */
- ai->ai_next = NULL;
-
- if (family == AF_INET6)
- {
- struct sockaddr_in6 *sin6p =
- (struct sockaddr_in6 *) ai->ai_addr;
-
- sin6p->sin6_port = st[i].port;
- sin6p->sin6_flowinfo = 0;
- memcpy (&sin6p->sin6_addr,
- at2->addr, sizeof (struct in6_addr));
- sin6p->sin6_scope_id = at2->scopeid;
- }
- else
- {
- struct sockaddr_in *sinp =
- (struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st[i].port;
- memcpy (&sinp->sin_addr,
- at2->addr, sizeof (struct in_addr));
- memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
- }
-
- pai = &(ai->ai_next);
- }
-
- ++*naddrs;
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &res)) != 0)
+ goto free_and_return;
- ignore:
- at2 = at2->next;
- }
- }
+ result = generate_addrinfo (req, &res, st, pai, naddrs);
- free_and_return:
+free_and_return:
if (malloc_name)
free ((char *) name);
free (addrmem);
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 12/12] gethosts: Return EAI_MEMORY on allocation failure
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (10 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 11/12] gaih_inet: Split result generation " Siddhesh Poyarekar
@ 2022-03-08 10:07 ` Siddhesh Poyarekar
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (2 subsequent siblings)
14 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-08 10:07 UTC (permalink / raw)
To: libc-alpha; +Cc: carlos, fweimer
All other cases of failures due to lack of memory return EAI_MEMORY, so
it seems wrong to return EAI_SYSTEM here. The only reason
convert_hostent_to_gaih_addrtuple could fail is on calloc failure.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 6cbbd5dac1..7c7565ac6d 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -303,13 +303,13 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
else if (status == NSS_STATUS_SUCCESS)
{
if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
if (localcanon != NULL && res->canon == NULL)
{
char *canonbuf = __strdup (localcanon);
if (canonbuf == NULL)
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
res->canon = canonbuf;
}
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 00/12] getaddrinfo facelift and fixes
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (11 preceding siblings ...)
2022-03-08 10:07 ` [PATCH 12/12] gethosts: Return EAI_MEMORY on allocation failure Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-14 9:48 ` [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
` (11 more replies)
2022-03-14 13:21 ` [PATCH 00/12] getaddrinfo facelift and fixes Cristian Rodríguez
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
14 siblings, 12 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
The gaih_inet implementation, which forms the core of getaddrinfo, is
quite complex in its implementation, making it hard to follow or debug.
Particularly, allocations for gaih_addrtuples to store intermediate
results are particularly hard to track because of the way in which it is
written.
This patchset is an attempt at cleaning up the implementation to make it
much easier to follow. In the process, it also fixes a couple of bugs,
one that was the trigger for this cleanup and another that was
discovered during the cleanup.
Testing:
The leak reproducer in BZ #28852 could not be converted into a testsuite
test since mtrace isn't able to track the leak, so I separately verified
that it is fixed. There is a new test for #28931 which tests a variety
of combinations with SUCCESS=merge and SUCCESS=continue. Further, I
have built and done some smoke testing on Fedora with and without nscd
to ensure that there are no regressions resulting from this patchset.
Finally, I did a scratch build for Fedora and verified that there are no
new regressions on i686, x86_64, s390x, ppc64le and aarch64.
Changes from v1:
- Fixed nit: boolean coercion in convert_hostent_to_gaih_addrtuple
- Dropped DNS tests in tst-nss-gai-actions test since they are
unnecessary and the files tests are sufficient.
Siddhesh Poyarekar (12):
Simplify allocations and fix merge and continue actions [BZ #28931]
gaih_inet: Simplify canon name resolution
getaddrinfo: Fix leak with AI_ALL [BZ #28852]
gaih_inet: Simplify service resolution
gaih_inet: make numeric lookup a separate routine
gaih_inet: Split simple gethostbyname into its own function
gaih_inet: Split nscd lookup code into its own function.
gaih_inet: separate nss lookup loop into its own function
gaih_inet: make gethosts into a function
gaih_inet: split loopback lookup into its own function
gaih_inet: Split result generation into its own function
gethosts: Return EAI_MEMORY on allocation failure
nss/Makefile | 1 +
nss/tst-nss-gai-actions.c | 208 +++++
sysdeps/posix/getaddrinfo.c | 1518 ++++++++++++++++++-----------------
3 files changed, 1012 insertions(+), 715 deletions(-)
create mode 100644 nss/tst-nss-gai-actions.c
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-14 10:30 ` Andreas Schwab
2022-03-16 20:47 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 02/12] gaih_inet: Simplify canon name resolution Siddhesh Poyarekar
` (10 subsequent siblings)
11 siblings, 2 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Allocations for address tuples is currently a bit confusing because of
the pointer chasing through PAT, making it hard to observe the sequence
in which allocations have been made. Narrow scope of the pointer
chasing through PAT so that it is only used where necessary.
This also tightens actions behaviour with the hosts database in
getaddrinfo to comply with the manual text. The "continue" action
discards previous results and the "merge" action results in an immedate
lookup failure. Consequently, chaining of allocations across modules is
no longer necessary, thus opening up cleanup opportunities.
A test has been added that checks some combinations to ensure that they
work correctly.
Resolves: BZ #28931
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
nss/Makefile | 1 +
nss/tst-nss-gai-actions.c | 208 ++++++++++++++++++++++++++++++++++++
sysdeps/posix/getaddrinfo.c | 142 +++++++++++++++---------
3 files changed, 299 insertions(+), 52 deletions(-)
create mode 100644 nss/tst-nss-gai-actions.c
diff --git a/nss/Makefile b/nss/Makefile
index de439d4911..8ca69ed25b 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -79,6 +79,7 @@ tests += tst-nss-files-hosts-multi
tests += tst-nss-files-hosts-getent
tests += tst-nss-files-alias-leak
tests += tst-nss-files-alias-truncated
+tests += tst-nss-gai-actions
endif
# If we have a thread library then we can test cancellation against
diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
new file mode 100644
index 0000000000..f7f38f0032
--- /dev/null
+++ b/nss/tst-nss-gai-actions.c
@@ -0,0 +1,208 @@
+/* Test continue and merge NSS actions for getaddrinfo.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+enum
+{
+ ACTION_MERGE = 0,
+ ACTION_CONTINUE,
+};
+
+struct test_params
+{
+ int action;
+ int family;
+ bool canon;
+};
+
+struct support_chroot *chroot_env;
+
+static void
+prepare (int argc, char **argv)
+{
+ chroot_env = support_chroot_create
+ ((struct support_chroot_configuration)
+ {
+ .resolv_conf = "",
+ .hosts = "",
+ .host_conf = "multi on\n",
+ });
+}
+
+/* Create the /etc/hosts file from outside the chroot. */
+static void
+write_hosts (void)
+{
+ const int count = 512;
+
+ FILE *fp = xfopen (chroot_env->path_hosts, "w");
+ fputs ("127.0.0.1 localhost localhost.localdomain\n"
+ "::1 localhost localhost.localdomain\n",
+ fp);
+ for (int i = 1; i < count; ++i)
+ fprintf (fp, "192.0.%d.%d gnu.org\n", (i / 256) & 0xff, i & 0xff);
+ xfclose (fp);
+}
+
+static const char *
+family_str (int family)
+{
+ switch (family)
+ {
+ case AF_UNSPEC:
+ return "AF_UNSPEC";
+ case AF_INET:
+ return "AF_INET";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static const char *
+action_str (int action)
+{
+ switch (action)
+ {
+ case ACTION_MERGE:
+ return "merge";
+ case ACTION_CONTINUE:
+ return "continue";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+/* getaddrinfo test. To be run from a subprocess. */
+static void
+test_gai (void *closure)
+{
+ struct test_params *params = closure;
+
+ struct addrinfo hints =
+ {
+ .ai_family = params->family,
+ };
+
+ struct addrinfo *ai;
+
+ if (params->canon)
+ hints.ai_flags = AI_CANONNAME;
+
+ /* Use /etc/hosts in the chroot. */
+ xchroot (chroot_env->path_chroot);
+
+ printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
+ action_str (params->action), family_str (params->family),
+ params->canon ? "AI_CANONNAME" : "");
+
+ int ret = getaddrinfo ("gnu.org", "80", &hints, &ai);
+
+ switch (params->action)
+ {
+ case ACTION_MERGE:
+ if (ret == 0)
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ printf ("merge unexpectedly succeeded:\n %s\n", formatted);
+ support_record_failure ();
+ free (formatted);
+ }
+ else
+ return;
+ case ACTION_CONTINUE:
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ /* Verify that the result appears exactly once. */
+ const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
+ "address: DGRAM/UDP 192.0.0.1 80\n"
+ "address: RAW/IP 192.0.0.1 80\n";
+
+ const char *contains = strstr (formatted, expected);
+ const char *contains2 = NULL;
+
+ if (contains != NULL)
+ contains2 = strstr (contains + strlen (expected), expected);
+
+ if (contains == NULL || contains2 != NULL)
+ {
+ printf ("continue failed:\n%s\n", formatted);
+ support_record_failure ();
+ }
+
+ free (formatted);
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+test_in_subprocess (int action)
+{
+ char buf[32];
+
+ snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
+ action_str (action));
+ __nss_configure_lookup ("hosts", buf);
+
+ struct test_params params =
+ {
+ .action = action,
+ .family = AF_UNSPEC,
+ .canon = false,
+ };
+ support_isolate_in_subprocess (test_gai, ¶ms);
+ params.family = AF_INET;
+ support_isolate_in_subprocess (test_gai, ¶ms);
+ params.canon = true;
+ support_isolate_in_subprocess (test_gai, ¶ms);
+}
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ if (!support_can_chroot ())
+ FAIL_UNSUPPORTED ("Cannot chroot\n");
+
+ write_hosts ();
+ test_in_subprocess (ACTION_CONTINUE);
+ test_in_subprocess (ACTION_MERGE);
+
+ support_chroot_free (chroot_env);
+ return 0;
+}
+
+#define PREPARE prepare
+#include <support/test-driver.c>
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 18dccd5924..454a27eb2f 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -458,11 +458,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (name != NULL)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->family = AF_UNSPEC;
- at->scopeid = 0;
- at->next = NULL;
-
if (req->ai_flags & AI_IDN)
{
char *out;
@@ -473,13 +468,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ uint32_t addr[4];
+ if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
{
+ at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- at->family = AF_INET;
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET;
+ }
else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
{
- at->addr[3] = at->addr[0];
+ at->addr[3] = addr[0];
at->addr[2] = htonl (0xffff);
at->addr[1] = 0;
at->addr[0] = 0;
@@ -493,49 +496,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_flags & AI_CANONNAME)
canon = name;
+
+ goto process_list;
}
- else if (at->family == AF_UNSPEC)
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
+
+ if (e > 0)
{
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, at->addr);
+ at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET6;
+ }
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (addr))
+ {
+ at->addr[0] = addr[3];
+ at->addr[1] = addr[1];
+ at->addr[2] = addr[2];
+ at->addr[3] = addr[3];
+ at->family = AF_INET;
+ }
else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name,
- at->addr);
- if (e > 0)
{
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- at->family = AF_INET6;
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (at->addr))
- {
- at->addr[0] = at->addr[3];
- at->family = AF_INET;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
-
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_ADDRFAMILY;
+ goto free_and_return;
+ }
- if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1,
+ &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto free_and_return;
}
+
+ if (req->ai_flags & AI_CANONNAME)
+ canon = name;
+
+ goto process_list;
}
- if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
+ if ((req->ai_flags & AI_NUMERICHOST) == 0)
{
- struct gaih_addrtuple **pat = &at;
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -543,6 +559,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
enum nss_status status = NSS_STATUS_UNAVAIL;
int no_more;
struct resolv_context *res_ctx = NULL;
+ bool do_merge = false;
/* If we do not have to look for IPv6 addresses or the canonical
name, use the simple, old functions, which do not support
@@ -579,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
result = -EAI_MEMORY;
goto free_and_return;
}
- *pat = addrmem;
+ at = addrmem;
}
else
{
@@ -632,6 +649,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &at;
+
for (int i = 0; i < air->naddrs; ++i)
{
socklen_t size = (air->family[i] == AF_INET
@@ -695,12 +714,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
free (air);
- if (at->family == AF_UNSPEC)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
-
goto process_list;
}
else if (err == 0)
@@ -732,6 +745,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ at = NULL;
+ free (canonbuf);
+ free (addrmem);
+ canon = canonbuf = NULL;
+ addrmem = NULL;
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
no_data = 0;
nss_gethostbyname4_r *fct4 = NULL;
@@ -744,12 +772,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
while (1)
{
- status = DL_CALL_FCT (fct4, (name, pat,
+ status = DL_CALL_FCT (fct4, (name, &at,
tmpbuf->data, tmpbuf->length,
&errno, &h_errno,
NULL));
if (status == NSS_STATUS_SUCCESS)
break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ at = NULL;
if (status != NSS_STATUS_TRYAGAIN
|| errno != ERANGE || h_errno != NETDB_INTERNAL)
{
@@ -774,7 +804,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = (*pat)->name;
+ canon = at->name;
+
+ struct gaih_addrtuple **pat = &at;
while (*pat != NULL)
{
@@ -826,6 +858,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (fct != NULL)
{
+ struct gaih_addrtuple **pat = &at;
+
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
@@ -899,6 +933,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
nip++;
if (nip->module == NULL)
no_more = -1;
@@ -930,7 +968,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
process_list:
- if (at->family == AF_UNSPEC)
+ if (at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-14 9:48 ` [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
@ 2022-03-14 10:30 ` Andreas Schwab
2022-03-14 14:15 ` Siddhesh Poyarekar
2022-03-16 20:47 ` DJ Delorie
1 sibling, 1 reply; 68+ messages in thread
From: Andreas Schwab @ 2022-03-14 10:30 UTC (permalink / raw)
To: Siddhesh Poyarekar via Libc-alpha; +Cc: Siddhesh Poyarekar
On Mär 14 2022, Siddhesh Poyarekar via Libc-alpha wrote:
> + fprintf (fp, "192.0.%d.%d gnu.org\n", (i / 256) & 0xff, i & 0xff);
> + int ret = getaddrinfo ("gnu.org", "80", &hints, &ai);
Shouldn't that use example.org?
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1
"And now for something completely different."
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-14 10:30 ` Andreas Schwab
@ 2022-03-14 14:15 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 14:15 UTC (permalink / raw)
To: Andreas Schwab, Siddhesh Poyarekar via Libc-alpha
On 14/03/2022 16:00, Andreas Schwab wrote:
> On Mär 14 2022, Siddhesh Poyarekar via Libc-alpha wrote:
>
>> + fprintf (fp, "192.0.%d.%d gnu.org\n", (i / 256) & 0xff, i & 0xff);
>
>> + int ret = getaddrinfo ("gnu.org", "80", &hints, &ai);
>
> Shouldn't that use example.org?
>
Thanks, fixed in my local copy.
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-14 9:48 ` [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
2022-03-14 10:30 ` Andreas Schwab
@ 2022-03-16 20:47 ` DJ Delorie
2022-03-17 1:39 ` Siddhesh Poyarekar
1 sibling, 1 reply; 68+ messages in thread
From: DJ Delorie @ 2022-03-16 20:47 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
LGTM
Reviewed-by: DJ Delorie <dj@redhat.com>
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> diff --git a/nss/Makefile b/nss/Makefile
> +tests += tst-nss-gai-actions
New test OK.
> diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
> +enum
> +{
> + ACTION_MERGE = 0,
> + ACTION_CONTINUE,
> +};
> +
> +struct test_params
> +{
> + int action;
> + int family;
> + bool canon;
> +};
> +
> +struct support_chroot *chroot_env;
Ok.
> +static void
> +prepare (int argc, char **argv)
> +{
> + chroot_env = support_chroot_create
> + ((struct support_chroot_configuration)
> + {
> + .resolv_conf = "",
> + .hosts = "",
> + .host_conf = "multi on\n",
> + });
> +}
I'm curious why you chose to go this route rather than using the
test-container framework, which would have done most of this for you?
(but ok)
> +/* Create the /etc/hosts file from outside the chroot. */
> +static void
> +write_hosts (void)
> +{
> + const int count = 512;
> +
> + FILE *fp = xfopen (chroot_env->path_hosts, "w");
> + fputs ("127.0.0.1 localhost localhost.localdomain\n"
> + "::1 localhost localhost.localdomain\n",
> + fp);
> + for (int i = 1; i < count; ++i)
> + fprintf (fp, "192.0.%d.%d gnu.org\n", (i / 256) & 0xff, i & 0xff);
That's a lot of gnu.org :-)
> + xfclose (fp);
> +}
Ok.
> +static const char *
> +family_str (int family)
> +{
> + switch (family)
> + {
> + case AF_UNSPEC:
> + return "AF_UNSPEC";
> + case AF_INET:
> + return "AF_INET";
> + default:
> + __builtin_unreachable ();
> + }
> +}
Ok.
> +static const char *
> +action_str (int action)
> +{
> + switch (action)
> + {
> + case ACTION_MERGE:
> + return "merge";
> + case ACTION_CONTINUE:
> + return "continue";
> + default:
> + __builtin_unreachable ();
> + }
> +}
Ok.
> +/* getaddrinfo test. To be run from a subprocess. */
> +static void
> +test_gai (void *closure)
> +{
> + struct test_params *params = closure;
> +
> + struct addrinfo hints =
> + {
> + .ai_family = params->family,
> + };
> +
> + struct addrinfo *ai;
> +
> + if (params->canon)
> + hints.ai_flags = AI_CANONNAME;
> +
> + /* Use /etc/hosts in the chroot. */
> + xchroot (chroot_env->path_chroot);
> +
> + printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
> + action_str (params->action), family_str (params->family),
> + params->canon ? "AI_CANONNAME" : "");
> +
> + int ret = getaddrinfo ("gnu.org", "80", &hints, &ai);
> +
> + switch (params->action)
> + {
> + case ACTION_MERGE:
> + if (ret == 0)
> + {
> + char *formatted = support_format_addrinfo (ai, ret);
> +
> + printf ("merge unexpectedly succeeded:\n %s\n", formatted);
> + support_record_failure ();
> + free (formatted);
> + }
> + else
> + return;
> + case ACTION_CONTINUE:
> + {
> + char *formatted = support_format_addrinfo (ai, ret);
> +
> + /* Verify that the result appears exactly once. */
> + const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
> + "address: DGRAM/UDP 192.0.0.1 80\n"
> + "address: RAW/IP 192.0.0.1 80\n";
> +
> + const char *contains = strstr (formatted, expected);
> + const char *contains2 = NULL;
> +
> + if (contains != NULL)
> + contains2 = strstr (contains + strlen (expected), expected);
> +
> + if (contains == NULL || contains2 != NULL)
> + {
> + printf ("continue failed:\n%s\n", formatted);
> + support_record_failure ();
> + }
> +
> + free (formatted);
> + break;
> + }
> + default:
> + __builtin_unreachable ();
> + }
> +}
Ok.
> +static void
> +test_in_subprocess (int action)
> +{
> + char buf[32];
> +
> + snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
> + action_str (action));
> + __nss_configure_lookup ("hosts", buf);
> +
> + struct test_params params =
> + {
> + .action = action,
> + .family = AF_UNSPEC,
> + .canon = false,
> + };
> + support_isolate_in_subprocess (test_gai, ¶ms);
> + params.family = AF_INET;
> + support_isolate_in_subprocess (test_gai, ¶ms);
> + params.canon = true;
> + support_isolate_in_subprocess (test_gai, ¶ms);
> +}
Ok.
> +static int
> +do_test (void)
> +{
> + support_become_root ();
> + if (!support_can_chroot ())
> + FAIL_UNSUPPORTED ("Cannot chroot\n");
> +
> + write_hosts ();
> + test_in_subprocess (ACTION_CONTINUE);
> + test_in_subprocess (ACTION_MERGE);
> +
> + support_chroot_free (chroot_env);
> + return 0;
> +}
Ok.
> +#define PREPARE prepare
> +#include <support/test-driver.c>
Ok.
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> index 18dccd5924..454a27eb2f 100644
> --- a/sysdeps/posix/getaddrinfo.c
> +++ b/sysdeps/posix/getaddrinfo.c
> @@ -458,11 +458,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
>
> if (name != NULL)
> {
> - at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
> - at->family = AF_UNSPEC;
> - at->scopeid = 0;
> - at->next = NULL;
> -
Moved below, ok.
> - if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
> + uint32_t addr[4];
> + if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
Use temp buffer because not allocated, ok.
> + at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
> + at->scopeid = 0;
> + at->next = NULL;
> +
Ok.
> if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
> - at->family = AF_INET;
> + {
> + memcpy (at->addr, addr, sizeof (at->addr));
> + at->family = AF_INET;
> + }
Ok.
> else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
> {
> - at->addr[3] = at->addr[0];
> + at->addr[3] = addr[0];
Ok.
> @@ -493,49 +496,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
>
> if (req->ai_flags & AI_CANONNAME)
> canon = name;
> +
> + goto process_list;
ok.
> }
> - else if (at->family == AF_UNSPEC)
> +
> + char *scope_delim = strchr (name, SCOPE_DELIMITER);
> + int e;
> +
> + if (scope_delim == NULL)
> + e = inet_pton (AF_INET6, name, addr);
> + else
> + e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
Moved out of scope, ok.
> +
> + if (e > 0)
Moved up, ok.
> {
> - char *scope_delim = strchr (name, SCOPE_DELIMITER);
> - int e;
> - if (scope_delim == NULL)
> - e = inet_pton (AF_INET6, name, at->addr);
Move up, ok.
> + at = alloca_account (sizeof (struct gaih_addrtuple),
> + alloca_used);
> + at->scopeid = 0;
> + at->next = NULL;
> +
> + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
> + {
> + memcpy (at->addr, addr, sizeof (at->addr));
> + at->family = AF_INET6;
> + }
> + else if (req->ai_family == AF_INET
> + && IN6_IS_ADDR_V4MAPPED (addr))
> + {
> + at->addr[0] = addr[3];
> + at->addr[1] = addr[1];
> + at->addr[2] = addr[2];
> + at->addr[3] = addr[3];
> + at->family = AF_INET;
> + }
Moved, ok.
> else
> - e = __inet_pton_length (AF_INET6, name, scope_delim - name,
> - at->addr);
> - if (e > 0)
> {
> - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
> - at->family = AF_INET6;
> - else if (req->ai_family == AF_INET
> - && IN6_IS_ADDR_V4MAPPED (at->addr))
> - {
> - at->addr[0] = at->addr[3];
> - at->family = AF_INET;
> - }
> - else
> - {
> - result = -EAI_ADDRFAMILY;
> - goto free_and_return;
> - }
> -
> - if (scope_delim != NULL
> - && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
> - scope_delim + 1,
> - &at->scopeid) != 0)
> - {
> - result = -EAI_NONAME;
> - goto free_and_return;
> - }
Moved, ok.
> + result = -EAI_ADDRFAMILY;
> + goto free_and_return;
> + }
Moved, ok.
> - if (req->ai_flags & AI_CANONNAME)
> - canon = name;
> + if (scope_delim != NULL
> + && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
> + scope_delim + 1,
> + &at->scopeid) != 0)
> + {
> + result = -EAI_NONAME;
> + goto free_and_return;
Moved, ok.
> }
> +
> + if (req->ai_flags & AI_CANONNAME)
> + canon = name;
> +
> + goto process_list;
> }
Ok.
> - if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
> + if ((req->ai_flags & AI_NUMERICHOST) == 0)
Ok.
> {
> - struct gaih_addrtuple **pat = &at;
Ok.
> + bool do_merge = false;
Ok.
> @@ -579,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
> result = -EAI_MEMORY;
> goto free_and_return;
> }
> - *pat = addrmem;
> + at = addrmem;
Ok.
> struct gaih_addrtuple *addrfree = addrmem;
> + struct gaih_addrtuple **pat = &at;
> +
Ok.
> free (air);
>
> - if (at->family == AF_UNSPEC)
> - {
> - result = -EAI_NONAME;
> - goto free_and_return;
> - }
> -
Ok.
> @@ -732,6 +745,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
>
> while (!no_more)
> {
> + /* Always start afresh; continue should discard previous results
> + and the hosts database does not support merge. */
> + at = NULL;
> + free (canonbuf);
> + free (addrmem);
> + canon = canonbuf = NULL;
> + addrmem = NULL;
> +
> + if (do_merge)
> + {
> + __set_h_errno (NETDB_INTERNAL);
> + __set_errno (EBUSY);
> + break;
> + }
> +
Ok.
> - status = DL_CALL_FCT (fct4, (name, pat,
> + status = DL_CALL_FCT (fct4, (name, &at,
Ok.
> + /* gethostbyname4_r may write into AT, so reset it. */
> + at = NULL;
This is alloca-ted, so no leak here. ok.
> @@ -774,7 +804,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
> no_data = 1;
>
> if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
> - canon = (*pat)->name;
> + canon = at->name;
> +
> + struct gaih_addrtuple **pat = &at;
Ok.
> while (*pat != NULL)
> {
> @@ -826,6 +858,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
>
> if (fct != NULL)
> {
> + struct gaih_addrtuple **pat = &at;
> +
Ok.
> + /* The hosts database does not support MERGE. */
> + if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
> + do_merge = true;
> +
Ok.
> process_list:
> - if (at->family == AF_UNSPEC)
> + if (at == NULL)
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-16 20:47 ` DJ Delorie
@ 2022-03-17 1:39 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 1:39 UTC (permalink / raw)
To: DJ Delorie; +Cc: libc-alpha
On 17/03/2022 02:17, DJ Delorie wrote:
>> +static void
>> +prepare (int argc, char **argv)
>> +{
>> + chroot_env = support_chroot_create
>> + ((struct support_chroot_configuration)
>> + {
>> + .resolv_conf = "",
>> + .hosts = "",
>> + .host_conf = "multi on\n",
>> + });
>> +}
>
> I'm curious why you chose to go this route rather than using the
> test-container framework, which would have done most of this for you?
> (but ok)
I had initially written this test with dns *and* files modules and the
former required me to stay out of the container. Now that the dns
module bit is gone, I could put it back into a container.
I'll respin this patch because...
>
>> +/* Create the /etc/hosts file from outside the chroot. */
>> +static void
>> +write_hosts (void)
>> +{
>> + const int count = 512;
>> +
>> + FILE *fp = xfopen (chroot_env->path_hosts, "w");
>> + fputs ("127.0.0.1 localhost localhost.localdomain\n"
>> + "::1 localhost localhost.localdomain\n",
>> + fp);
>> + for (int i = 1; i < count; ++i)
>> + fprintf (fp, "192.0.%d.%d gnu.org\n", (i / 256) & 0xff, i & 0xff);
>
> That's a lot of gnu.org :-)
... Andreas suggested that I replace this with example.org.
Thanks,
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 02/12] gaih_inet: Simplify canon name resolution
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
2022-03-14 9:48 ` [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-16 21:12 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
` (9 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Simplify logic for allocation of canon to remove the canonbuf variable;
canon now always points to an allocated block. Also pull the canon name
set into a separate function.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 130 +++++++++++++++++++++---------------
1 file changed, 75 insertions(+), 55 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 454a27eb2f..df164a3e96 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -285,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
\
if (localcanon != NULL && canon == NULL) \
{ \
- canonbuf = __strdup (localcanon); \
+ char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
@@ -323,6 +323,41 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
return __strdup (name);
}
+/* Process looked up canonical name and if necessary, decode to IDNA. Result
+ is a new string written to CANONP and the earlier string is freed. */
+
+static int
+process_canonname (const struct addrinfo *req, const char *orig_name,
+ char **canonp)
+{
+ char *canon = *canonp;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0)
+ {
+ bool do_idn = req->ai_flags & AI_CANONIDN;
+ if (do_idn)
+ {
+ char *out;
+ int rc = __idna_from_dns_encoding (canon ?: orig_name, &out);
+ if (rc == 0)
+ {
+ free (canon);
+ canon = out;
+ }
+ else if (rc == EAI_IDN_ENCODE)
+ /* Use the punycode name as a fallback. */
+ do_idn = false;
+ else
+ return -rc;
+ }
+ if (!do_idn && canon == NULL && (canon = __strdup (orig_name)) == NULL)
+ return -EAI_MEMORY;
+ }
+
+ *canonp = canon;
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -332,7 +367,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
- const char *canon = NULL;
+ char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -453,7 +488,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
- char *canonbuf = NULL;
int result = 0;
if (name != NULL)
@@ -495,7 +529,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -545,7 +587,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -676,9 +726,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
(*pat)->next = NULL;
if (added_canon || air->canon == NULL)
(*pat)->name = NULL;
- else if (canonbuf == NULL)
+ else if (canon == NULL)
{
- canonbuf = __strdup (air->canon);
+ char *canonbuf = __strdup (air->canon);
if (canonbuf == NULL)
{
result = -EAI_MEMORY;
@@ -748,9 +798,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
/* Always start afresh; continue should discard previous results
and the hosts database does not support merge. */
at = NULL;
- free (canonbuf);
+ free (canon);
free (addrmem);
- canon = canonbuf = NULL;
+ canon = NULL;
addrmem = NULL;
if (do_merge)
@@ -804,7 +854,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = at->name;
+ {
+ char *canonbuf = __strdup (at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
struct gaih_addrtuple **pat = &at;
@@ -892,7 +951,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((req->ai_flags & AI_CANONNAME) != 0
&& canon == NULL)
{
- canonbuf = getcanonname (nip, at, name);
+ char *canonbuf = getcanonname (nip, at, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
@@ -1003,6 +1062,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
{
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &canon)) != 0)
+ goto free_and_return;
+
struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
@@ -1013,48 +1076,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
*/
while (at2 != NULL)
{
- /* Only the first entry gets the canonical name. */
- if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
- {
- if (canon == NULL)
- /* If the canonical name cannot be determined, use
- the passed in string. */
- canon = orig_name;
-
- bool do_idn = req->ai_flags & AI_CANONIDN;
- if (do_idn)
- {
- char *out;
- int rc = __idna_from_dns_encoding (canon, &out);
- if (rc == 0)
- canon = out;
- else if (rc == EAI_IDN_ENCODE)
- /* Use the punycode name as a fallback. */
- do_idn = false;
- else
- {
- result = -rc;
- goto free_and_return;
- }
- }
- if (!do_idn)
- {
- if (canonbuf != NULL)
- /* We already allocated the string using malloc, but
- the buffer is now owned by canon. */
- canonbuf = NULL;
- else
- {
- canon = __strdup (canon);
- if (canon == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
- }
- }
-
family = at2->family;
if (family == AF_INET6)
{
@@ -1077,7 +1098,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
if (ai == NULL)
{
- free ((char *) canon);
result = -EAI_MEMORY;
goto free_and_return;
}
@@ -1137,7 +1157,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canonbuf);
+ free (canon);
return result;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 02/12] gaih_inet: Simplify canon name resolution
2022-03-14 9:48 ` [PATCH v2 02/12] gaih_inet: Simplify canon name resolution Siddhesh Poyarekar
@ 2022-03-16 21:12 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-16 21:12 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> Simplify logic for allocation of canon to remove the canonbuf variable;
> canon now always points to an allocated block. Also pull the canon name
> set into a separate function.
LGTM.
Reviewed-by: DJ Delorie <dj@redhat.com>
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> - canonbuf = __strdup (localcanon); \
> + char *canonbuf = __strdup (localcanon); \
Ok.
> @@ -323,6 +323,41 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
> +/* Process looked up canonical name and if necessary, decode to IDNA. Result
> + is a new string written to CANONP and the earlier string is freed. */
> +
> +static int
> +process_canonname (const struct addrinfo *req, const char *orig_name,
> + char **canonp)
> +{
> + char *canon = *canonp;
> +
> + if ((req->ai_flags & AI_CANONNAME) != 0)
> + {
> + bool do_idn = req->ai_flags & AI_CANONIDN;
> + if (do_idn)
> + {
> + char *out;
> + int rc = __idna_from_dns_encoding (canon ?: orig_name, &out);
> + if (rc == 0)
> + {
> + free (canon);
> + canon = out;
> + }
> + else if (rc == EAI_IDN_ENCODE)
> + /* Use the punycode name as a fallback. */
> + do_idn = false;
> + else
> + return -rc;
> + }
> + if (!do_idn && canon == NULL && (canon = __strdup (orig_name)) == NULL)
> + return -EAI_MEMORY;
> + }
> +
> + *canonp = canon;
> + return 0;
> +}
Moved from below, ok.
> @@ -332,7 +367,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
> struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
> struct gaih_addrtuple *at = NULL;
> bool got_ipv6 = false;
> - const char *canon = NULL;
> + char *canon = NULL;
Ok.
> - char *canonbuf = NULL;
Ok.
> @@ -495,7 +529,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
> }
>
> if (req->ai_flags & AI_CANONNAME)
> - canon = name;
> + {
> + char *canonbuf = __strdup (name);
> + if (canonbuf == NULL)
> + {
> + result = -EAI_MEMORY;
> + goto free_and_return;
> + }
> + canon = canonbuf;
> + }
Ok.
> @@ -545,7 +587,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
> }
>
> if (req->ai_flags & AI_CANONNAME)
> - canon = name;
> + {
> + char *canonbuf = __strdup (name);
> + if (canonbuf == NULL)
> + {
> + result = -EAI_MEMORY;
> + goto free_and_return;
> + }
> + canon = canonbuf;
> + }
Ok.
> @@ -676,9 +726,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
> (*pat)->next = NULL;
> if (added_canon || air->canon == NULL)
> (*pat)->name = NULL;
> - else if (canonbuf == NULL)
> + else if (canon == NULL)
> {
> - canonbuf = __strdup (air->canon);
> + char *canonbuf = __strdup (air->canon);
Ok.
> @@ -748,9 +798,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
> /* Always start afresh; continue should discard previous results
> and the hosts database does not support merge. */
> at = NULL;
> - free (canonbuf);
> + free (canon);
> free (addrmem);
> - canon = canonbuf = NULL;
> + canon = NULL;
> addrmem = NULL;
Ok.
> @@ -804,7 +854,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
> no_data = 1;
>
> if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
> - canon = at->name;
> + {
> + char *canonbuf = __strdup (at->name);
> + if (canonbuf == NULL)
> + {
> + __resolv_context_put (res_ctx);
> + result = -EAI_MEMORY;
> + goto free_and_return;
> + }
> + canon = canonbuf;
> + }
Ok.
> @@ -892,7 +951,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
> if ((req->ai_flags & AI_CANONNAME) != 0
> && canon == NULL)
> {
> - canonbuf = getcanonname (nip, at, name);
> + char *canonbuf = getcanonname (nip, at, name);
Ok.
> @@ -1003,6 +1062,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
> }
>
> {
> + /* Set up the canonical name if we need it. */
> + if ((result = process_canonname (req, orig_name, &canon)) != 0)
> + goto free_and_return;
> +
Ok.
> @@ -1013,48 +1076,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
> */
> while (at2 != NULL)
> {
> - /* Only the first entry gets the canonical name. */
> - if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
> - {
> - if (canon == NULL)
> - /* If the canonical name cannot be determined, use
> - the passed in string. */
> - canon = orig_name;
> -
> - bool do_idn = req->ai_flags & AI_CANONIDN;
> - if (do_idn)
> - {
> - char *out;
> - int rc = __idna_from_dns_encoding (canon, &out);
> - if (rc == 0)
> - canon = out;
> - else if (rc == EAI_IDN_ENCODE)
> - /* Use the punycode name as a fallback. */
> - do_idn = false;
> - else
> - {
> - result = -rc;
> - goto free_and_return;
> - }
> - }
> - if (!do_idn)
> - {
> - if (canonbuf != NULL)
> - /* We already allocated the string using malloc, but
> - the buffer is now owned by canon. */
> - canonbuf = NULL;
> - else
> - {
> - canon = __strdup (canon);
> - if (canon == NULL)
> - {
> - result = -EAI_MEMORY;
> - goto free_and_return;
> - }
> - }
> - }
> - }
> -
Moved above; ok.
> @@ -1077,7 +1098,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
> ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
> if (ai == NULL)
> {
> - free ((char *) canon);
Ok.
> @@ -1137,7 +1157,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
> if (malloc_name)
> free ((char *) name);
> free (addrmem);
> - free (canonbuf);
> + free (canon);
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852]
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
2022-03-14 9:48 ` [PATCH v2 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
2022-03-14 9:48 ` [PATCH v2 02/12] gaih_inet: Simplify canon name resolution Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-16 23:42 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 04/12] gaih_inet: Simplify service resolution Siddhesh Poyarekar
` (8 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Use realloc in convert_hostent_to_gaih_addrtuple and fix up pointers in
the result list so that a single block is maintained for
hostbyname3_r/hostbyname2_r and freed in gaih_inet. This result is
never merged with any other results, since the hosts database does not
permit merging.
Resolves BZ #28852.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index df164a3e96..b0a64ead0e 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -199,9 +199,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
struct hostent *h,
struct gaih_addrtuple **result)
{
- while (*result)
- result = &(*result)->next;
-
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
for (char **p = h->h_addr_list; *p != NULL; ++p)
@@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = calloc (count, sizeof (*array));
+ struct gaih_addrtuple *array = *result;
+ size_t old = 0;
+
+ while (array != NULL)
+ {
+ old++;
+ array = array->next;
+ }
+
+ array = realloc (*result, (old + count) * sizeof (*array));
+
if (array == NULL)
return false;
+ *result = array;
+
+ /* Update the next pointers on reallocation. */
+ for (size_t i = 0; i < old; i++)
+ array[i].next = array + i + 1;
+
+ array += old;
+
+ memset (array, 0, count * sizeof (*array));
+
for (size_t i = 0; i < count; ++i)
{
if (family == AF_INET && req->ai_family == AF_INET6)
@@ -235,7 +252,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array[0].name = h->h_name;
array[count - 1].next = NULL;
- *result = array;
return true;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852]
2022-03-14 9:48 ` [PATCH v2 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
@ 2022-03-16 23:42 ` DJ Delorie
2022-03-17 2:30 ` Siddhesh Poyarekar
0 siblings, 1 reply; 68+ messages in thread
From: DJ Delorie @ 2022-03-16 23:42 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> Use realloc in convert_hostent_to_gaih_addrtuple and fix up pointers in
> the result list so that a single block is maintained for
> hostbyname3_r/hostbyname2_r and freed in gaih_inet. This result is
> never merged with any other results, since the hosts database does not
> permit merging.
It took me a while to realize that you're basically converting the data
structure from a linked list to an array, and ensuring that it's always
handled as an array. That means the comment preceeding
convert_hostent_to_gaih_addrtuple() is no longer accurate and needs
updating. Ideally, the users could be optimized to treat it as an array
instead of a list, but it may need to remain a list-like type for
compatibility.
LGTM with that comment change.
Reviewed-by: DJ Delorie <dj@redhat.com>
> - while (*result)
> - result = &(*result)->next;
> -
Don't skip to end of "list". Ok.
> @@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
> if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
> return true;
>
> - struct gaih_addrtuple *array = calloc (count, sizeof (*array));
> + struct gaih_addrtuple *array = *result;
> + size_t old = 0;
> +
> + while (array != NULL)
> + {
> + old++;
> + array = array->next;
> + }
> +
> + array = realloc (*result, (old + count) * sizeof (*array));
> +
Count existing members of *array* and resize base array. Ok. The rest
are initialized later, in the unchanged part of the code.
> if (array == NULL)
> return false;
>
> + *result = array;
> +
> + /* Update the next pointers on reallocation. */
> + for (size_t i = 0; i < old; i++)
> + array[i].next = array + i + 1;
> +
> + array += old;
> +
> + memset (array, 0, count * sizeof (*array));
> +
Ok.
> for (size_t i = 0; i < count; ++i)
> {
> if (family == AF_INET && req->ai_family == AF_INET6)
> @@ -235,7 +252,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
> array[0].name = h->h_name;
> array[count - 1].next = NULL;
>
> - *result = array;
> return true;
> }
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852]
2022-03-16 23:42 ` DJ Delorie
@ 2022-03-17 2:30 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 2:30 UTC (permalink / raw)
To: DJ Delorie; +Cc: libc-alpha
On 17/03/2022 05:12, DJ Delorie via Libc-alpha wrote:
> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
>> Use realloc in convert_hostent_to_gaih_addrtuple and fix up pointers in
>> the result list so that a single block is maintained for
>> hostbyname3_r/hostbyname2_r and freed in gaih_inet. This result is
>> never merged with any other results, since the hosts database does not
>> permit merging.
>
> It took me a while to realize that you're basically converting the data
> structure from a linked list to an array, and ensuring that it's always
> handled as an array. That means the comment preceeding
> convert_hostent_to_gaih_addrtuple() is no longer accurate and needs
> updating. Ideally, the users could be optimized to treat it as an array
> instead of a list, but it may need to remain a list-like type for
> compatibility.
Thanks, I'll update the comment.
Thanks,
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 04/12] gaih_inet: Simplify service resolution
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (2 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 0:48 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 05/12] gaih_inet: make numeric lookup a separate routine Siddhesh Poyarekar
` (7 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Refactor the code to split out the service resolution code into a
separate function. Allocate the service tuples array just once to the
size of the typeproto array, thus avoiding the unnecessary pointer
chasing and stack allocations.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 178 ++++++++++++++++--------------------
1 file changed, 78 insertions(+), 100 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index b0a64ead0e..936fa64d17 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -100,14 +100,12 @@ struct gaih_service
struct gaih_servtuple
{
- struct gaih_servtuple *next;
int socktype;
int protocol;
int port;
+ bool set;
};
-static const struct gaih_servtuple nullserv;
-
struct gaih_typeproto
{
@@ -180,11 +178,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
while (r);
- st->next = NULL;
st->socktype = tp->socktype;
st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
? req->ai_protocol : tp->protocol);
st->port = s->s_port;
+ st->set = true;
return 0;
}
@@ -375,20 +373,11 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
}
static int
-gaih_inet (const char *name, const struct gaih_service *service,
- const struct addrinfo *req, struct addrinfo **pai,
- unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
+ struct gaih_servtuple *st, struct scratch_buffer *tmpbuf)
{
+ int i;
const struct gaih_typeproto *tp = gaih_inet_typeproto;
- struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
- struct gaih_addrtuple *at = NULL;
- bool got_ipv6 = false;
- char *canon = NULL;
- const char *orig_name = name;
-
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
if (req->ai_protocol || req->ai_socktype)
{
@@ -410,98 +399,88 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
- int port = 0;
- if (service != NULL)
+ if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ return -EAI_SERVICE;
+
+ if (service == NULL || service->num >= 0)
{
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- return -EAI_SERVICE;
+ int port = service != NULL ? htons (service->num) : 0;
- if (service->num < 0)
+ if (req->ai_socktype || req->ai_protocol)
{
- if (tp->name[0])
- {
- st = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple), alloca_used);
-
- int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- if (__glibc_unlikely (rc != 0))
- return rc;
- }
- else
- {
- struct gaih_servtuple **pst = &st;
- for (tp++; tp->name[0]; tp++)
- {
- struct gaih_servtuple *newp;
+ st[0].socktype = tp->socktype;
+ st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+ ? req->ai_protocol : tp->protocol);
+ st[0].port = port;
+ st[0].set = true;
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- continue;
+ return 0;
+ }
- if (req->ai_socktype != 0
- && req->ai_socktype != tp->socktype)
- continue;
- if (req->ai_protocol != 0
- && !(tp->protoflag & GAI_PROTO_PROTOANY)
- && req->ai_protocol != tp->protocol)
- continue;
+ /* Neither socket type nor protocol is set. Return all socket types
+ we know about. */
+ for (i = 0, ++tp; tp->name[0]; ++tp)
+ if (tp->defaultflag)
+ {
+ st[i].socktype = tp->socktype;
+ st[i].protocol = tp->protocol;
+ st[i].port = port;
+ st[i++].set = true;
+ }
- newp = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
+ return 0;
+ }
- if (gaih_inet_serv (service->name,
- tp, req, newp, tmpbuf) != 0)
- continue;
+ if (tp->name[0])
+ return gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- *pst = newp;
- pst = &(newp->next);
- }
- if (st == (struct gaih_servtuple *) &nullserv)
- return -EAI_SERVICE;
- }
- }
- else
- {
- port = htons (service->num);
- goto got_port;
- }
- }
- else
+ for (i = 0, tp++; tp->name[0]; tp++)
{
- got_port:
+ if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ continue;
- if (req->ai_socktype || req->ai_protocol)
- {
- st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
- st->next = NULL;
- st->socktype = tp->socktype;
- st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
- ? req->ai_protocol : tp->protocol);
- st->port = port;
- }
- else
- {
- /* Neither socket type nor protocol is set. Return all socket types
- we know about. */
- struct gaih_servtuple **lastp = &st;
- for (++tp; tp->name[0]; ++tp)
- if (tp->defaultflag)
- {
- struct gaih_servtuple *newp;
+ if (req->ai_socktype != 0
+ && req->ai_socktype != tp->socktype)
+ continue;
+ if (req->ai_protocol != 0
+ && !(tp->protoflag & GAI_PROTO_PROTOANY)
+ && req->ai_protocol != tp->protocol)
+ continue;
- newp = alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
- newp->next = NULL;
- newp->socktype = tp->socktype;
- newp->protocol = tp->protocol;
- newp->port = port;
+ if (gaih_inet_serv (service->name,
+ tp, req, &st[i], tmpbuf) != 0)
+ continue;
- *lastp = newp;
- lastp = &newp->next;
- }
- }
+ i++;
}
+ if (!st[0].set)
+ return -EAI_SERVICE;
+
+ return 0;
+}
+
+static int
+gaih_inet (const char *name, const struct gaih_service *service,
+ const struct addrinfo *req, struct addrinfo **pai,
+ unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+{
+ struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
+ / sizeof (struct gaih_typeproto)] = {0};
+
+ struct gaih_addrtuple *at = NULL;
+ bool got_ipv6 = false;
+ char *canon = NULL;
+ const char *orig_name = name;
+
+ /* Reserve stack memory for the scratch buffer in the getaddrinfo
+ function. */
+ size_t alloca_used = sizeof (struct scratch_buffer);
+
+ int rc;
+ if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
+ return rc;
+
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
@@ -1082,7 +1061,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((result = process_canonname (req, orig_name, &canon)) != 0)
goto free_and_return;
- struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
sa_family_t family;
@@ -1108,7 +1086,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
socklen = sizeof (struct sockaddr_in);
- for (st2 = st; st2 != NULL; st2 = st2->next)
+ for (int i = 0; st[i].set; i++)
{
struct addrinfo *ai;
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
@@ -1120,8 +1098,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_flags = req->ai_flags;
ai->ai_family = family;
- ai->ai_socktype = st2->socktype;
- ai->ai_protocol = st2->protocol;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
ai->ai_addrlen = socklen;
ai->ai_addr = (void *) (ai + 1);
@@ -1143,7 +1121,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) ai->ai_addr;
- sin6p->sin6_port = st2->port;
+ sin6p->sin6_port = st[i].port;
sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr));
@@ -1153,7 +1131,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
struct sockaddr_in *sinp =
(struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st2->port;
+ sinp->sin_port = st[i].port;
memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr));
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 04/12] gaih_inet: Simplify service resolution
2022-03-14 9:48 ` [PATCH v2 04/12] gaih_inet: Simplify service resolution Siddhesh Poyarekar
@ 2022-03-17 0:48 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 0:48 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> Refactor the code to split out the service resolution code into a
> separate function. Allocate the service tuples array just once to the
> size of the typeproto array, thus avoiding the unnecessary pointer
> chasing and stack allocations.
LGTM
Reviewed-by: DJ Delorie <dj@redhat.com>
> struct gaih_servtuple
> {
> - struct gaih_servtuple *next;
> int socktype;
> int protocol;
> int port;
> + bool set;
> };
>
> -static const struct gaih_servtuple nullserv;
> -
Ok.
> @@ -180,11 +178,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
> }
> while (r);
>
> - st->next = NULL;
> st->socktype = tp->socktype;
> st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
> ? req->ai_protocol : tp->protocol);
> st->port = s->s_port;
> + st->set = true;
Ok.
> @@ -375,20 +373,11 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
> }
>
> static int
> -gaih_inet (const char *name, const struct gaih_service *service,
> - const struct addrinfo *req, struct addrinfo **pai,
> - unsigned int *naddrs, struct scratch_buffer *tmpbuf)
> +get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
> + struct gaih_servtuple *st, struct scratch_buffer *tmpbuf)
> {
Split out but the names of passed variables remain the same; ok.
> + int i;
> const struct gaih_typeproto *tp = gaih_inet_typeproto;
> - struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
> - struct gaih_addrtuple *at = NULL;
> - bool got_ipv6 = false;
> - char *canon = NULL;
> - const char *orig_name = name;
> -
> - /* Reserve stack memory for the scratch buffer in the getaddrinfo
> - function. */
> - size_t alloca_used = sizeof (struct scratch_buffer);
This part done in the parent function; ok.
> @@ -410,98 +399,88 @@ gaih_inet (const char *name, const struct gaih_service *service,
> }
> }
>
> - int port = 0;
> - if (service != NULL)
> + if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
> + return -EAI_SERVICE;
> +
> + if (service == NULL || service->num >= 0)
> {
> - if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
> - return -EAI_SERVICE;
> + int port = service != NULL ? htons (service->num) : 0;
Ok.
> + if (req->ai_socktype || req->ai_protocol)
> {
> + st[0].socktype = tp->socktype;
> + st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
> + ? req->ai_protocol : tp->protocol);
> + st[0].port = port;
> + st[0].set = true;
> + return 0;
> + }
ok.
> + /* Neither socket type nor protocol is set. Return all socket types
> + we know about. */
> + for (i = 0, ++tp; tp->name[0]; ++tp)
> + if (tp->defaultflag)
> + {
> + st[i].socktype = tp->socktype;
> + st[i].protocol = tp->protocol;
> + st[i].port = port;
> + st[i++].set = true;
> + }
Ok.
> - if (service->num < 0)
> - if (tp->name[0])
> - {
> - st = (struct gaih_servtuple *)
> - alloca_account (sizeof (struct gaih_servtuple), alloca_used);
> -
> - int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf);
> - if (__glibc_unlikely (rc != 0))
> - return rc;
> - }
> - else
> - {
> - struct gaih_servtuple **pst = &st;
> - for (tp++; tp->name[0]; tp++)
> - {
> - struct gaih_servtuple *newp;
>
> - if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
> - continue;
>
> - if (req->ai_socktype != 0
> - && req->ai_socktype != tp->socktype)
> - continue;
> - if (req->ai_protocol != 0
> - && !(tp->protoflag & GAI_PROTO_PROTOANY)
> - && req->ai_protocol != tp->protocol)
> - continue;
>
> - newp = (struct gaih_servtuple *)
> - alloca_account (sizeof (struct gaih_servtuple),
> - alloca_used);
> + return 0;
> + }
Ok.
> - if (gaih_inet_serv (service->name,
> - tp, req, newp, tmpbuf) != 0)
> - continue;
Ok.
> + if (tp->name[0])
> + return gaih_inet_serv (service->name, tp, req, st, tmpbuf);
Ok.
> + for (i = 0, tp++; tp->name[0]; tp++)
> + if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
> + continue;
> + if (req->ai_socktype != 0
> + && req->ai_socktype != tp->socktype)
> + continue;
> + if (req->ai_protocol != 0
> + && !(tp->protoflag & GAI_PROTO_PROTOANY)
> + && req->ai_protocol != tp->protocol)
> + continue;
> + if (gaih_inet_serv (service->name,
> + tp, req, &st[i], tmpbuf) != 0)
> + continue;
> + i++;
> + if (!st[0].set)
> + return -EAI_SERVICE;
> +
> + return 0;
> +}
Ok.
> - *pst = newp;
> - pst = &(newp->next);
> - }
> - if (st == (struct gaih_servtuple *) &nullserv)
> - return -EAI_SERVICE;
> - }
> - }
> - else
> - {
> - port = htons (service->num);
> - goto got_port;
> - }
> - }
> - else
> {
> - got_port:
>
> - if (req->ai_socktype || req->ai_protocol)
> - {
> - st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
> - st->next = NULL;
> - st->socktype = tp->socktype;
> - st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
> - ? req->ai_protocol : tp->protocol);
> - st->port = port;
> - }
> - else
> - {
> - /* Neither socket type nor protocol is set. Return all socket types
> - we know about. */
> - struct gaih_servtuple **lastp = &st;
> - for (++tp; tp->name[0]; ++tp)
> - if (tp->defaultflag)
> - {
> - struct gaih_servtuple *newp;
>
> - newp = alloca_account (sizeof (struct gaih_servtuple),
> - alloca_used);
> - newp->next = NULL;
> - newp->socktype = tp->socktype;
> - newp->protocol = tp->protocol;
> - newp->port = port;
>
> - *lastp = newp;
> - lastp = &newp->next;
> - }
> - }
> }
Ok.
> +
> +static int
> +gaih_inet (const char *name, const struct gaih_service *service,
> + const struct addrinfo *req, struct addrinfo **pai,
> + unsigned int *naddrs, struct scratch_buffer *tmpbuf)
> +{
> + struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
> + / sizeof (struct gaih_typeproto)] = {0};
> +
> + struct gaih_addrtuple *at = NULL;
> + bool got_ipv6 = false;
> + char *canon = NULL;
> + const char *orig_name = name;
> +
> + /* Reserve stack memory for the scratch buffer in the getaddrinfo
> + function. */
> + size_t alloca_used = sizeof (struct scratch_buffer);
> +
> + int rc;
> + if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
> + return rc;
> +
Ok.
> - struct gaih_servtuple *st2;
Ok.
> - for (st2 = st; st2 != NULL; st2 = st2->next)
> + for (int i = 0; st[i].set; i++)
Ok.
> - ai->ai_socktype = st2->socktype;
> - ai->ai_protocol = st2->protocol;
> + ai->ai_socktype = st[i].socktype;
> + ai->ai_protocol = st[i].protocol;
Ok.
> - sin6p->sin6_port = st2->port;
> + sin6p->sin6_port = st[i].port;
Ok.
> - sinp->sin_port = st2->port;
> + sinp->sin_port = st[i].port;
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 05/12] gaih_inet: make numeric lookup a separate routine
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (3 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 04/12] gaih_inet: Simplify service resolution Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 4:10 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 06/12] gaih_inet: Split simple gethostbyname into its own function Siddhesh Poyarekar
` (6 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Introduce the gaih_result structure and general paradigm for cleanups
that follow to process the lookup request and return a result. A lookup
function (like text_to_binary_address), should return an integer error
code and set members of gaih_result based on what it finds. If the
function does not have a result and no errors have occurred during the
lookup, it should return 0 and res.at should be set to NULL, allowing a
subsequent function to do the lookup until we run out of options.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 889 ++++++++++++++++++------------------
1 file changed, 451 insertions(+), 438 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 936fa64d17..d7b6eae9fc 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -116,6 +116,12 @@ struct gaih_typeproto
char name[8];
};
+struct gaih_result
+{
+ struct gaih_addrtuple *at;
+ char *canon;
+};
+
/* Values for `protoflag'. */
#define GAI_PROTO_NOSERVICE 1
#define GAI_PROTO_PROTOANY 2
@@ -297,7 +303,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
*pat = addrmem; \
\
- if (localcanon != NULL && canon == NULL) \
+ if (localcanon != NULL && res.canon == NULL) \
{ \
char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
@@ -306,7 +312,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
result = -EAI_SYSTEM; \
goto free_and_return; \
} \
- canon = canonbuf; \
+ res.canon = canonbuf; \
} \
if (_family == AF_INET6 && *pat != NULL) \
got_ipv6 = true; \
@@ -342,9 +348,9 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
static int
process_canonname (const struct addrinfo *req, const char *orig_name,
- char **canonp)
+ struct gaih_result *res)
{
- char *canon = *canonp;
+ char *canon = res->canon;
if ((req->ai_flags & AI_CANONNAME) != 0)
{
@@ -368,7 +374,7 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
return -EAI_MEMORY;
}
- *canonp = canon;
+ res->canon = canon;
return 0;
}
@@ -460,6 +466,105 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
return 0;
}
+/* 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
+ returned. */
+
+static int
+text_to_binary_address (const char *name, const struct addrinfo *req,
+ struct gaih_result *res)
+{
+ struct gaih_addrtuple *at = res->at;
+ int result = 0;
+
+ assert (at != NULL);
+
+ memset (at->addr, 0, sizeof (at->addr));
+ if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ {
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+ at->family = AF_INET;
+ else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
+ {
+ at->addr[3] = at->addr[0];
+ at->addr[2] = htonl (0xffff);
+ at->addr[1] = 0;
+ at->addr[0] = 0;
+ at->family = AF_INET6;
+ }
+ else
+ {
+ result = -EAI_ADDRFAMILY;
+ goto out;
+ }
+
+ if (req->ai_flags & AI_CANONNAME)
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+ return 0;
+ }
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, at->addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, at->addr);
+
+ if (e > 0)
+ {
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ at->family = AF_INET6;
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ {
+ at->addr[0] = at->addr[3];
+ at->family = AF_INET;
+ }
+ else
+ {
+ result = -EAI_ADDRFAMILY;
+ goto out;
+ }
+
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1, &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto out;
+ }
+
+ if (req->ai_flags & AI_CANONNAME)
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+ return 0;
+ }
+
+ if ((req->ai_flags & AI_NUMERICHOST))
+ result = -EAI_NONAME;
+
+out:
+ res->at = NULL;
+ return result;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -468,9 +573,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
/ sizeof (struct gaih_typeproto)] = {0};
- struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
- char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -485,6 +588,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
+ struct gaih_result res = {0};
if (name != NULL)
{
if (req->ai_flags & AI_IDN)
@@ -497,532 +601,440 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- uint32_t addr[4];
- if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
+ res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ res.at->scopeid = 0;
+ res.at->next = NULL;
+
+ if ((result = text_to_binary_address (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+
+ 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;
+ bool do_merge = false;
+
+ /* If we do not have to look for IPv6 addresses or the canonical
+ name, use the simple, old functions, which do not support
+ IPv6 scope ids, nor retrieving the canonical name. */
+ if (req->ai_family == AF_INET
+ && (req->ai_flags & AI_CANONNAME) == 0)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->scopeid = 0;
- at->next = NULL;
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- {
- memcpy (at->addr, addr, sizeof (at->addr));
- at->family = AF_INET;
- }
- else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
- {
- at->addr[3] = addr[0];
- at->addr[2] = htonl (0xffff);
- at->addr[1] = 0;
- at->addr[0] = 0;
- at->family = AF_INET6;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
+ int rc;
+ struct hostent th;
+ struct hostent *h;
- if (req->ai_flags & AI_CANONNAME)
+ while (1)
{
- char *canonbuf = __strdup (name);
- if (canonbuf == NULL)
+ rc = __gethostbyname2_r (name, AF_INET, &th,
+ tmpbuf->data, tmpbuf->length,
+ &h, &h_errno);
+ if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
{
result = -EAI_MEMORY;
goto free_and_return;
}
- canon = canonbuf;
}
- goto process_list;
- }
-
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
-
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, addr);
- else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
-
- if (e > 0)
- {
- at = alloca_account (sizeof (struct gaih_addrtuple),
- alloca_used);
- at->scopeid = 0;
- at->next = NULL;
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- {
- memcpy (at->addr, addr, sizeof (at->addr));
- at->family = AF_INET6;
- }
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (addr))
+ if (rc == 0)
{
- at->addr[0] = addr[3];
- at->addr[1] = addr[1];
- at->addr[2] = addr[2];
- at->addr[3] = addr[3];
- at->family = AF_INET;
+ if (h != NULL)
+ {
+ /* We found data, convert it. */
+ if (!convert_hostent_to_gaih_addrtuple
+ (req, AF_INET, h, &addrmem))
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ res.at = addrmem;
+ }
+ else
+ {
+ if (h_errno == NO_DATA)
+ result = -EAI_NODATA;
+ else
+ result = -EAI_NONAME;
+ goto free_and_return;
+ }
}
else
{
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
+ if (h_errno == NETDB_INTERNAL)
+ result = -EAI_SYSTEM;
+ else if (h_errno == TRY_AGAIN)
+ result = -EAI_AGAIN;
+ else
+ /* We made requests but they turned out no data.
+ The name is known, though. */
+ result = -EAI_NODATA;
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
goto free_and_return;
}
- if (req->ai_flags & AI_CANONNAME)
+ goto process_list;
+ }
+
+#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)
{
- char *canonbuf = __strdup (name);
- if (canonbuf == 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;
}
- canon = canonbuf;
- }
- goto process_list;
- }
-
- if ((req->ai_flags & AI_NUMERICHOST) == 0)
- {
- 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;
- bool do_merge = false;
-
- /* If we do not have to look for IPv6 addresses or the canonical
- name, use the simple, old functions, which do not support
- IPv6 scope ids, nor retrieving the canonical name. */
- if (req->ai_family == AF_INET
- && (req->ai_flags & AI_CANONNAME) == 0)
- {
- int rc;
- struct hostent th;
- struct hostent *h;
+ struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &res.at;
- while (1)
+ for (int i = 0; i < air->naddrs; ++i)
{
- rc = __gethostbyname2_r (name, AF_INET, &th,
- tmpbuf->data, tmpbuf->length,
- &h, &h_errno);
- if (rc != ERANGE || h_errno != NETDB_INTERNAL)
- break;
- if (!scratch_buffer_grow (tmpbuf))
+ 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))
{
- result = -EAI_MEMORY;
- goto free_and_return;
+ /* Skip over non-matching result. */
+ addrs += size;
+ continue;
}
- }
- if (rc == 0)
- {
- if (h != NULL)
+ 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)
{
- /* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple
- (req, AF_INET, h, &addrmem))
+ char *canonbuf = __strdup (air->canon);
+ if (canonbuf == NULL)
{
result = -EAI_MEMORY;
goto free_and_return;
}
- at = addrmem;
+ res.canon = (*pat)->name = canonbuf;
}
- else
+
+ if (air->family[i] == AF_INET
+ && req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED))
{
- if (h_errno == NO_DATA)
- result = -EAI_NODATA;
- else
- result = -EAI_NONAME;
- goto free_and_return;
+ (*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;
}
- else
- {
- if (h_errno == NETDB_INTERNAL)
- result = -EAI_SYSTEM;
- else if (h_errno == TRY_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;
- }
+ 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;
-#ifdef USE_NSCD
- if (__nss_not_use_nscd_hosts > 0
- && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
- __nss_not_use_nscd_hosts = 0;
+ goto free_and_return;
+ }
+ }
+#endif
+
+ no_more = !__nss_database_get (nss_database_hosts, &nip);
- if (!__nss_not_use_nscd_hosts
- && !__nss_database_custom[NSS_DBSIDX_hosts])
+ /* 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)
+ {
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ res.at = NULL;
+ free (res.canon);
+ free (addrmem);
+ res.canon = NULL;
+ addrmem = NULL;
+
+ if (do_merge)
{
- /* Try to use nscd. */
- struct nscd_ai_result *air = NULL;
- int err = __nscd_getai (name, &air, &h_errno);
- if (air != NULL)
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
+ 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)
+ {
+ while (1)
{
- /* Transform into gaih_addrtuple list. */
- bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
- char *addrs = air->addrs;
+ status = DL_CALL_FCT (fct4, (name, &res.at,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno,
+ NULL));
+ if (status == NSS_STATUS_SUCCESS)
+ break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ res.at = NULL;
+ 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;
+ }
- addrmem = calloc (air->naddrs, sizeof (*addrmem));
- if (addrmem == NULL)
+ if (!scratch_buffer_grow (tmpbuf))
{
+ __resolv_context_put (res_ctx);
result = -EAI_MEMORY;
goto free_and_return;
}
+ }
- struct gaih_addrtuple *addrfree = addrmem;
- struct gaih_addrtuple **pat = &at;
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ assert (!no_data);
+ no_data = 1;
- for (int i = 0; i < air->naddrs; ++i)
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL)
{
- 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))
+ char *canonbuf = __strdup (res.at->name);
+ if (canonbuf == NULL)
{
- /* Skip over non-matching result. */
- addrs += size;
- continue;
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto free_and_return;
}
+ res.canon = canonbuf;
+ }
- 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 (canon == NULL)
- {
- char *canonbuf = __strdup (air->canon);
- if (canonbuf == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- canon = (*pat)->name = canonbuf;
- }
+ struct gaih_addrtuple **pat = &res.at;
- if (air->family[i] == AF_INET
+ while (*pat != NULL)
+ {
+ if ((*pat)->family == AF_INET
&& req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED))
+ && (req->ai_flags & AI_V4MAPPED) != 0)
{
+ uint32_t *pataddr = (*pat)->addr;
(*pat)->family = AF_INET6;
- pataddr[3] = *(uint32_t *) addrs;
+ pataddr[3] = pataddr[0];
pataddr[2] = htonl (0xffff);
pataddr[1] = 0;
pataddr[0] = 0;
pat = &((*pat)->next);
- added_canon = true;
+ no_data = 0;
}
else if (req->ai_family == AF_UNSPEC
- || air->family[i] == req->ai_family)
+ || (*pat)->family == req->ai_family)
{
- (*pat)->family = air->family[i];
- memcpy (pataddr, addrs, size);
pat = &((*pat)->next);
- added_canon = true;
- if (air->family[i] == AF_INET6)
+
+ no_data = 0;
+ if (req->ai_family == AF_INET6)
got_ipv6 = true;
}
- addrs += size;
+ else
+ *pat = ((*pat)->next);
}
-
- 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;
- }
+ no_inet6_data = no_data;
}
-#endif
-
- 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)
+ else
{
- /* Always start afresh; continue should discard previous results
- and the hosts database does not support merge. */
- at = NULL;
- free (canon);
- free (addrmem);
- canon = NULL;
- addrmem = NULL;
-
- if (do_merge)
+ 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)
{
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- break;
- }
-
- 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");
+ struct gaih_addrtuple **pat = &res.at;
- if (fct4 != NULL)
- {
- while (1)
+ if (req->ai_family == AF_INET6
+ || req->ai_family == AF_UNSPEC)
{
- status = DL_CALL_FCT (fct4, (name, &at,
- tmpbuf->data, tmpbuf->length,
- &errno, &h_errno,
- NULL));
- if (status == NSS_STATUS_SUCCESS)
- break;
- /* gethostbyname4_r may write into AT, so reset it. */
- at = NULL;
- 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;
- }
+ 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 (!scratch_buffer_grow (tmpbuf))
+ if (req->ai_family == AF_INET)
{
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
+ no_inet6_data = no_data;
+ inet6_status = status;
}
}
- if (status == NSS_STATUS_SUCCESS)
+ /* 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)
{
- assert (!no_data);
- no_data = 1;
-
- if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
+ if ((req->ai_flags & AI_CANONNAME) != 0
+ && res.canon == NULL)
{
- char *canonbuf = __strdup (at->name);
+ char *canonbuf = getcanonname (nip, res.at, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
result = -EAI_MEMORY;
goto free_and_return;
}
- canon = canonbuf;
- }
-
- struct gaih_addrtuple **pat = &at;
-
- 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)
- {
- struct gaih_addrtuple **pat = &at;
-
- 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;
+ res.canon = canonbuf;
}
+ status = NSS_STATUS_SUCCESS;
}
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);
+ /* 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;
+ if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+ break;
- /* The hosts database does not support MERGE. */
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
- do_merge = true;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
- nip++;
- if (nip->module == NULL)
- no_more = -1;
- }
+ nip++;
+ if (nip->module == NULL)
+ no_more = -1;
+ }
- __resolv_context_put (res_ctx);
+ __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 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;
+ 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;
- goto free_and_return;
- }
+ goto free_and_return;
}
process_list:
- if (at == NULL)
+ if (res.at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;
@@ -1031,21 +1043,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
{
struct gaih_addrtuple *atr;
- atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- memset (at, '\0', sizeof (struct gaih_addrtuple));
+ atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ memset (res.at, '\0', sizeof (struct gaih_addrtuple));
if (req->ai_family == AF_UNSPEC)
{
- at->next = __alloca (sizeof (struct gaih_addrtuple));
- memset (at->next, '\0', sizeof (struct gaih_addrtuple));
+ res.at->next = __alloca (sizeof (struct gaih_addrtuple));
+ memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
}
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
{
- at->family = AF_INET6;
+ res.at->family = AF_INET6;
if ((req->ai_flags & AI_PASSIVE) == 0)
- memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
- atr = at->next;
+ memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+ atr = res.at->next;
}
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
@@ -1058,10 +1071,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
/* Set up the canonical name if we need it. */
- if ((result = process_canonname (req, orig_name, &canon)) != 0)
+ if ((result = process_canonname (req, orig_name, &res)) != 0)
goto free_and_return;
- struct gaih_addrtuple *at2 = at;
+ struct gaih_addrtuple *at2 = res.at;
size_t socklen;
sa_family_t family;
@@ -1104,8 +1117,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_addr = (void *) (ai + 1);
/* We only add the canonical name once. */
- ai->ai_canonname = (char *) canon;
- canon = NULL;
+ ai->ai_canonname = res.canon;
+ res.canon = NULL;
#ifdef _HAVE_SA_LEN
ai->ai_addr->sa_len = socklen;
@@ -1151,7 +1164,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canon);
+ free (res.canon);
return result;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 05/12] gaih_inet: make numeric lookup a separate routine
2022-03-14 9:48 ` [PATCH v2 05/12] gaih_inet: make numeric lookup a separate routine Siddhesh Poyarekar
@ 2022-03-17 4:10 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 4:10 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> . . .
git's default patch method results in too messy a patch to review in
this case, so I applied the patch and re-diffed it with alternate
options (diff -EZdbwpU5) and I'll review *that*.
LGTM.
Reviewed-by: DJ Delorie <dj@redhat.com>
> @@ -114,10 +114,16 @@ struct gaih_typeproto
> +struct gaih_result
> +{
> + struct gaih_addrtuple *at;
> + char *canon;
> +};
Ok.
> @@ -295,20 +301,20 @@ convert_hostent_to_gaih_addrtuple (const
> - if (localcanon != NULL && canon == NULL) \
> + if (localcanon != NULL && res.canon == NULL) \
Ok.
> - canon = canonbuf; \
> + res.canon = canonbuf; \
Ok.
> static int
> process_canonname (const struct addrinfo *req, const char *orig_name,
> - char **canonp)
> + struct gaih_result *res)
> {
> - char *canon = *canonp;
> + char *canon = res->canon;
Ok.
>
> - *canonp = canon;
> + res->canon = canon;
Ok.
> +/* 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
> + returned. */
> +
> static int
> -gaih_inet (const char *name, const struct gaih_service *service,
> - const struct addrinfo *req, struct addrinfo **pai,
> - unsigned int *naddrs, struct scratch_buffer *tmpbuf)
> +text_to_binary_address (const char *name, const struct addrinfo *req,
> + struct gaih_result *res)
Ok.
> {
> - struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
> - / sizeof (struct gaih_typeproto)] = {0};
> -
> - struct gaih_addrtuple *at = NULL;
> - bool got_ipv6 = false;
> - char *canon = NULL;
> - const char *orig_name = name;
> -
> - /* Reserve stack memory for the scratch buffer in the getaddrinfo
> - function. */
> - size_t alloca_used = sizeof (struct scratch_buffer);
> -
> - int rc;
> - if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
> - return rc;
> -
> - bool malloc_name = false;
> - struct gaih_addrtuple *addrmem = NULL;
> int result = 0;
>
> - if (name != NULL)
> - {
> - if (req->ai_flags & AI_IDN)
> - {
> - char *out;
> - result = __idna_to_dns_encoding (name, &out);
> - if (result != 0)
> - return -result;
> - name = out;
> - malloc_name = true;
> - }
"Moved", ok.
> + struct gaih_addrtuple *at = res->at;
> + assert (at != NULL);
Ok.
> - uint32_t addr[4];
> - if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
> + memset (at->addr, 0, sizeof (at->addr));
> + if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
Ok.
> {
> - at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
> - at->scopeid = 0;
> - at->next = NULL;
> -
at is pre-filled, ok.
> if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
> - {
> - memcpy (at->addr, addr, sizeof (at->addr));
> at->family = AF_INET;
> - }
Ok.
> else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
> {
> - at->addr[3] = addr[0];
> + at->addr[3] = at->addr[0];
> at->addr[2] = htonl (0xffff);
> at->addr[1] = 0;
> at->addr[0] = 0;
Ok.
> - goto free_and_return;
> + goto out;
Ok.
> - goto free_and_return;
> + goto out;
> }
> - canon = canonbuf;
> + res->canon = canonbuf;
> }
> -
> - goto process_list;
> + return 0;
> }
Ok.
> char *scope_delim = strchr (name, SCOPE_DELIMITER);
> int e;
>
> if (scope_delim == NULL)
> - e = inet_pton (AF_INET6, name, addr);
> + e = inet_pton (AF_INET6, name, at->addr);
> else
> - e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
> + e = __inet_pton_length (AF_INET6, name, scope_delim - name, at->addr);
Ok.
> if (e > 0)
> {
> - at = alloca_account (sizeof (struct gaih_addrtuple),
> - alloca_used);
> - at->scopeid = 0;
> - at->next = NULL;
> -
Ok.
> if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
> - {
> - memcpy (at->addr, addr, sizeof (at->addr));
> at->family = AF_INET6;
> - }
Ok.
> else if (req->ai_family == AF_INET
> - && IN6_IS_ADDR_V4MAPPED (addr))
> + && IN6_IS_ADDR_V4MAPPED (at->addr))
> {
> - at->addr[0] = addr[3];
> - at->addr[1] = addr[1];
> - at->addr[2] = addr[2];
> - at->addr[3] = addr[3];
> + at->addr[0] = at->addr[3];
> at->family = AF_INET;
Ok.
> result = -EAI_ADDRFAMILY;
> - goto free_and_return;
> + goto out;
Ok.
> if (scope_delim != NULL
> && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
> - scope_delim + 1,
> - &at->scopeid) != 0)
> + scope_delim + 1, &at->scopeid) != 0)
Ok.
> {
> result = -EAI_NONAME;
> - goto free_and_return;
> + goto out;
> }
Ok.
> result = -EAI_MEMORY;
> - goto free_and_return;
> + goto out;
Ok.
> - canon = canonbuf;
> + res->canon = canonbuf;
> + }
> + return 0;
Ok.
> - goto process_list;
> + if ((req->ai_flags & AI_NUMERICHOST))
> + result = -EAI_NONAME;
> +
> +out:
> + res->at = NULL;
> + return result;
> }
Ok.
> - if ((req->ai_flags & AI_NUMERICHOST) == 0)
Ok.
> +static int
> +gaih_inet (const char *name, const struct gaih_service *service,
> + const struct addrinfo *req, struct addrinfo **pai,
> + unsigned int *naddrs, struct scratch_buffer *tmpbuf)
> +{
> + 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
> + function. */
> + size_t alloca_used = sizeof (struct scratch_buffer);
> +
> + int rc;
> + if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
> + return rc;
> +
> + bool malloc_name = false;
> + struct gaih_addrtuple *addrmem = NULL;
> + int result = 0;
> +
> + struct gaih_result res = {0};
> + if (name != NULL)
> {
> + if (req->ai_flags & AI_IDN)
> + {
> + char *out;
> + result = __idna_to_dns_encoding (name, &out);
> + if (result != 0)
> + return -result;
> + name = out;
> + malloc_name = true;
> + }
> +
> + res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
> + res.at->scopeid = 0;
> + res.at->next = NULL;
> +
> + if ((result = text_to_binary_address (name, req, &res)) != 0)
> + goto free_and_return;
> + else if (res.at != NULL)
> + goto process_list;
> +
"Moved", ok.
> - at = addrmem;
> + res.at = addrmem;
Ok.
> - struct gaih_addrtuple **pat = &at;
> + struct gaih_addrtuple **pat = &res.at;
Ok.
> - else if (canon == NULL)
> + else if (res.canon == NULL)
Ok.
> - canon = (*pat)->name = canonbuf;
> + res.canon = (*pat)->name = canonbuf;
Ok.
> /* Always start afresh; continue should discard previous results
> and the hosts database does not support merge. */
> - at = NULL;
> - free (canon);
> + res.at = NULL;
> + free (res.canon);
> free (addrmem);
> - canon = NULL;
> + res.canon = NULL;
> addrmem = NULL;
Ok.
> - status = DL_CALL_FCT (fct4, (name, &at,
> + status = DL_CALL_FCT (fct4, (name, &res.at,
Ok.
> - at = NULL;
> + res.at = NULL;
Ok.
> - if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
> + if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL)
> {
> - char *canonbuf = __strdup (at->name);
> + char *canonbuf = __strdup (res.at->name);
Ok.
> - canon = canonbuf;
> + res.canon = canonbuf;
> }
>
> - struct gaih_addrtuple **pat = &at;
> + struct gaih_addrtuple **pat = &res.at;
Ok.
> - struct gaih_addrtuple **pat = &at;
> + struct gaih_addrtuple **pat = &res.at;
Ok.
> if ((req->ai_flags & AI_CANONNAME) != 0
> - && canon == NULL)
> + && res.canon == NULL)
Ok.
> - char *canonbuf = getcanonname (nip, at, name);
> + char *canonbuf = getcanonname (nip, res.at, name);
Ok.
> - canon = canonbuf;
> + res.canon = canonbuf;
Ok.
> - }
Ok, matches "if (name != NULL) {"
> process_list:
> - if (at == NULL)
> + if (res.at == NULL)
Ok.
> struct gaih_addrtuple *atr;
> - atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
> + atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
> + alloca_used);
> - memset (at, '\0', sizeof (struct gaih_addrtuple));
> + memset (res.at, '\0', sizeof (struct gaih_addrtuple));
Ok.
> if (req->ai_family == AF_UNSPEC)
> {
> - at->next = __alloca (sizeof (struct gaih_addrtuple));
> + res.at->next = __alloca (sizeof (struct gaih_addrtuple));
> - memset (at->next, '\0', sizeof (struct gaih_addrtuple));
> + memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
> }
Ok.
> if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
> {
> - at->family = AF_INET6;
> + res.at->family = AF_INET6;
> if ((req->ai_flags & AI_PASSIVE) == 0)
> - memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
> + memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
> - atr = at->next;
> + atr = res.at->next;
> }
Ok.
> {
> /* Set up the canonical name if we need it. */
> - if ((result = process_canonname (req, orig_name, &canon)) != 0)
> + if ((result = process_canonname (req, orig_name, &res)) != 0)
> goto free_and_return;
Ok.
> - struct gaih_addrtuple *at2 = at;
> + struct gaih_addrtuple *at2 = res.at;
Ok.
> /* We only add the canonical name once. */
> - ai->ai_canonname = (char *) canon;
> + ai->ai_canonname = res.canon;
> - canon = NULL;
> + res.canon = NULL;
Ok.
> free_and_return:
> if (malloc_name)
> free ((char *) name);
> free (addrmem);
> - free (canon);
> + free (res.canon);
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 06/12] gaih_inet: Split simple gethostbyname into its own function
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (4 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 05/12] gaih_inet: make numeric lookup a separate routine Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 4:20 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 07/12] gaih_inet: Split nscd lookup code " Siddhesh Poyarekar
` (5 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Add a free_at flag in gaih_result to indicate if res.at needs to be
freed by the caller.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 125 ++++++++++++++++++------------------
1 file changed, 62 insertions(+), 63 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index d7b6eae9fc..bcceab7d07 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -120,6 +120,7 @@ struct gaih_result
{
struct gaih_addrtuple *at;
char *canon;
+ bool free_at;
};
/* Values for `protoflag'. */
@@ -565,6 +566,60 @@ out:
return result;
}
+/* If possible, call the simple, old functions, which do not support IPv6 scope
+ ids, nor retrieving the canonical name. */
+
+static int
+try_simple_gethostbyname (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf,
+ struct gaih_result *res)
+{
+ res->at = NULL;
+
+ if (req->ai_family != AF_INET || (req->ai_flags & AI_CANONNAME) != 0)
+ return 0;
+
+ int rc;
+ struct hostent th;
+ struct hostent *h;
+
+ while (1)
+ {
+ rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf->data,
+ tmpbuf->length, &h, &h_errno);
+ if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+
+ if (rc == 0)
+ {
+ if (h != NULL)
+ {
+ /* We found data, convert it. */
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ return -EAI_MEMORY;
+
+ res->free_at = true;
+ return 0;
+ }
+ if (h_errno == NO_DATA)
+ return -EAI_NODATA;
+
+ return -EAI_NONAME;
+ }
+
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ return -EAI_AGAIN;
+
+ /* We made requests but they turned out no data.
+ The name is known, though. */
+ return -EAI_NODATA;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -610,6 +665,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
else if (res.at != NULL)
goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -619,69 +679,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct resolv_context *res_ctx = NULL;
bool do_merge = false;
- /* If we do not have to look for IPv6 addresses or the canonical
- name, use the simple, old functions, which do not support
- IPv6 scope ids, nor retrieving the canonical name. */
- if (req->ai_family == AF_INET
- && (req->ai_flags & AI_CANONNAME) == 0)
- {
- int rc;
- struct hostent th;
- struct hostent *h;
-
- while (1)
- {
- rc = __gethostbyname2_r (name, AF_INET, &th,
- tmpbuf->data, tmpbuf->length,
- &h, &h_errno);
- if (rc != ERANGE || h_errno != NETDB_INTERNAL)
- break;
- if (!scratch_buffer_grow (tmpbuf))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
-
- if (rc == 0)
- {
- if (h != NULL)
- {
- /* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple
- (req, AF_INET, h, &addrmem))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.at = addrmem;
- }
- else
- {
- if (h_errno == NO_DATA)
- result = -EAI_NODATA;
- else
- result = -EAI_NONAME;
- goto free_and_return;
- }
- }
- else
- {
- if (h_errno == NETDB_INTERNAL)
- result = -EAI_SYSTEM;
- else if (h_errno == TRY_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;
- }
-
- goto process_list;
- }
-
#ifdef USE_NSCD
if (__nss_not_use_nscd_hosts > 0
&& ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
@@ -1164,6 +1161,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
+ if (res.free_at)
+ free (res.at);
free (res.canon);
return result;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 06/12] gaih_inet: Split simple gethostbyname into its own function
2022-03-14 9:48 ` [PATCH v2 06/12] gaih_inet: Split simple gethostbyname into its own function Siddhesh Poyarekar
@ 2022-03-17 4:20 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 4:20 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> Add a free_at flag in gaih_result to indicate if res.at needs to be
> freed by the caller.
LGTM with one comment to be added.
Reviewed-by: DJ Delorie <dj@redhat.com>
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> index d7b6eae9fc..bcceab7d07 100644
> --- a/sysdeps/posix/getaddrinfo.c
> +++ b/sysdeps/posix/getaddrinfo.c
> @@ -120,6 +120,7 @@ struct gaih_result
> {
> struct gaih_addrtuple *at;
> char *canon;
> + bool free_at;
> };
Ok.
> @@ -565,6 +566,60 @@ out:
> return result;
> }
>
> +/* If possible, call the simple, old functions, which do not support IPv6 scope
> + ids, nor retrieving the canonical name. */
> +
> +static int
> +try_simple_gethostbyname (const char *name, const struct addrinfo *req,
> + struct scratch_buffer *tmpbuf,
> + struct gaih_result *res)
> +{
> + res->at = NULL;
> +
> + if (req->ai_family != AF_INET || (req->ai_flags & AI_CANONNAME) != 0)
> + return 0;
> +
> + int rc;
> + struct hostent th;
> + struct hostent *h;
> +
> + while (1)
> + {
> + rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf->data,
> + tmpbuf->length, &h, &h_errno);
> + if (rc != ERANGE || h_errno != NETDB_INTERNAL)
> + break;
> + if (!scratch_buffer_grow (tmpbuf))
> + return -EAI_MEMORY;
> + }
> +
> + if (rc == 0)
> + {
> + if (h != NULL)
> + {
> + /* We found data, convert it. */
> + if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
> + return -EAI_MEMORY;
> +
> + res->free_at = true;
Please add a comment here that res->at will either be the result of a
realloc() or will be NULL, either of which may be safely passed to
free(). convert_hostent_to_gaih_addrtuple() has a true return path that
doesn't include the allocation, which may confuse future readers.
Otherwise ok
> + return 0;
> + }
> + if (h_errno == NO_DATA)
> + return -EAI_NODATA;
> +
> + return -EAI_NONAME;
> + }
> +
> + if (h_errno == NETDB_INTERNAL)
> + return -EAI_SYSTEM;
> + if (h_errno == TRY_AGAIN)
> + return -EAI_AGAIN;
> +
> + /* We made requests but they turned out no data.
> + The name is known, though. */
> + return -EAI_NODATA;
> +}
Ok.
> static int
> gaih_inet (const char *name, const struct gaih_service *service,
> const struct addrinfo *req, struct addrinfo **pai,
> @@ -610,6 +665,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
> else if (res.at != NULL)
> goto process_list;
>
> + if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
> + goto free_and_return;
> + else if (res.at != NULL)
> + goto process_list;
> +
Ok.
> @@ -619,69 +679,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
> struct resolv_context *res_ctx = NULL;
> bool do_merge = false;
>
> - /* If we do not have to look for IPv6 addresses or the canonical
> - name, use the simple, old functions, which do not support
> - . . .
> -
> - goto process_list;
> - }
Ok.
> + if (res.free_at)
> + free (res.at);
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 07/12] gaih_inet: Split nscd lookup code into its own function.
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (5 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 06/12] gaih_inet: Split simple gethostbyname into its own function Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 4:31 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
` (4 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
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>
---
sysdeps/posix/getaddrinfo.c | 248 +++++++++++++++++++-----------------
1 file changed, 134 insertions(+), 114 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index bcceab7d07..ba5028ad7b 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
@@ -628,7 +751,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
@@ -670,6 +792,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;
@@ -679,115 +808,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
@@ -894,7 +914,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);
@@ -937,7 +957,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);
@@ -1088,7 +1108,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;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 07/12] gaih_inet: Split nscd lookup code into its own function.
2022-03-14 9:48 ` [PATCH v2 07/12] gaih_inet: Split nscd lookup code " Siddhesh Poyarekar
@ 2022-03-17 4:31 ` DJ Delorie
2022-03-17 6:22 ` Siddhesh Poyarekar
0 siblings, 1 reply; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 4:31 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> Add a new member got_ipv6 to indicate if the results have an IPv6
> result and use it instead of the local got_ipv6.
One problem - need to clear res->got_ipv6 at some point (I couldn't find
a global "memset &res 0" that might indirectly clear it). I think once
you get a valid ipv6 response, it wlil get stuck set to true.
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> index bcceab7d07..ba5028ad7b 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;
Ok.
>
> - got_ipv6 = true; \
> + res.got_ipv6 = true; \
Ok.
> }
>
> @@ -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)
> +{
> + . . .
> +}
> +#endif
Moved, Ok.
> /* 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
> @@ -628,7 +751,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;
Nothing seems to set res.got_ipv6 to false?
> @@ -670,6 +792,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
Ok.
> -#ifdef USE_NSCD
> - if (__nss_not_use_nscd_hosts > 0
> - . . .
> - }
> -#endif
Ok.
> - got_ipv6 = true;
> + res.got_ipv6 = true;
Ok.
> - && ((req->ai_flags & AI_ALL) || !got_ipv6)))
> + && ((req->ai_flags & AI_ALL) || !res.got_ipv6)))
Ok.
> - if (got_ipv6
> + if (res.got_ipv6
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 07/12] gaih_inet: Split nscd lookup code into its own function.
2022-03-17 4:31 ` DJ Delorie
@ 2022-03-17 6:22 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 6:22 UTC (permalink / raw)
To: DJ Delorie; +Cc: libc-alpha
On 17/03/2022 10:01, DJ Delorie via Libc-alpha wrote:
>
> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
>> Add a new member got_ipv6 to indicate if the results have an IPv6
>> result and use it instead of the local got_ipv6.
>
> One problem - need to clear res->got_ipv6 at some point (I couldn't find
> a global "memset &res 0" that might indirectly clear it). I think once
> you get a valid ipv6 response, it wlil get stuck set to true.
I took a closer look at this and the nscd bit doesn't seem to need this;
it's the nss code below that needs the initialization. I've fixed 1/12
to resolve it; 8/12 will then propagate it to gaih_result.
Thanks,
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 08/12] gaih_inet: separate nss lookup loop into its own function
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (6 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 07/12] gaih_inet: Split nscd lookup code " Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 4:42 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 09/12] gaih_inet: make gethosts into a function Siddhesh Poyarekar
` (3 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 566 ++++++++++++++++++------------------
1 file changed, 288 insertions(+), 278 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index ba5028ad7b..c33cc2507b 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -159,6 +159,14 @@ static const struct addrinfo default_hints =
.ai_next = NULL
};
+static void
+gaih_result_reset (struct gaih_result *res)
+{
+ if (res->free_at)
+ free (res->at);
+ free (res->canon);
+ memset (res, 0, sizeof (*res));
+}
static int
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
@@ -195,15 +203,13 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
return 0;
}
-/* Convert struct hostent to a list of struct gaih_addrtuple objects.
- h_name is not copied, and the struct hostent object must not be
- deallocated prematurely. *RESULT must be NULL or a pointer to a
- linked-list. The new addresses are appended at the end. */
+/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
+ is not copied, and the struct hostent object must not be deallocated
+ prematurely. *RESULT must be NULL or a pointer to a linked-list. The new
+ addresses are appended at the end. */
static bool
-convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
- int family,
- struct hostent *h,
- struct gaih_addrtuple **result)
+convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
+ struct hostent *h, struct gaih_result *res)
{
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
@@ -215,7 +221,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = *result;
+ struct gaih_addrtuple *array = res->at;
size_t old = 0;
while (array != NULL)
@@ -224,12 +230,13 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array = array->next;
}
- array = realloc (*result, (old + count) * sizeof (*array));
+ array = res->at = realloc (res->at, (old + count) * sizeof (*array));
if (array == NULL)
return false;
- *result = array;
+ res->got_ipv6 = family == AF_INET6;
+ res->free_at = true;
/* Update the next pointers on reallocation. */
for (size_t i = 0; i < old; i++)
@@ -278,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_MEMORY; \
- goto free_and_return; \
+ goto out; \
} \
} \
if (status == NSS_STATUS_NOTFOUND \
@@ -288,7 +295,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
if (h_errno == TRY_AGAIN) \
no_data = EAI_AGAIN; \
@@ -297,27 +304,24 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
else if (status == NSS_STATUS_SUCCESS) \
{ \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \
+ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- *pat = addrmem; \
\
- if (localcanon != NULL && res.canon == NULL) \
+ if (localcanon != NULL && res->canon == NULL) \
{ \
char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- res.canon = canonbuf; \
+ res->canon = canonbuf; \
} \
- if (_family == AF_INET6 && *pat != NULL) \
- res.got_ipv6 = true; \
} \
}
@@ -590,6 +594,260 @@ out:
}
#endif
+static int
+get_nss_addresses (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf, struct gaih_result *res)
+{
+ 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;
+ bool do_merge = false;
+ int result = 0;
+
+ 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)
+ {
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ gaih_result_reset (res);
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
+ 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)
+ {
+ while (1)
+ {
+ status = DL_CALL_FCT (fct4, (name, &res->at,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno,
+ NULL));
+ if (status == NSS_STATUS_SUCCESS)
+ break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ res->at = NULL;
+ 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;
+ }
+
+ if (!scratch_buffer_grow (tmpbuf))
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ assert (!no_data);
+ no_data = 1;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (res->at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+
+ struct gaih_addrtuple **pat = &res->at;
+
+ 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
+ && res->canon == NULL)
+ {
+ char *canonbuf = getcanonname (nip, res->at, name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->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;
+
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
+ 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 out;
+ }
+
+ 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;
+ }
+
+out:
+ if (result != 0)
+ gaih_result_reset (res);
+ return result;
+}
+
/* 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
@@ -721,7 +979,7 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
if (h != NULL)
{
/* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, res))
return -EAI_MEMORY;
res->free_at = true;
@@ -799,263 +1057,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto process_list;
#endif
- 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;
- bool do_merge = false;
-
- 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)
- {
- /* Always start afresh; continue should discard previous results
- and the hosts database does not support merge. */
- res.at = NULL;
- free (res.canon);
- free (addrmem);
- res.canon = NULL;
- addrmem = NULL;
-
- if (do_merge)
- {
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- break;
- }
-
- 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)
- {
- while (1)
- {
- status = DL_CALL_FCT (fct4, (name, &res.at,
- tmpbuf->data, tmpbuf->length,
- &errno, &h_errno,
- NULL));
- if (status == NSS_STATUS_SUCCESS)
- break;
- /* gethostbyname4_r may write into AT, so reset it. */
- res.at = NULL;
- 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;
- }
-
- if (!scratch_buffer_grow (tmpbuf))
- {
- __resolv_context_put (res_ctx);
- 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 && res.canon == NULL)
- {
- char *canonbuf = __strdup (res.at->name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.canon = canonbuf;
- }
-
- struct gaih_addrtuple **pat = &res.at;
-
- 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)
- {
- struct gaih_addrtuple **pat = &res.at;
-
- 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
- && res.canon == NULL)
- {
- char *canonbuf = getcanonname (nip, res.at, name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.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;
-
- /* The hosts database does not support MERGE. */
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
- do_merge = true;
-
- 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 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;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- process_list:
- if (res.at == NULL)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
}
else
{
@@ -1086,6 +1095,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
+process_list:
{
/* Set up the canonical name if we need it. */
if ((result = process_canonname (req, orig_name, &res)) != 0)
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 08/12] gaih_inet: separate nss lookup loop into its own function
2022-03-14 9:48 ` [PATCH v2 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
@ 2022-03-17 4:42 ` DJ Delorie
2022-03-17 4:59 ` Siddhesh Poyarekar
0 siblings, 1 reply; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 4:42 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> ---
One memory leak needs fixing...
> +static void
> +gaih_result_reset (struct gaih_result *res)
> +{
> + if (res->free_at)
> + free (res->at);
> + free (res->canon);
> + memset (res, 0, sizeof (*res));
> +}
(I think this fixes the problem in [07/12] ;)
> -/* Convert struct hostent to a list of struct gaih_addrtuple objects.
> - h_name is not copied, and the struct hostent object must not be
> - deallocated prematurely. *RESULT must be NULL or a pointer to a
> - linked-list. The new addresses are appended at the end. */
> +/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
> + is not copied, and the struct hostent object must not be deallocated
> + prematurely. *RESULT must be NULL or a pointer to a linked-list. The new
> + addresses are appended at the end. */
no changes, ok.
> static bool
> -convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
> - int family,
> - struct hostent *h,
> - struct gaih_addrtuple **result)
> +convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
> + struct hostent *h, struct gaih_result *res)
Ok.
> - struct gaih_addrtuple *array = *result;
> + struct gaih_addrtuple *array = res->at;
Ok.
> - array = realloc (*result, (old + count) * sizeof (*array));
> + array = res->at = realloc (res->at, (old + count) * sizeof (*array));
>
> if (array == NULL)
> return false;
>
> - *result = array;
This is not the same - if realloc fails, the original res->at is lost
and can no longer be free'd.
> + res->got_ipv6 = family == AF_INET6;
> + res->free_at = true;
Ok.
> - goto free_and_return; \
> + goto out; \
Ok.
> - goto free_and_return; \
> + goto out; \
Ok.
> - if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \
> + if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
Ok.
> - goto free_and_return; \
> + goto out; \
Ok.
> - *pat = addrmem; \
> \
> - if (localcanon != NULL && res.canon == NULL) \
> + if (localcanon != NULL && res->canon == NULL) \
Ok.
> - goto free_and_return; \
> + goto out; \
Ok.
> - res.canon = canonbuf; \
> + res->canon = canonbuf; \
Ok.
> - if (_family == AF_INET6 && *pat != NULL) \
> - res.got_ipv6 = true; \
Ok.
> +static int
> +get_nss_addresses (const char *name, const struct addrinfo *req,
> + struct scratch_buffer *tmpbuf, struct gaih_result *res)
> +{
> + . . .
> +}
Moved, ok.
> - if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
> + if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, res))
> return -EAI_MEMORY;
Ok.
> - int no_data = 0;
> - int no_inet6_data = 0;
> - . . .
> - }
Moved, ok.
> + if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
> + goto free_and_return;
> + else if (res.at != NULL)
> + goto process_list;
Ok.
> - process_list:
> - if (res.at == NULL)
> - {
> - result = -EAI_NONAME;
> - goto free_and_return;
> - }
> + /* None of the lookups worked, so name not found. */
> + result = -EAI_NONAME;
> + goto free_and_return;
Ok.
>
> +process_list:
> {
> /* Set up the canonical name if we need it. */
> if ((result = process_canonname (req, orig_name, &res)) != 0)
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 08/12] gaih_inet: separate nss lookup loop into its own function
2022-03-17 4:42 ` DJ Delorie
@ 2022-03-17 4:59 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 4:59 UTC (permalink / raw)
To: DJ Delorie; +Cc: libc-alpha
On 17/03/2022 10:12, DJ Delorie wrote:
> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
>> ---
>
> One memory leak needs fixing...
>
>> +static void
>> +gaih_result_reset (struct gaih_result *res)
>> +{
>> + if (res->free_at)
>> + free (res->at);
>> + free (res->canon);
>> + memset (res, 0, sizeof (*res));
>> +}
>
> (I think this fixes the problem in [07/12] ;)
Hah, this is why my first though on your comment on 7/12 was "what do
you mean? I memset the whole block" :) I'll move this bit into 7/12.
>> -/* Convert struct hostent to a list of struct gaih_addrtuple objects.
>> - h_name is not copied, and the struct hostent object must not be
>> - deallocated prematurely. *RESULT must be NULL or a pointer to a
>> - linked-list. The new addresses are appended at the end. */
>> +/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
>> + is not copied, and the struct hostent object must not be deallocated
>> + prematurely. *RESULT must be NULL or a pointer to a linked-list. The new
>> + addresses are appended at the end. */
>
> no changes, ok.
>
>> static bool
>> -convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
>> - int family,
>> - struct hostent *h,
>> - struct gaih_addrtuple **result)
>> +convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
>> + struct hostent *h, struct gaih_result *res)
>
> Ok.
>
>> - struct gaih_addrtuple *array = *result;
>> + struct gaih_addrtuple *array = res->at;
>
> Ok.
>
>> - array = realloc (*result, (old + count) * sizeof (*array));
>> + array = res->at = realloc (res->at, (old + count) * sizeof (*array));
>>
>> if (array == NULL)
>> return false;
>>
>> - *result = array;
>
> This is not the same - if realloc fails, the original res->at is lost
> and can no longer be free'd.
>
Oops, indeed. I'll fix this.
Thanks,
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 09/12] gaih_inet: make gethosts into a function
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (7 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 4:44 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 10/12] gaih_inet: split loopback lookup into its own function Siddhesh Poyarekar
` (2 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
The macro is quite a pain to debug, so make gethosts into a function to
make it easier to maintain.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 117 ++++++++++++++++++------------------
1 file changed, 59 insertions(+), 58 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index c33cc2507b..e71f21f3c9 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -268,63 +268,54 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
return true;
}
-#define gethosts(_family) \
- { \
- struct hostent th; \
- char *localcanon = NULL; \
- no_data = 0; \
- while (1) \
- { \
- status = DL_CALL_FCT (fct, (name, _family, &th, \
- tmpbuf->data, tmpbuf->length, \
- &errno, &h_errno, NULL, &localcanon)); \
- if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \
- || errno != ERANGE) \
- break; \
- if (!scratch_buffer_grow (tmpbuf)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_MEMORY; \
- goto out; \
- } \
- } \
- if (status == NSS_STATUS_NOTFOUND \
- || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \
- { \
- if (h_errno == NETDB_INTERNAL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- if (h_errno == TRY_AGAIN) \
- no_data = EAI_AGAIN; \
- else \
- no_data = h_errno == NO_DATA; \
- } \
- else if (status == NSS_STATUS_SUCCESS) \
- { \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- \
- if (localcanon != NULL && res->canon == NULL) \
- { \
- char *canonbuf = __strdup (localcanon); \
- if (canonbuf == NULL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- res->canon = canonbuf; \
- } \
- } \
- }
+static int
+gethosts (nss_gethostbyname3_r fct, int family, const char *name,
+ const struct addrinfo *req, struct scratch_buffer *tmpbuf,
+ struct gaih_result *res, enum nss_status *statusp, int *no_datap)
+{
+ struct hostent th;
+ char *localcanon = NULL;
+ enum nss_status status;
+
+ *no_datap = 0;
+ while (1)
+ {
+ *statusp = status = DL_CALL_FCT (fct, (name, family, &th,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno, NULL,
+ &localcanon));
+ if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL
+ || errno != ERANGE)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+ if (status == NSS_STATUS_NOTFOUND
+ || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
+ {
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ *no_datap = EAI_AGAIN;
+ else
+ *no_datap = h_errno == NO_DATA;
+ }
+ else if (status == NSS_STATUS_SUCCESS)
+ {
+ if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
+ return -EAI_SYSTEM;
+
+ if (localcanon != NULL && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (localcanon);
+ if (canonbuf == NULL)
+ return -EAI_SYSTEM;
+ res->canon = canonbuf;
+ }
+ }
+ return 0;
+}
/* This function is called if a canonical name is requested, but if
the service function did not provide it. It tries to obtain the
@@ -741,7 +732,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
- gethosts (AF_INET6);
+ if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
no_inet6_data = no_data;
inet6_status = status;
}
@@ -753,7 +749,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
know we are not going to need them. */
&& ((req->ai_flags & AI_ALL) || !res->got_ipv6)))
{
- gethosts (AF_INET);
+ if ((result = gethosts (fct, AF_INET, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
if (req->ai_family == AF_INET)
{
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 09/12] gaih_inet: make gethosts into a function
2022-03-14 9:48 ` [PATCH v2 09/12] gaih_inet: make gethosts into a function Siddhesh Poyarekar
@ 2022-03-17 4:44 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 4:44 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> The macro is quite a pain to debug, so make gethosts into a function to
> make it easier to maintain.
LGTM
Reviewed-by: DJ Delorie <dj@redhat.com>
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> index c33cc2507b..e71f21f3c9 100644
> --- a/sysdeps/posix/getaddrinfo.c
> +++ b/sysdeps/posix/getaddrinfo.c
> @@ -268,63 +268,54 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
> return true;
> }
>
> -#define gethosts(_family) \
> - { \
> - struct hostent th; \
> - char *localcanon = NULL; \
> - no_data = 0; \
> - while (1) \
> - { \
> - status = DL_CALL_FCT (fct, (name, _family, &th, \
> - tmpbuf->data, tmpbuf->length, \
> - &errno, &h_errno, NULL, &localcanon)); \
> - if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \
> - || errno != ERANGE) \
> - break; \
> - if (!scratch_buffer_grow (tmpbuf)) \
> - { \
> - __resolv_context_put (res_ctx); \
> - result = -EAI_MEMORY; \
> - goto out; \
> - } \
> - } \
> - if (status == NSS_STATUS_NOTFOUND \
> - || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \
> - { \
> - if (h_errno == NETDB_INTERNAL) \
> - { \
> - __resolv_context_put (res_ctx); \
> - result = -EAI_SYSTEM; \
> - goto out; \
> - } \
> - if (h_errno == TRY_AGAIN) \
> - no_data = EAI_AGAIN; \
> - else \
> - no_data = h_errno == NO_DATA; \
> - } \
> - else if (status == NSS_STATUS_SUCCESS) \
> - { \
> - if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
> - { \
> - __resolv_context_put (res_ctx); \
> - result = -EAI_SYSTEM; \
> - goto out; \
> - } \
> - \
> - if (localcanon != NULL && res->canon == NULL) \
> - { \
> - char *canonbuf = __strdup (localcanon); \
> - if (canonbuf == NULL) \
> - { \
> - __resolv_context_put (res_ctx); \
> - result = -EAI_SYSTEM; \
> - goto out; \
> - } \
> - res->canon = canonbuf; \
> - } \
> - } \
> - }
> +static int
> +gethosts (nss_gethostbyname3_r fct, int family, const char *name,
> + const struct addrinfo *req, struct scratch_buffer *tmpbuf,
> + struct gaih_result *res, enum nss_status *statusp, int *no_datap)
> +{
> + struct hostent th;
> + char *localcanon = NULL;
> + enum nss_status status;
> +
> + *no_datap = 0;
> + while (1)
> + {
> + *statusp = status = DL_CALL_FCT (fct, (name, family, &th,
> + tmpbuf->data, tmpbuf->length,
> + &errno, &h_errno, NULL,
> + &localcanon));
> + if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL
> + || errno != ERANGE)
> + break;
> + if (!scratch_buffer_grow (tmpbuf))
> + return -EAI_MEMORY;
> + }
> + if (status == NSS_STATUS_NOTFOUND
> + || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
> + {
> + if (h_errno == NETDB_INTERNAL)
> + return -EAI_SYSTEM;
> + if (h_errno == TRY_AGAIN)
> + *no_datap = EAI_AGAIN;
> + else
> + *no_datap = h_errno == NO_DATA;
> + }
> + else if (status == NSS_STATUS_SUCCESS)
> + {
> + if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
> + return -EAI_SYSTEM;
> +
> + if (localcanon != NULL && res->canon == NULL)
> + {
> + char *canonbuf = __strdup (localcanon);
> + if (canonbuf == NULL)
> + return -EAI_SYSTEM;
> + res->canon = canonbuf;
> + }
> + }
>
> + return 0;
> +}
>
> /* This function is called if a canonical name is requested, but if
> the service function did not provide it. It tries to obtain the
> @@ -741,7 +732,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
> if (req->ai_family == AF_INET6
> || req->ai_family == AF_UNSPEC)
> {
> - gethosts (AF_INET6);
> + if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf,
> + res, &status, &no_data)) != 0)
> + {
> + __resolv_context_put (res_ctx);
> + goto out;
> + }
> no_inet6_data = no_data;
> inet6_status = status;
> }
> @@ -753,7 +749,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
> know we are not going to need them. */
> && ((req->ai_flags & AI_ALL) || !res->got_ipv6)))
> {
> - gethosts (AF_INET);
> + if ((result = gethosts (fct, AF_INET, name, req, tmpbuf,
> + res, &status, &no_data)) != 0)
> + {
> + __resolv_context_put (res_ctx);
> + goto out;
> + }
>
> if (req->ai_family == AF_INET)
> {
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 10/12] gaih_inet: split loopback lookup into its own function
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (8 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 09/12] gaih_inet: make gethosts into a function Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 4:51 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 11/12] gaih_inet: Split result generation " Siddhesh Poyarekar
2022-03-14 9:48 ` [PATCH v2 12/12] gethosts: Return EAI_MEMORY on allocation failure Siddhesh Poyarekar
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Flatten the condition nesting and replace the alloca for RET.AT/ATR with
a single array LOCAL_AT[2]. This gets rid of alloca and alloca
accounting.
`git diff -b` is probably the best way to view this change since much of
the diff is whitespace changes.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 127 ++++++++++++++++++------------------
1 file changed, 62 insertions(+), 65 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index e71f21f3c9..3aeeb0d1e0 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1002,6 +1002,32 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
return -EAI_NODATA;
}
+/* Add local address information into RES. RES->AT is assumed to have enough
+ space for two tuples and is zeroed out. */
+
+static void
+get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
+{
+ struct gaih_addrtuple *atr = res->at;
+ if (req->ai_family == AF_UNSPEC)
+ res->at->next = res->at + 1;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ res->at->family = AF_INET6;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ memcpy (res->at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+ atr = res->at->next;
+ }
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+ {
+ atr->family = AF_INET;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ atr->addr[0] = htonl (INADDR_LOOPBACK);
+ }
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1012,10 +1038,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
const char *orig_name = name;
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
-
int rc;
if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
return rc;
@@ -1025,76 +1047,51 @@ gaih_inet (const char *name, const struct gaih_service *service,
int result = 0;
struct gaih_result res = {0};
- if (name != NULL)
+ struct gaih_addrtuple local_at[2] = {0};
+
+ res.at = local_at;
+
+ if (__glibc_unlikely (name == NULL))
{
- if (req->ai_flags & AI_IDN)
- {
- char *out;
- result = __idna_to_dns_encoding (name, &out);
- if (result != 0)
- return -result;
- name = out;
- malloc_name = true;
- }
+ get_local_addresses (req, &res);
+ goto process_list;
+ }
- res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- res.at->scopeid = 0;
- res.at->next = NULL;
+ if (req->ai_flags & AI_IDN)
+ {
+ char *out;
+ result = __idna_to_dns_encoding (name, &out);
+ if (result != 0)
+ return -result;
+ name = out;
+ malloc_name = true;
+ }
- if ((result = text_to_binary_address (name, req, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = text_to_binary_address (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ 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;
+ if ((result = get_nscd_addresses (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
#endif
- if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
-
- /* None of the lookups worked, so name not found. */
- result = -EAI_NONAME;
- goto free_and_return;
- }
- else
- {
- struct gaih_addrtuple *atr;
- atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
- alloca_used);
- memset (res.at, '\0', sizeof (struct gaih_addrtuple));
-
- if (req->ai_family == AF_UNSPEC)
- {
- res.at->next = __alloca (sizeof (struct gaih_addrtuple));
- memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
- }
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- {
- res.at->family = AF_INET6;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
- atr = res.at->next;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- {
- atr->family = AF_INET;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- atr->addr[0] = htonl (INADDR_LOOPBACK);
- }
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
process_list:
{
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 10/12] gaih_inet: split loopback lookup into its own function
2022-03-14 9:48 ` [PATCH v2 10/12] gaih_inet: split loopback lookup into its own function Siddhesh Poyarekar
@ 2022-03-17 4:51 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 4:51 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> Flatten the condition nesting and replace the alloca for RET.AT/ATR with
> a single array LOCAL_AT[2]. This gets rid of alloca and alloca
> accounting.
>
> `git diff -b` is probably the best way to view this change since much of
> the diff is whitespace changes.
reviewing alternate diff then... ;-)
LGTM.
Reviewed-by: DJ Delorie <dj@redhat.com>
> +/* Add local address information into RES. RES->AT is assumed to have enough
> + space for two tuples and is zeroed out. */
> +
> +static void
> +get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
> +{
> + struct gaih_addrtuple *atr = res->at;
> + if (req->ai_family == AF_UNSPEC)
> + res->at->next = res->at + 1;
> +
> + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
> + {
> + res->at->family = AF_INET6;
> + if ((req->ai_flags & AI_PASSIVE) == 0)
> + memcpy (res->at->addr, &in6addr_loopback, sizeof (struct in6_addr));
> + atr = res->at->next;
> + }
> +
> + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
> + {
> + atr->family = AF_INET;
> + if ((req->ai_flags & AI_PASSIVE) == 0)
> + atr->addr[0] = htonl (INADDR_LOOPBACK);
> + }
> +}
Ok.
>
> - /* Reserve stack memory for the scratch buffer in the getaddrinfo
> - function. */
> - size_t alloca_used = sizeof (struct scratch_buffer);
> -
Ok.
> struct gaih_result res = {0};
> + struct gaih_addrtuple local_at[2] = {0};
> +
> + res.at = local_at;
> +
> + if (__glibc_unlikely (name == NULL))
> - if (name != NULL)
> {
> + get_local_addresses (req, &res);
> + goto process_list;
> + }
> +
Ok.
>
> - res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
> - res.at->scopeid = 0;
> - res.at->next = NULL;
Ok.
> - else
> - {
> - struct gaih_addrtuple *atr;
> - atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
> - alloca_used);
> - memset (res.at, '\0', sizeof (struct gaih_addrtuple));
> -
> - if (req->ai_family == AF_UNSPEC)
> - {
> - res.at->next = __alloca (sizeof (struct gaih_addrtuple));
> - memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
> - }
> -
> - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
> - {
> - res.at->family = AF_INET6;
> - if ((req->ai_flags & AI_PASSIVE) == 0)
> - memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
> - atr = res.at->next;
> - }
> -
> - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
> - {
> - atr->family = AF_INET;
> - if ((req->ai_flags & AI_PASSIVE) == 0)
> - atr->addr[0] = htonl (INADDR_LOOPBACK);
> - }
> - }
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 11/12] gaih_inet: Split result generation into its own function
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (9 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 10/12] gaih_inet: split loopback lookup into its own function Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 5:05 ` DJ Delorie
2022-03-14 9:48 ` [PATCH v2 12/12] gethosts: Return EAI_MEMORY on allocation failure Siddhesh Poyarekar
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
Simplify the loop a wee bit and clean up variable names too.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 176 ++++++++++++++++++------------------
1 file changed, 86 insertions(+), 90 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 3aeeb0d1e0..eebed824a8 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1028,6 +1028,87 @@ get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
}
}
+/* Generate results in PAI and its count in NADDRS. Return 0 on success or an
+ error code on failure. */
+
+static int
+generate_addrinfo (const struct addrinfo *req, struct gaih_result *res,
+ const struct gaih_servtuple *st, struct addrinfo **pai,
+ unsigned int *naddrs)
+{
+ size_t socklen;
+ sa_family_t family;
+
+ /* Buffer is the size of an unformatted IPv6 address in printable format. */
+ for (struct gaih_addrtuple *at = res->at; at != NULL; at = at->next)
+ {
+ family = at->family;
+ if (family == AF_INET6)
+ {
+ socklen = sizeof (struct sockaddr_in6);
+
+ /* 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 (res->got_ipv6
+ && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ continue;
+ }
+ else
+ socklen = sizeof (struct sockaddr_in);
+
+ for (int i = 0; st[i].set; i++)
+ {
+ struct addrinfo *ai;
+ ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
+ if (ai == NULL)
+ return -EAI_MEMORY;
+
+ ai->ai_flags = req->ai_flags;
+ ai->ai_family = family;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
+ ai->ai_addrlen = socklen;
+ ai->ai_addr = (void *) (ai + 1);
+
+ /* We only add the canonical name once. */
+ ai->ai_canonname = res->canon;
+ res->canon = NULL;
+
+#ifdef _HAVE_SA_LEN
+ ai->ai_addr->sa_len = socklen;
+#endif /* _HAVE_SA_LEN */
+ ai->ai_addr->sa_family = family;
+
+ /* In case of an allocation error the list must be NULL
+ terminated. */
+ ai->ai_next = NULL;
+
+ if (family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) ai->ai_addr;
+ sin6p->sin6_port = st[i].port;
+ sin6p->sin6_flowinfo = 0;
+ memcpy (&sin6p->sin6_addr, at->addr, sizeof (struct in6_addr));
+ sin6p->sin6_scope_id = at->scopeid;
+ }
+ else
+ {
+ struct sockaddr_in *sinp = (struct sockaddr_in *) ai->ai_addr;
+ sinp->sin_port = st[i].port;
+ memcpy (&sinp->sin_addr, at->addr, sizeof (struct in_addr));
+ memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+ }
+
+ pai = &(ai->ai_next);
+ }
+
+ ++*naddrs;
+ }
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1094,98 +1175,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto free_and_return;
process_list:
- {
- /* Set up the canonical name if we need it. */
- if ((result = process_canonname (req, orig_name, &res)) != 0)
- goto free_and_return;
-
- struct gaih_addrtuple *at2 = res.at;
- size_t socklen;
- sa_family_t family;
-
- /*
- buffer is the size of an unformatted IPv6 address in printable format.
- */
- while (at2 != NULL)
- {
- family = at2->family;
- if (family == AF_INET6)
- {
- socklen = sizeof (struct sockaddr_in6);
-
- /* 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 (res.got_ipv6
- && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
- && IN6_IS_ADDR_V4MAPPED (at2->addr))
- goto ignore;
- }
- else
- socklen = sizeof (struct sockaddr_in);
-
- for (int i = 0; st[i].set; i++)
- {
- struct addrinfo *ai;
- ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
- if (ai == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
-
- ai->ai_flags = req->ai_flags;
- ai->ai_family = family;
- ai->ai_socktype = st[i].socktype;
- ai->ai_protocol = st[i].protocol;
- ai->ai_addrlen = socklen;
- ai->ai_addr = (void *) (ai + 1);
-
- /* We only add the canonical name once. */
- ai->ai_canonname = res.canon;
- res.canon = NULL;
-
-#ifdef _HAVE_SA_LEN
- ai->ai_addr->sa_len = socklen;
-#endif /* _HAVE_SA_LEN */
- ai->ai_addr->sa_family = family;
-
- /* In case of an allocation error the list must be NULL
- terminated. */
- ai->ai_next = NULL;
-
- if (family == AF_INET6)
- {
- struct sockaddr_in6 *sin6p =
- (struct sockaddr_in6 *) ai->ai_addr;
-
- sin6p->sin6_port = st[i].port;
- sin6p->sin6_flowinfo = 0;
- memcpy (&sin6p->sin6_addr,
- at2->addr, sizeof (struct in6_addr));
- sin6p->sin6_scope_id = at2->scopeid;
- }
- else
- {
- struct sockaddr_in *sinp =
- (struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st[i].port;
- memcpy (&sinp->sin_addr,
- at2->addr, sizeof (struct in_addr));
- memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
- }
-
- pai = &(ai->ai_next);
- }
-
- ++*naddrs;
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &res)) != 0)
+ goto free_and_return;
- ignore:
- at2 = at2->next;
- }
- }
+ result = generate_addrinfo (req, &res, st, pai, naddrs);
- free_and_return:
+free_and_return:
if (malloc_name)
free ((char *) name);
free (addrmem);
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 11/12] gaih_inet: Split result generation into its own function
2022-03-14 9:48 ` [PATCH v2 11/12] gaih_inet: Split result generation " Siddhesh Poyarekar
@ 2022-03-17 5:05 ` DJ Delorie
2022-03-17 5:11 ` Siddhesh Poyarekar
0 siblings, 1 reply; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 5:05 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> Simplify the loop a wee bit and clean up variable names too.
FYI combining "split out" and "minor changes" makes it harder to review,
because the minor changes are nearly impossible to spot in the large
chunks of "moving".
I had one comment about a leak (see below) but it's independent of this
patch set (maybe?).
LGTM.
Reviewed-by: DJ Delorie <dj@redhat.com>
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> index 3aeeb0d1e0..eebed824a8 100644
> --- a/sysdeps/posix/getaddrinfo.c
> +++ b/sysdeps/posix/getaddrinfo.c
> @@ -1028,6 +1028,87 @@ get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
> }
> }
>
> +/* Generate results in PAI and its count in NADDRS. Return 0 on success or an
> + error code on failure. */
> +
> +static int
> +generate_addrinfo (const struct addrinfo *req, struct gaih_result *res,
> + const struct gaih_servtuple *st, struct addrinfo **pai,
> + unsigned int *naddrs)
> +{
> + . . .
Ok.
> + for (int i = 0; st[i].set; i++)
> + {
> + struct addrinfo *ai;
> + ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
> + if (ai == NULL)
> + return -EAI_MEMORY;
I think there might be a memory leak here if malloc fails on the second
or later iteration of the loop. However, we would have had that leak
before, too, and if we're out of memory... this type of leak is likely
not what you'd be worried about.
> + . . .
> + return 0;
> +}
> +
Ok.
>
> process_list:
> + /* Set up the canonical name if we need it. */
> + if ((result = process_canonname (req, orig_name, &res)) != 0)
> + goto free_and_return;
> - {
> - /* Set up the canonical name if we need it. */
> - if ((result = process_canonname (req, orig_name, &res)) != 0)
> - goto free_and_return;
> -
> - . . .
> - }
> - }
Ok.
> + result = generate_addrinfo (req, &res, st, pai, naddrs);
Ok.
> - free_and_return:
> +free_and_return:
Ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 11/12] gaih_inet: Split result generation into its own function
2022-03-17 5:05 ` DJ Delorie
@ 2022-03-17 5:11 ` Siddhesh Poyarekar
0 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 5:11 UTC (permalink / raw)
To: DJ Delorie; +Cc: libc-alpha
On 17/03/2022 10:35, DJ Delorie wrote:
> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
>> Simplify the loop a wee bit and clean up variable names too.
>
> FYI combining "split out" and "minor changes" makes it harder to review,
> because the minor changes are nearly impossible to spot in the large
> chunks of "moving".
Ack, I got a bit lazy :/
> I had one comment about a leak (see below) but it's independent of this
> patch set (maybe?).
Yeah, it's a preexisting leak, but it only manifests when the system is
out of memory.
Thanks,
Siddhesh
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 12/12] gethosts: Return EAI_MEMORY on allocation failure
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (10 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 11/12] gaih_inet: Split result generation " Siddhesh Poyarekar
@ 2022-03-14 9:48 ` Siddhesh Poyarekar
2022-03-17 5:06 ` DJ Delorie
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-14 9:48 UTC (permalink / raw)
To: libc-alpha
All other cases of failures due to lack of memory return EAI_MEMORY, so
it seems wrong to return EAI_SYSTEM here. The only reason
convert_hostent_to_gaih_addrtuple could fail is on calloc failure.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index eebed824a8..5cd988bec5 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -303,13 +303,13 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
else if (status == NSS_STATUS_SUCCESS)
{
if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
if (localcanon != NULL && res->canon == NULL)
{
char *canonbuf = __strdup (localcanon);
if (canonbuf == NULL)
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
res->canon = canonbuf;
}
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v2 12/12] gethosts: Return EAI_MEMORY on allocation failure
2022-03-14 9:48 ` [PATCH v2 12/12] gethosts: Return EAI_MEMORY on allocation failure Siddhesh Poyarekar
@ 2022-03-17 5:06 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 5:06 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> All other cases of failures due to lack of memory return EAI_MEMORY, so
> it seems wrong to return EAI_SYSTEM here. The only reason
> convert_hostent_to_gaih_addrtuple could fail is on calloc failure.
LGTM.
Reviewed-by: DJ Delorie <dj@redhat.com>
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
> index eebed824a8..5cd988bec5 100644
> --- a/sysdeps/posix/getaddrinfo.c
> +++ b/sysdeps/posix/getaddrinfo.c
> @@ -303,13 +303,13 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
> else if (status == NSS_STATUS_SUCCESS)
> {
> if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
> - return -EAI_SYSTEM;
> + return -EAI_MEMORY;
>
> if (localcanon != NULL && res->canon == NULL)
> {
> char *canonbuf = __strdup (localcanon);
> if (canonbuf == NULL)
> - return -EAI_SYSTEM;
> + return -EAI_MEMORY;
> res->canon = canonbuf;
> }
> }
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 00/12] getaddrinfo facelift and fixes
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (12 preceding siblings ...)
2022-03-14 9:48 ` [PATCH v2 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
@ 2022-03-14 13:21 ` Cristian Rodríguez
2022-03-14 14:16 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
14 siblings, 1 reply; 68+ messages in thread
From: Cristian Rodríguez @ 2022-03-14 13:21 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha, fweimer
Do you have a remote that I could add to test this changes and make
suggestions..?
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 00/12] getaddrinfo facelift and fixes
2022-03-08 10:07 [PATCH 00/12] getaddrinfo facelift and fixes Siddhesh Poyarekar
` (13 preceding siblings ...)
2022-03-14 13:21 ` [PATCH 00/12] getaddrinfo facelift and fixes Cristian Rodríguez
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
` (11 more replies)
14 siblings, 12 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
The gaih_inet implementation, which forms the core of getaddrinfo, is
quite complex in its implementation, making it hard to follow or debug.
Particularly, allocations for gaih_addrtuples to store intermediate
results are particularly hard to track because of the way in which it is
written.
This patchset is an attempt at cleaning up the implementation to make it
much easier to follow. In the process, it also fixes a couple of bugs,
one that was the trigger for this cleanup and another that was
discovered during the cleanup.
Changes from v2:
- 1/12: reinitialized got_ipv6 too, changed test case to run in a
container.
- 8/12: Fix leak on realloc failure
- Rest: updated review comments.
Changes from v1:
- Fixed nit: boolean coercion in convert_hostent_to_gaih_addrtuple
- Dropped DNS tests in tst-nss-gai-actions test since they are
unnecessary and the files tests are sufficient.
Siddhesh Poyarekar (12):
Simplify allocations and fix merge and continue actions [BZ #28931]
gaih_inet: Simplify canon name resolution
getaddrinfo: Fix leak with AI_ALL [BZ #28852]
gaih_inet: Simplify service resolution
gaih_inet: make numeric lookup a separate routine
gaih_inet: Split simple gethostbyname into its own function
gaih_inet: Split nscd lookup code into its own function.
gaih_inet: separate nss lookup loop into its own function
gaih_inet: make gethosts into a function
gaih_inet: split loopback lookup into its own function
gaih_inet: Split result generation into its own function
gethosts: Return EAI_MEMORY on allocation failure
nss/Makefile | 1 +
nss/tst-nss-gai-actions.c | 149 ++
nss/tst-nss-gai-actions.root/etc/host.conf | 1 +
nss/tst-nss-gai-actions.root/etc/hosts | 508 +++++++
sysdeps/posix/getaddrinfo.c | 1520 +++++++++++---------
5 files changed, 1464 insertions(+), 715 deletions(-)
create mode 100644 nss/tst-nss-gai-actions.c
create mode 100644 nss/tst-nss-gai-actions.root/etc/host.conf
create mode 100644 nss/tst-nss-gai-actions.root/etc/hosts
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 21:47 ` DJ Delorie
2022-03-17 8:11 ` [PATCH v3 02/12] gaih_inet: Simplify canon name resolution Siddhesh Poyarekar
` (10 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Allocations for address tuples is currently a bit confusing because of
the pointer chasing through PAT, making it hard to observe the sequence
in which allocations have been made. Narrow scope of the pointer
chasing through PAT so that it is only used where necessary.
This also tightens actions behaviour with the hosts database in
getaddrinfo to comply with the manual text. The "continue" action
discards previous results and the "merge" action results in an immedate
lookup failure. Consequently, chaining of allocations across modules is
no longer necessary, thus opening up cleanup opportunities.
A test has been added that checks some combinations to ensure that they
work correctly.
Resolves: BZ #28931
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
nss/Makefile | 1 +
nss/tst-nss-gai-actions.c | 149 ++++++
nss/tst-nss-gai-actions.root/etc/host.conf | 1 +
nss/tst-nss-gai-actions.root/etc/hosts | 508 +++++++++++++++++++++
sysdeps/posix/getaddrinfo.c | 143 +++---
5 files changed, 750 insertions(+), 52 deletions(-)
create mode 100644 nss/tst-nss-gai-actions.c
create mode 100644 nss/tst-nss-gai-actions.root/etc/host.conf
create mode 100644 nss/tst-nss-gai-actions.root/etc/hosts
diff --git a/nss/Makefile b/nss/Makefile
index 42a59535cb..d8b06b44fb 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -76,6 +76,7 @@ tests-container := \
tst-nss-db-endgrent \
tst-nss-db-endpwent \
tst-nss-files-hosts-long \
+ tst-nss-gai-actions \
tst-nss-test3 \
tst-reload1 \
tst-reload2 \
diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
new file mode 100644
index 0000000000..efca6cd183
--- /dev/null
+++ b/nss/tst-nss-gai-actions.c
@@ -0,0 +1,149 @@
+/* Test continue and merge NSS actions for getaddrinfo.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+enum
+{
+ ACTION_MERGE = 0,
+ ACTION_CONTINUE,
+};
+
+static const char *
+family_str (int family)
+{
+ switch (family)
+ {
+ case AF_UNSPEC:
+ return "AF_UNSPEC";
+ case AF_INET:
+ return "AF_INET";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static const char *
+action_str (int action)
+{
+ switch (action)
+ {
+ case ACTION_MERGE:
+ return "merge";
+ case ACTION_CONTINUE:
+ return "continue";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+do_one_test (int action, int family, bool canon)
+{
+ struct addrinfo hints =
+ {
+ .ai_family = family,
+ };
+
+ struct addrinfo *ai;
+
+ if (canon)
+ hints.ai_flags = AI_CANONNAME;
+
+ printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
+ action_str (action), family_str (family),
+ canon ? "AI_CANONNAME" : "");
+
+ int ret = getaddrinfo ("example.org", "80", &hints, &ai);
+
+ switch (action)
+ {
+ case ACTION_MERGE:
+ if (ret == 0)
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ printf ("merge unexpectedly succeeded:\n %s\n", formatted);
+ support_record_failure ();
+ free (formatted);
+ }
+ else
+ return;
+ case ACTION_CONTINUE:
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ /* Verify that the result appears exactly once. */
+ const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
+ "address: DGRAM/UDP 192.0.0.1 80\n"
+ "address: RAW/IP 192.0.0.1 80\n";
+
+ const char *contains = strstr (formatted, expected);
+ const char *contains2 = NULL;
+
+ if (contains != NULL)
+ contains2 = strstr (contains + strlen (expected), expected);
+
+ if (contains == NULL || contains2 != NULL)
+ {
+ printf ("continue failed:\n%s\n", formatted);
+ support_record_failure ();
+ }
+
+ free (formatted);
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+do_one_test_set (int action)
+{
+ char buf[32];
+
+ snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
+ action_str (action));
+ __nss_configure_lookup ("hosts", buf);
+
+ do_one_test (action, AF_UNSPEC, false);
+ do_one_test (action, AF_INET, false);
+ do_one_test (action, AF_INET, true);
+}
+
+static int
+do_test (void)
+{
+ do_one_test_set (ACTION_CONTINUE);
+ do_one_test_set (ACTION_MERGE);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf
new file mode 100644
index 0000000000..d1a59f73a9
--- /dev/null
+++ b/nss/tst-nss-gai-actions.root/etc/host.conf
@@ -0,0 +1 @@
+multi on
diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts
new file mode 100644
index 0000000000..50ce9774dc
--- /dev/null
+++ b/nss/tst-nss-gai-actions.root/etc/hosts
@@ -0,0 +1,508 @@
+192.0.0.1 example.org
+192.0.0.2 example.org
+192.0.0.3 example.org
+192.0.0.4 example.org
+192.0.0.5 example.org
+192.0.0.6 example.org
+192.0.0.7 example.org
+192.0.0.8 example.org
+192.0.0.9 example.org
+192.0.0.10 example.org
+192.0.0.11 example.org
+192.0.0.12 example.org
+192.0.0.13 example.org
+192.0.0.14 example.org
+192.0.0.15 example.org
+192.0.0.16 example.org
+192.0.0.17 example.org
+192.0.0.18 example.org
+192.0.0.19 example.org
+192.0.0.20 example.org
+192.0.0.21 example.org
+192.0.0.22 example.org
+192.0.0.23 example.org
+192.0.0.24 example.org
+192.0.0.25 example.org
+192.0.0.26 example.org
+192.0.0.27 example.org
+192.0.0.28 example.org
+192.0.0.29 example.org
+192.0.0.30 example.org
+192.0.0.31 example.org
+192.0.0.32 example.org
+192.0.0.33 example.org
+192.0.0.34 example.org
+192.0.0.35 example.org
+192.0.0.36 example.org
+192.0.0.37 example.org
+192.0.0.38 example.org
+192.0.0.39 example.org
+192.0.0.40 example.org
+192.0.0.41 example.org
+192.0.0.42 example.org
+192.0.0.43 example.org
+192.0.0.44 example.org
+192.0.0.45 example.org
+192.0.0.46 example.org
+192.0.0.47 example.org
+192.0.0.48 example.org
+192.0.0.49 example.org
+192.0.0.50 example.org
+192.0.0.51 example.org
+192.0.0.52 example.org
+192.0.0.53 example.org
+192.0.0.54 example.org
+192.0.0.55 example.org
+192.0.0.56 example.org
+192.0.0.57 example.org
+192.0.0.58 example.org
+192.0.0.59 example.org
+192.0.0.60 example.org
+192.0.0.61 example.org
+192.0.0.62 example.org
+192.0.0.63 example.org
+192.0.0.64 example.org
+192.0.0.65 example.org
+192.0.0.66 example.org
+192.0.0.67 example.org
+192.0.0.68 example.org
+192.0.0.69 example.org
+192.0.0.70 example.org
+192.0.0.71 example.org
+192.0.0.72 example.org
+192.0.0.73 example.org
+192.0.0.74 example.org
+192.0.0.75 example.org
+192.0.0.76 example.org
+192.0.0.77 example.org
+192.0.0.78 example.org
+192.0.0.79 example.org
+192.0.0.80 example.org
+192.0.0.81 example.org
+192.0.0.82 example.org
+192.0.0.83 example.org
+192.0.0.84 example.org
+192.0.0.85 example.org
+192.0.0.86 example.org
+192.0.0.87 example.org
+192.0.0.88 example.org
+192.0.0.89 example.org
+192.0.0.90 example.org
+192.0.0.91 example.org
+192.0.0.92 example.org
+192.0.0.93 example.org
+192.0.0.94 example.org
+192.0.0.95 example.org
+192.0.0.96 example.org
+192.0.0.97 example.org
+192.0.0.98 example.org
+192.0.0.99 example.org
+192.0.0.100 example.org
+192.0.0.101 example.org
+192.0.0.102 example.org
+192.0.0.103 example.org
+192.0.0.104 example.org
+192.0.0.105 example.org
+192.0.0.106 example.org
+192.0.0.107 example.org
+192.0.0.108 example.org
+192.0.0.109 example.org
+192.0.0.110 example.org
+192.0.0.111 example.org
+192.0.0.112 example.org
+192.0.0.113 example.org
+192.0.0.114 example.org
+192.0.0.115 example.org
+192.0.0.116 example.org
+192.0.0.117 example.org
+192.0.0.118 example.org
+192.0.0.119 example.org
+192.0.0.120 example.org
+192.0.0.121 example.org
+192.0.0.122 example.org
+192.0.0.123 example.org
+192.0.0.124 example.org
+192.0.0.125 example.org
+192.0.0.126 example.org
+192.0.0.127 example.org
+192.0.0.128 example.org
+192.0.0.129 example.org
+192.0.0.130 example.org
+192.0.0.131 example.org
+192.0.0.132 example.org
+192.0.0.133 example.org
+192.0.0.134 example.org
+192.0.0.135 example.org
+192.0.0.136 example.org
+192.0.0.137 example.org
+192.0.0.138 example.org
+192.0.0.139 example.org
+192.0.0.140 example.org
+192.0.0.141 example.org
+192.0.0.142 example.org
+192.0.0.143 example.org
+192.0.0.144 example.org
+192.0.0.145 example.org
+192.0.0.146 example.org
+192.0.0.147 example.org
+192.0.0.148 example.org
+192.0.0.149 example.org
+192.0.0.150 example.org
+192.0.0.151 example.org
+192.0.0.152 example.org
+192.0.0.153 example.org
+192.0.0.154 example.org
+192.0.0.155 example.org
+192.0.0.156 example.org
+192.0.0.157 example.org
+192.0.0.158 example.org
+192.0.0.159 example.org
+192.0.0.160 example.org
+192.0.0.161 example.org
+192.0.0.162 example.org
+192.0.0.163 example.org
+192.0.0.164 example.org
+192.0.0.165 example.org
+192.0.0.166 example.org
+192.0.0.167 example.org
+192.0.0.168 example.org
+192.0.0.169 example.org
+192.0.0.170 example.org
+192.0.0.171 example.org
+192.0.0.172 example.org
+192.0.0.173 example.org
+192.0.0.174 example.org
+192.0.0.175 example.org
+192.0.0.176 example.org
+192.0.0.177 example.org
+192.0.0.178 example.org
+192.0.0.179 example.org
+192.0.0.180 example.org
+192.0.0.181 example.org
+192.0.0.182 example.org
+192.0.0.183 example.org
+192.0.0.184 example.org
+192.0.0.185 example.org
+192.0.0.186 example.org
+192.0.0.187 example.org
+192.0.0.188 example.org
+192.0.0.189 example.org
+192.0.0.190 example.org
+192.0.0.191 example.org
+192.0.0.192 example.org
+192.0.0.193 example.org
+192.0.0.194 example.org
+192.0.0.195 example.org
+192.0.0.196 example.org
+192.0.0.197 example.org
+192.0.0.198 example.org
+192.0.0.199 example.org
+192.0.0.200 example.org
+192.0.0.201 example.org
+192.0.0.202 example.org
+192.0.0.203 example.org
+192.0.0.204 example.org
+192.0.0.205 example.org
+192.0.0.206 example.org
+192.0.0.207 example.org
+192.0.0.208 example.org
+192.0.0.209 example.org
+192.0.0.210 example.org
+192.0.0.211 example.org
+192.0.0.212 example.org
+192.0.0.213 example.org
+192.0.0.214 example.org
+192.0.0.215 example.org
+192.0.0.216 example.org
+192.0.0.217 example.org
+192.0.0.218 example.org
+192.0.0.219 example.org
+192.0.0.220 example.org
+192.0.0.221 example.org
+192.0.0.222 example.org
+192.0.0.223 example.org
+192.0.0.224 example.org
+192.0.0.225 example.org
+192.0.0.226 example.org
+192.0.0.227 example.org
+192.0.0.228 example.org
+192.0.0.229 example.org
+192.0.0.230 example.org
+192.0.0.231 example.org
+192.0.0.232 example.org
+192.0.0.233 example.org
+192.0.0.234 example.org
+192.0.0.235 example.org
+192.0.0.236 example.org
+192.0.0.237 example.org
+192.0.0.238 example.org
+192.0.0.239 example.org
+192.0.0.240 example.org
+192.0.0.241 example.org
+192.0.0.242 example.org
+192.0.0.243 example.org
+192.0.0.244 example.org
+192.0.0.245 example.org
+192.0.0.246 example.org
+192.0.0.247 example.org
+192.0.0.248 example.org
+192.0.0.249 example.org
+192.0.0.250 example.org
+192.0.0.251 example.org
+192.0.0.252 example.org
+192.0.0.253 example.org
+192.0.0.254 example.org
+192.0.1.1 example.org
+192.0.1.2 example.org
+192.0.1.3 example.org
+192.0.1.4 example.org
+192.0.1.5 example.org
+192.0.1.6 example.org
+192.0.1.7 example.org
+192.0.1.8 example.org
+192.0.1.9 example.org
+192.0.1.10 example.org
+192.0.1.11 example.org
+192.0.1.12 example.org
+192.0.1.13 example.org
+192.0.1.14 example.org
+192.0.1.15 example.org
+192.0.1.16 example.org
+192.0.1.17 example.org
+192.0.1.18 example.org
+192.0.1.19 example.org
+192.0.1.20 example.org
+192.0.1.21 example.org
+192.0.1.22 example.org
+192.0.1.23 example.org
+192.0.1.24 example.org
+192.0.1.25 example.org
+192.0.1.26 example.org
+192.0.1.27 example.org
+192.0.1.28 example.org
+192.0.1.29 example.org
+192.0.1.30 example.org
+192.0.1.31 example.org
+192.0.1.32 example.org
+192.0.1.33 example.org
+192.0.1.34 example.org
+192.0.1.35 example.org
+192.0.1.36 example.org
+192.0.1.37 example.org
+192.0.1.38 example.org
+192.0.1.39 example.org
+192.0.1.40 example.org
+192.0.1.41 example.org
+192.0.1.42 example.org
+192.0.1.43 example.org
+192.0.1.44 example.org
+192.0.1.45 example.org
+192.0.1.46 example.org
+192.0.1.47 example.org
+192.0.1.48 example.org
+192.0.1.49 example.org
+192.0.1.50 example.org
+192.0.1.51 example.org
+192.0.1.52 example.org
+192.0.1.53 example.org
+192.0.1.54 example.org
+192.0.1.55 example.org
+192.0.1.56 example.org
+192.0.1.57 example.org
+192.0.1.58 example.org
+192.0.1.59 example.org
+192.0.1.60 example.org
+192.0.1.61 example.org
+192.0.1.62 example.org
+192.0.1.63 example.org
+192.0.1.64 example.org
+192.0.1.65 example.org
+192.0.1.66 example.org
+192.0.1.67 example.org
+192.0.1.68 example.org
+192.0.1.69 example.org
+192.0.1.70 example.org
+192.0.1.71 example.org
+192.0.1.72 example.org
+192.0.1.73 example.org
+192.0.1.74 example.org
+192.0.1.75 example.org
+192.0.1.76 example.org
+192.0.1.77 example.org
+192.0.1.78 example.org
+192.0.1.79 example.org
+192.0.1.80 example.org
+192.0.1.81 example.org
+192.0.1.82 example.org
+192.0.1.83 example.org
+192.0.1.84 example.org
+192.0.1.85 example.org
+192.0.1.86 example.org
+192.0.1.87 example.org
+192.0.1.88 example.org
+192.0.1.89 example.org
+192.0.1.90 example.org
+192.0.1.91 example.org
+192.0.1.92 example.org
+192.0.1.93 example.org
+192.0.1.94 example.org
+192.0.1.95 example.org
+192.0.1.96 example.org
+192.0.1.97 example.org
+192.0.1.98 example.org
+192.0.1.99 example.org
+192.0.1.100 example.org
+192.0.1.101 example.org
+192.0.1.102 example.org
+192.0.1.103 example.org
+192.0.1.104 example.org
+192.0.1.105 example.org
+192.0.1.106 example.org
+192.0.1.107 example.org
+192.0.1.108 example.org
+192.0.1.109 example.org
+192.0.1.110 example.org
+192.0.1.111 example.org
+192.0.1.112 example.org
+192.0.1.113 example.org
+192.0.1.114 example.org
+192.0.1.115 example.org
+192.0.1.116 example.org
+192.0.1.117 example.org
+192.0.1.118 example.org
+192.0.1.119 example.org
+192.0.1.120 example.org
+192.0.1.121 example.org
+192.0.1.122 example.org
+192.0.1.123 example.org
+192.0.1.124 example.org
+192.0.1.125 example.org
+192.0.1.126 example.org
+192.0.1.127 example.org
+192.0.1.128 example.org
+192.0.1.129 example.org
+192.0.1.130 example.org
+192.0.1.131 example.org
+192.0.1.132 example.org
+192.0.1.133 example.org
+192.0.1.134 example.org
+192.0.1.135 example.org
+192.0.1.136 example.org
+192.0.1.137 example.org
+192.0.1.138 example.org
+192.0.1.139 example.org
+192.0.1.140 example.org
+192.0.1.141 example.org
+192.0.1.142 example.org
+192.0.1.143 example.org
+192.0.1.144 example.org
+192.0.1.145 example.org
+192.0.1.146 example.org
+192.0.1.147 example.org
+192.0.1.148 example.org
+192.0.1.149 example.org
+192.0.1.150 example.org
+192.0.1.151 example.org
+192.0.1.152 example.org
+192.0.1.153 example.org
+192.0.1.154 example.org
+192.0.1.155 example.org
+192.0.1.156 example.org
+192.0.1.157 example.org
+192.0.1.158 example.org
+192.0.1.159 example.org
+192.0.1.160 example.org
+192.0.1.161 example.org
+192.0.1.162 example.org
+192.0.1.163 example.org
+192.0.1.164 example.org
+192.0.1.165 example.org
+192.0.1.166 example.org
+192.0.1.167 example.org
+192.0.1.168 example.org
+192.0.1.169 example.org
+192.0.1.170 example.org
+192.0.1.171 example.org
+192.0.1.172 example.org
+192.0.1.173 example.org
+192.0.1.174 example.org
+192.0.1.175 example.org
+192.0.1.176 example.org
+192.0.1.177 example.org
+192.0.1.178 example.org
+192.0.1.179 example.org
+192.0.1.180 example.org
+192.0.1.181 example.org
+192.0.1.182 example.org
+192.0.1.183 example.org
+192.0.1.184 example.org
+192.0.1.185 example.org
+192.0.1.186 example.org
+192.0.1.187 example.org
+192.0.1.188 example.org
+192.0.1.189 example.org
+192.0.1.190 example.org
+192.0.1.191 example.org
+192.0.1.192 example.org
+192.0.1.193 example.org
+192.0.1.194 example.org
+192.0.1.195 example.org
+192.0.1.196 example.org
+192.0.1.197 example.org
+192.0.1.198 example.org
+192.0.1.199 example.org
+192.0.1.200 example.org
+192.0.1.201 example.org
+192.0.1.202 example.org
+192.0.1.203 example.org
+192.0.1.204 example.org
+192.0.1.205 example.org
+192.0.1.206 example.org
+192.0.1.207 example.org
+192.0.1.208 example.org
+192.0.1.209 example.org
+192.0.1.210 example.org
+192.0.1.211 example.org
+192.0.1.212 example.org
+192.0.1.213 example.org
+192.0.1.214 example.org
+192.0.1.215 example.org
+192.0.1.216 example.org
+192.0.1.217 example.org
+192.0.1.218 example.org
+192.0.1.219 example.org
+192.0.1.220 example.org
+192.0.1.221 example.org
+192.0.1.222 example.org
+192.0.1.223 example.org
+192.0.1.224 example.org
+192.0.1.225 example.org
+192.0.1.226 example.org
+192.0.1.227 example.org
+192.0.1.228 example.org
+192.0.1.229 example.org
+192.0.1.230 example.org
+192.0.1.231 example.org
+192.0.1.232 example.org
+192.0.1.233 example.org
+192.0.1.234 example.org
+192.0.1.235 example.org
+192.0.1.236 example.org
+192.0.1.237 example.org
+192.0.1.238 example.org
+192.0.1.239 example.org
+192.0.1.240 example.org
+192.0.1.241 example.org
+192.0.1.242 example.org
+192.0.1.243 example.org
+192.0.1.244 example.org
+192.0.1.245 example.org
+192.0.1.246 example.org
+192.0.1.247 example.org
+192.0.1.248 example.org
+192.0.1.249 example.org
+192.0.1.250 example.org
+192.0.1.251 example.org
+192.0.1.252 example.org
+192.0.1.253 example.org
+192.0.1.254 example.org
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 18dccd5924..3d9bea60c6 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -458,11 +458,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (name != NULL)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->family = AF_UNSPEC;
- at->scopeid = 0;
- at->next = NULL;
-
if (req->ai_flags & AI_IDN)
{
char *out;
@@ -473,13 +468,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ uint32_t addr[4];
+ if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
{
+ at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- at->family = AF_INET;
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET;
+ }
else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
{
- at->addr[3] = at->addr[0];
+ at->addr[3] = addr[0];
at->addr[2] = htonl (0xffff);
at->addr[1] = 0;
at->addr[0] = 0;
@@ -493,49 +496,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_flags & AI_CANONNAME)
canon = name;
+
+ goto process_list;
}
- else if (at->family == AF_UNSPEC)
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
+
+ if (e > 0)
{
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, at->addr);
+ at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET6;
+ }
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (addr))
+ {
+ at->addr[0] = addr[3];
+ at->addr[1] = addr[1];
+ at->addr[2] = addr[2];
+ at->addr[3] = addr[3];
+ at->family = AF_INET;
+ }
else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name,
- at->addr);
- if (e > 0)
{
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- at->family = AF_INET6;
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (at->addr))
- {
- at->addr[0] = at->addr[3];
- at->family = AF_INET;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
-
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_ADDRFAMILY;
+ goto free_and_return;
+ }
- if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1,
+ &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto free_and_return;
}
+
+ if (req->ai_flags & AI_CANONNAME)
+ canon = name;
+
+ goto process_list;
}
- if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
+ if ((req->ai_flags & AI_NUMERICHOST) == 0)
{
- struct gaih_addrtuple **pat = &at;
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -543,6 +559,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
enum nss_status status = NSS_STATUS_UNAVAIL;
int no_more;
struct resolv_context *res_ctx = NULL;
+ bool do_merge = false;
/* If we do not have to look for IPv6 addresses or the canonical
name, use the simple, old functions, which do not support
@@ -579,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
result = -EAI_MEMORY;
goto free_and_return;
}
- *pat = addrmem;
+ at = addrmem;
}
else
{
@@ -632,6 +649,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &at;
+
for (int i = 0; i < air->naddrs; ++i)
{
socklen_t size = (air->family[i] == AF_INET
@@ -695,12 +714,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
free (air);
- if (at->family == AF_UNSPEC)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
-
goto process_list;
}
else if (err == 0)
@@ -732,6 +745,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ at = NULL;
+ free (canonbuf);
+ free (addrmem);
+ canon = canonbuf = NULL;
+ addrmem = NULL;
+ got_ipv6 = false;
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
no_data = 0;
nss_gethostbyname4_r *fct4 = NULL;
@@ -744,12 +773,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
while (1)
{
- status = DL_CALL_FCT (fct4, (name, pat,
+ status = DL_CALL_FCT (fct4, (name, &at,
tmpbuf->data, tmpbuf->length,
&errno, &h_errno,
NULL));
if (status == NSS_STATUS_SUCCESS)
break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ at = NULL;
if (status != NSS_STATUS_TRYAGAIN
|| errno != ERANGE || h_errno != NETDB_INTERNAL)
{
@@ -774,7 +805,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = (*pat)->name;
+ canon = at->name;
+
+ struct gaih_addrtuple **pat = &at;
while (*pat != NULL)
{
@@ -826,6 +859,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (fct != NULL)
{
+ struct gaih_addrtuple **pat = &at;
+
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
@@ -899,6 +934,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
nip++;
if (nip->module == NULL)
no_more = -1;
@@ -930,7 +969,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
process_list:
- if (at->family == AF_UNSPEC)
+ if (at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v3 01/12] Simplify allocations and fix merge and continue actions [BZ #28931]
2022-03-17 8:11 ` [PATCH v3 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
@ 2022-03-17 21:47 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 21:47 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
LGTM. I expected multiple test cases (one per nsswitch) but forgot
about the hot reloading, so we're testing that too :-)
Reviewed-by: DJ Delorie <dj@redhat.com>
Siddhesh Poyarekar <siddhesh@sourceware.org> writes:
> diff --git a/nss/Makefile b/nss/Makefile
> + tst-nss-gai-actions \
Ok.
> diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
> +/* Test continue and merge NSS actions for getaddrinfo.
> + Copyright The GNU Toolchain Authors.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <dlfcn.h>
> +#include <gnu/lib-names.h>
> +#include <nss.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <support/check.h>
> +#include <support/format_nss.h>
> +#include <support/support.h>
> +#include <support/xstdio.h>
> +#include <support/xunistd.h>
Ok.
> +enum
> +{
> + ACTION_MERGE = 0,
> + ACTION_CONTINUE,
> +};
> +
> +static const char *
> +family_str (int family)
> +{
> + switch (family)
> + {
> + case AF_UNSPEC:
> + return "AF_UNSPEC";
> + case AF_INET:
> + return "AF_INET";
> + default:
> + __builtin_unreachable ();
> + }
> +}
> +
> +static const char *
> +action_str (int action)
> +{
> + switch (action)
> + {
> + case ACTION_MERGE:
> + return "merge";
> + case ACTION_CONTINUE:
> + return "continue";
> + default:
> + __builtin_unreachable ();
> + }
> +}
Ok.
> +static void
> +do_one_test (int action, int family, bool canon)
> +{
> + struct addrinfo hints =
> + {
> + .ai_family = family,
> + };
> +
> + struct addrinfo *ai;
> +
> + if (canon)
> + hints.ai_flags = AI_CANONNAME;
> +
> + printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
> + action_str (action), family_str (family),
> + canon ? "AI_CANONNAME" : "");
Ok.
> + int ret = getaddrinfo ("example.org", "80", &hints, &ai);
Ok. Do we need an /etc/services? Probably not.
> + switch (action)
> + {
> + case ACTION_MERGE:
> + if (ret == 0)
> + {
> + char *formatted = support_format_addrinfo (ai, ret);
> +
> + printf ("merge unexpectedly succeeded:\n %s\n", formatted);
> + support_record_failure ();
> + free (formatted);
> + }
> + else
> + return;
Ok.
> + case ACTION_CONTINUE:
> + {
> + char *formatted = support_format_addrinfo (ai, ret);
> +
> + /* Verify that the result appears exactly once. */
> + const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
> + "address: DGRAM/UDP 192.0.0.1 80\n"
> + "address: RAW/IP 192.0.0.1 80\n";
> +
> + const char *contains = strstr (formatted, expected);
> + const char *contains2 = NULL;
> +
> + if (contains != NULL)
> + contains2 = strstr (contains + strlen (expected), expected);
> +
> + if (contains == NULL || contains2 != NULL)
> + {
> + printf ("continue failed:\n%s\n", formatted);
> + support_record_failure ();
> + }
> +
> + free (formatted);
> + break;
Ok.
> + }
> + default:
> + __builtin_unreachable ();
> + }
> +}
Ok.
> +static void
> +do_one_test_set (int action)
> +{
> + char buf[32];
> +
> + snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
> + action_str (action));
> + __nss_configure_lookup ("hosts", buf);
> +
> + do_one_test (action, AF_UNSPEC, false);
> + do_one_test (action, AF_INET, false);
> + do_one_test (action, AF_INET, true);
> +}
> +
> +static int
> +do_test (void)
> +{
> + do_one_test_set (ACTION_CONTINUE);
> + do_one_test_set (ACTION_MERGE);
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
Ok.
> diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf
> +multi on
Ok.
> diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts
> +192.0.0.1 example.org
> +192.0.0.2 example.org
> + . . .
> +192.0.1.252 example.org
> +192.0.1.253 example.org
> +192.0.1.254 example.org
Ok.
> diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
Unchanged from v2, ok.
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 02/12] gaih_inet: Simplify canon name resolution
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
` (9 subsequent siblings)
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Simplify logic for allocation of canon to remove the canonbuf variable;
canon now always points to an allocated block. Also pull the canon name
set into a separate function.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 130 +++++++++++++++++++++---------------
1 file changed, 75 insertions(+), 55 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 3d9bea60c6..0629fd147b 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -285,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
\
if (localcanon != NULL && canon == NULL) \
{ \
- canonbuf = __strdup (localcanon); \
+ char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
@@ -323,6 +323,41 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
return __strdup (name);
}
+/* Process looked up canonical name and if necessary, decode to IDNA. Result
+ is a new string written to CANONP and the earlier string is freed. */
+
+static int
+process_canonname (const struct addrinfo *req, const char *orig_name,
+ char **canonp)
+{
+ char *canon = *canonp;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0)
+ {
+ bool do_idn = req->ai_flags & AI_CANONIDN;
+ if (do_idn)
+ {
+ char *out;
+ int rc = __idna_from_dns_encoding (canon ?: orig_name, &out);
+ if (rc == 0)
+ {
+ free (canon);
+ canon = out;
+ }
+ else if (rc == EAI_IDN_ENCODE)
+ /* Use the punycode name as a fallback. */
+ do_idn = false;
+ else
+ return -rc;
+ }
+ if (!do_idn && canon == NULL && (canon = __strdup (orig_name)) == NULL)
+ return -EAI_MEMORY;
+ }
+
+ *canonp = canon;
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -332,7 +367,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
- const char *canon = NULL;
+ char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -453,7 +488,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
- char *canonbuf = NULL;
int result = 0;
if (name != NULL)
@@ -495,7 +529,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -545,7 +587,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
goto process_list;
}
@@ -676,9 +726,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
(*pat)->next = NULL;
if (added_canon || air->canon == NULL)
(*pat)->name = NULL;
- else if (canonbuf == NULL)
+ else if (canon == NULL)
{
- canonbuf = __strdup (air->canon);
+ char *canonbuf = __strdup (air->canon);
if (canonbuf == NULL)
{
result = -EAI_MEMORY;
@@ -748,9 +798,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
/* Always start afresh; continue should discard previous results
and the hosts database does not support merge. */
at = NULL;
- free (canonbuf);
+ free (canon);
free (addrmem);
- canon = canonbuf = NULL;
+ canon = NULL;
addrmem = NULL;
got_ipv6 = false;
@@ -805,7 +855,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = at->name;
+ {
+ char *canonbuf = __strdup (at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ canon = canonbuf;
+ }
struct gaih_addrtuple **pat = &at;
@@ -893,7 +952,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((req->ai_flags & AI_CANONNAME) != 0
&& canon == NULL)
{
- canonbuf = getcanonname (nip, at, name);
+ char *canonbuf = getcanonname (nip, at, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
@@ -1004,6 +1063,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
{
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &canon)) != 0)
+ goto free_and_return;
+
struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
@@ -1014,48 +1077,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
*/
while (at2 != NULL)
{
- /* Only the first entry gets the canonical name. */
- if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
- {
- if (canon == NULL)
- /* If the canonical name cannot be determined, use
- the passed in string. */
- canon = orig_name;
-
- bool do_idn = req->ai_flags & AI_CANONIDN;
- if (do_idn)
- {
- char *out;
- int rc = __idna_from_dns_encoding (canon, &out);
- if (rc == 0)
- canon = out;
- else if (rc == EAI_IDN_ENCODE)
- /* Use the punycode name as a fallback. */
- do_idn = false;
- else
- {
- result = -rc;
- goto free_and_return;
- }
- }
- if (!do_idn)
- {
- if (canonbuf != NULL)
- /* We already allocated the string using malloc, but
- the buffer is now owned by canon. */
- canonbuf = NULL;
- else
- {
- canon = __strdup (canon);
- if (canon == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
- }
- }
-
family = at2->family;
if (family == AF_INET6)
{
@@ -1078,7 +1099,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
if (ai == NULL)
{
- free ((char *) canon);
result = -EAI_MEMORY;
goto free_and_return;
}
@@ -1138,7 +1158,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canonbuf);
+ free (canon);
return result;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852]
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 01/12] Simplify allocations and fix merge and continue actions [BZ #28931] Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 02/12] gaih_inet: Simplify canon name resolution Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 04/12] gaih_inet: Simplify service resolution Siddhesh Poyarekar
` (8 subsequent siblings)
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Use realloc in convert_hostent_to_gaih_addrtuple and fix up pointers in
the result list so that a single block is maintained for
hostbyname3_r/hostbyname2_r and freed in gaih_inet. This result is
never merged with any other results, since the hosts database does not
permit merging.
Resolves BZ #28852.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 34 +++++++++++++++++++++++++---------
1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 0629fd147b..e9deb2da6a 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -189,19 +189,16 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
return 0;
}
-/* Convert struct hostent to a list of struct gaih_addrtuple objects.
- h_name is not copied, and the struct hostent object must not be
- deallocated prematurely. *RESULT must be NULL or a pointer to a
- linked-list. The new addresses are appended at the end. */
+/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
+ is not copied, and the struct hostent object must not be deallocated
+ prematurely. The new addresses are appended to the tuple array in
+ RESULT. */
static bool
convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
int family,
struct hostent *h,
struct gaih_addrtuple **result)
{
- while (*result)
- result = &(*result)->next;
-
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
for (char **p = h->h_addr_list; *p != NULL; ++p)
@@ -212,10 +209,30 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = calloc (count, sizeof (*array));
+ struct gaih_addrtuple *array = *result;
+ size_t old = 0;
+
+ while (array != NULL)
+ {
+ old++;
+ array = array->next;
+ }
+
+ array = realloc (*result, (old + count) * sizeof (*array));
+
if (array == NULL)
return false;
+ *result = array;
+
+ /* Update the next pointers on reallocation. */
+ for (size_t i = 0; i < old; i++)
+ array[i].next = array + i + 1;
+
+ array += old;
+
+ memset (array, 0, count * sizeof (*array));
+
for (size_t i = 0; i < count; ++i)
{
if (family == AF_INET && req->ai_family == AF_INET6)
@@ -235,7 +252,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array[0].name = h->h_name;
array[count - 1].next = NULL;
- *result = array;
return true;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 04/12] gaih_inet: Simplify service resolution
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (2 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 03/12] getaddrinfo: Fix leak with AI_ALL [BZ #28852] Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 05/12] gaih_inet: make numeric lookup a separate routine Siddhesh Poyarekar
` (7 subsequent siblings)
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Refactor the code to split out the service resolution code into a
separate function. Allocate the service tuples array just once to the
size of the typeproto array, thus avoiding the unnecessary pointer
chasing and stack allocations.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 178 ++++++++++++++++--------------------
1 file changed, 78 insertions(+), 100 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index e9deb2da6a..dae5e9f55f 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -100,14 +100,12 @@ struct gaih_service
struct gaih_servtuple
{
- struct gaih_servtuple *next;
int socktype;
int protocol;
int port;
+ bool set;
};
-static const struct gaih_servtuple nullserv;
-
struct gaih_typeproto
{
@@ -180,11 +178,11 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
while (r);
- st->next = NULL;
st->socktype = tp->socktype;
st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
? req->ai_protocol : tp->protocol);
st->port = s->s_port;
+ st->set = true;
return 0;
}
@@ -375,20 +373,11 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
}
static int
-gaih_inet (const char *name, const struct gaih_service *service,
- const struct addrinfo *req, struct addrinfo **pai,
- unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
+ struct gaih_servtuple *st, struct scratch_buffer *tmpbuf)
{
+ int i;
const struct gaih_typeproto *tp = gaih_inet_typeproto;
- struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
- struct gaih_addrtuple *at = NULL;
- bool got_ipv6 = false;
- char *canon = NULL;
- const char *orig_name = name;
-
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
if (req->ai_protocol || req->ai_socktype)
{
@@ -410,98 +399,88 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
- int port = 0;
- if (service != NULL)
+ if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ return -EAI_SERVICE;
+
+ if (service == NULL || service->num >= 0)
{
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- return -EAI_SERVICE;
+ int port = service != NULL ? htons (service->num) : 0;
- if (service->num < 0)
+ if (req->ai_socktype || req->ai_protocol)
{
- if (tp->name[0])
- {
- st = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple), alloca_used);
-
- int rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- if (__glibc_unlikely (rc != 0))
- return rc;
- }
- else
- {
- struct gaih_servtuple **pst = &st;
- for (tp++; tp->name[0]; tp++)
- {
- struct gaih_servtuple *newp;
+ st[0].socktype = tp->socktype;
+ st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+ ? req->ai_protocol : tp->protocol);
+ st[0].port = port;
+ st[0].set = true;
- if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
- continue;
+ return 0;
+ }
- if (req->ai_socktype != 0
- && req->ai_socktype != tp->socktype)
- continue;
- if (req->ai_protocol != 0
- && !(tp->protoflag & GAI_PROTO_PROTOANY)
- && req->ai_protocol != tp->protocol)
- continue;
+ /* Neither socket type nor protocol is set. Return all socket types
+ we know about. */
+ for (i = 0, ++tp; tp->name[0]; ++tp)
+ if (tp->defaultflag)
+ {
+ st[i].socktype = tp->socktype;
+ st[i].protocol = tp->protocol;
+ st[i].port = port;
+ st[i++].set = true;
+ }
- newp = (struct gaih_servtuple *)
- alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
+ return 0;
+ }
- if (gaih_inet_serv (service->name,
- tp, req, newp, tmpbuf) != 0)
- continue;
+ if (tp->name[0])
+ return gaih_inet_serv (service->name, tp, req, st, tmpbuf);
- *pst = newp;
- pst = &(newp->next);
- }
- if (st == (struct gaih_servtuple *) &nullserv)
- return -EAI_SERVICE;
- }
- }
- else
- {
- port = htons (service->num);
- goto got_port;
- }
- }
- else
+ for (i = 0, tp++; tp->name[0]; tp++)
{
- got_port:
+ if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+ continue;
- if (req->ai_socktype || req->ai_protocol)
- {
- st = alloca_account (sizeof (struct gaih_servtuple), alloca_used);
- st->next = NULL;
- st->socktype = tp->socktype;
- st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
- ? req->ai_protocol : tp->protocol);
- st->port = port;
- }
- else
- {
- /* Neither socket type nor protocol is set. Return all socket types
- we know about. */
- struct gaih_servtuple **lastp = &st;
- for (++tp; tp->name[0]; ++tp)
- if (tp->defaultflag)
- {
- struct gaih_servtuple *newp;
+ if (req->ai_socktype != 0
+ && req->ai_socktype != tp->socktype)
+ continue;
+ if (req->ai_protocol != 0
+ && !(tp->protoflag & GAI_PROTO_PROTOANY)
+ && req->ai_protocol != tp->protocol)
+ continue;
- newp = alloca_account (sizeof (struct gaih_servtuple),
- alloca_used);
- newp->next = NULL;
- newp->socktype = tp->socktype;
- newp->protocol = tp->protocol;
- newp->port = port;
+ if (gaih_inet_serv (service->name,
+ tp, req, &st[i], tmpbuf) != 0)
+ continue;
- *lastp = newp;
- lastp = &newp->next;
- }
- }
+ i++;
}
+ if (!st[0].set)
+ return -EAI_SERVICE;
+
+ return 0;
+}
+
+static int
+gaih_inet (const char *name, const struct gaih_service *service,
+ const struct addrinfo *req, struct addrinfo **pai,
+ unsigned int *naddrs, struct scratch_buffer *tmpbuf)
+{
+ struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
+ / sizeof (struct gaih_typeproto)] = {0};
+
+ struct gaih_addrtuple *at = NULL;
+ bool got_ipv6 = false;
+ char *canon = NULL;
+ const char *orig_name = name;
+
+ /* Reserve stack memory for the scratch buffer in the getaddrinfo
+ function. */
+ size_t alloca_used = sizeof (struct scratch_buffer);
+
+ int rc;
+ if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
+ return rc;
+
bool malloc_name = false;
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
@@ -1083,7 +1062,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((result = process_canonname (req, orig_name, &canon)) != 0)
goto free_and_return;
- struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen;
sa_family_t family;
@@ -1109,7 +1087,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
socklen = sizeof (struct sockaddr_in);
- for (st2 = st; st2 != NULL; st2 = st2->next)
+ for (int i = 0; st[i].set; i++)
{
struct addrinfo *ai;
ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
@@ -1121,8 +1099,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_flags = req->ai_flags;
ai->ai_family = family;
- ai->ai_socktype = st2->socktype;
- ai->ai_protocol = st2->protocol;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
ai->ai_addrlen = socklen;
ai->ai_addr = (void *) (ai + 1);
@@ -1144,7 +1122,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) ai->ai_addr;
- sin6p->sin6_port = st2->port;
+ sin6p->sin6_port = st[i].port;
sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr));
@@ -1154,7 +1132,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
struct sockaddr_in *sinp =
(struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st2->port;
+ sinp->sin_port = st[i].port;
memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr));
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 05/12] gaih_inet: make numeric lookup a separate routine
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (3 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 04/12] gaih_inet: Simplify service resolution Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 06/12] gaih_inet: Split simple gethostbyname into its own function Siddhesh Poyarekar
` (6 subsequent siblings)
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Introduce the gaih_result structure and general paradigm for cleanups
that follow to process the lookup request and return a result. A lookup
function (like text_to_binary_address), should return an integer error
code and set members of gaih_result based on what it finds. If the
function does not have a result and no errors have occurred during the
lookup, it should return 0 and res.at should be set to NULL, allowing a
subsequent function to do the lookup until we run out of options.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 891 ++++++++++++++++++------------------
1 file changed, 452 insertions(+), 439 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index dae5e9f55f..19bb13db59 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -116,6 +116,12 @@ struct gaih_typeproto
char name[8];
};
+struct gaih_result
+{
+ struct gaih_addrtuple *at;
+ char *canon;
+};
+
/* Values for `protoflag'. */
#define GAI_PROTO_NOSERVICE 1
#define GAI_PROTO_PROTOANY 2
@@ -297,7 +303,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
*pat = addrmem; \
\
- if (localcanon != NULL && canon == NULL) \
+ if (localcanon != NULL && res.canon == NULL) \
{ \
char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
@@ -306,7 +312,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
result = -EAI_SYSTEM; \
goto free_and_return; \
} \
- canon = canonbuf; \
+ res.canon = canonbuf; \
} \
if (_family == AF_INET6 && *pat != NULL) \
got_ipv6 = true; \
@@ -342,9 +348,9 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
static int
process_canonname (const struct addrinfo *req, const char *orig_name,
- char **canonp)
+ struct gaih_result *res)
{
- char *canon = *canonp;
+ char *canon = res->canon;
if ((req->ai_flags & AI_CANONNAME) != 0)
{
@@ -368,7 +374,7 @@ process_canonname (const struct addrinfo *req, const char *orig_name,
return -EAI_MEMORY;
}
- *canonp = canon;
+ res->canon = canon;
return 0;
}
@@ -460,6 +466,105 @@ get_servtuples (const struct gaih_service *service, const struct addrinfo *req,
return 0;
}
+/* 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
+ returned. */
+
+static int
+text_to_binary_address (const char *name, const struct addrinfo *req,
+ struct gaih_result *res)
+{
+ struct gaih_addrtuple *at = res->at;
+ int result = 0;
+
+ assert (at != NULL);
+
+ memset (at->addr, 0, sizeof (at->addr));
+ if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ {
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+ at->family = AF_INET;
+ else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
+ {
+ at->addr[3] = at->addr[0];
+ at->addr[2] = htonl (0xffff);
+ at->addr[1] = 0;
+ at->addr[0] = 0;
+ at->family = AF_INET6;
+ }
+ else
+ {
+ result = -EAI_ADDRFAMILY;
+ goto out;
+ }
+
+ if (req->ai_flags & AI_CANONNAME)
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+ return 0;
+ }
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, at->addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, at->addr);
+
+ if (e > 0)
+ {
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ at->family = AF_INET6;
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ {
+ at->addr[0] = at->addr[3];
+ at->family = AF_INET;
+ }
+ else
+ {
+ result = -EAI_ADDRFAMILY;
+ goto out;
+ }
+
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1, &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto out;
+ }
+
+ if (req->ai_flags & AI_CANONNAME)
+ {
+ char *canonbuf = __strdup (name);
+ if (canonbuf == NULL)
+ {
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+ return 0;
+ }
+
+ if ((req->ai_flags & AI_NUMERICHOST))
+ result = -EAI_NONAME;
+
+out:
+ res->at = NULL;
+ return result;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -468,9 +573,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_servtuple st[sizeof (gaih_inet_typeproto)
/ sizeof (struct gaih_typeproto)] = {0};
- struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
- char *canon = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -485,6 +588,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple *addrmem = NULL;
int result = 0;
+ struct gaih_result res = {0};
if (name != NULL)
{
if (req->ai_flags & AI_IDN)
@@ -497,533 +601,441 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- uint32_t addr[4];
- if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
+ res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ res.at->scopeid = 0;
+ res.at->next = NULL;
+
+ if ((result = text_to_binary_address (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+
+ 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;
+ bool do_merge = false;
+
+ /* If we do not have to look for IPv6 addresses or the canonical
+ name, use the simple, old functions, which do not support
+ IPv6 scope ids, nor retrieving the canonical name. */
+ if (req->ai_family == AF_INET
+ && (req->ai_flags & AI_CANONNAME) == 0)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->scopeid = 0;
- at->next = NULL;
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- {
- memcpy (at->addr, addr, sizeof (at->addr));
- at->family = AF_INET;
- }
- else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
- {
- at->addr[3] = addr[0];
- at->addr[2] = htonl (0xffff);
- at->addr[1] = 0;
- at->addr[0] = 0;
- at->family = AF_INET6;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
+ int rc;
+ struct hostent th;
+ struct hostent *h;
- if (req->ai_flags & AI_CANONNAME)
+ while (1)
{
- char *canonbuf = __strdup (name);
- if (canonbuf == NULL)
+ rc = __gethostbyname2_r (name, AF_INET, &th,
+ tmpbuf->data, tmpbuf->length,
+ &h, &h_errno);
+ if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
{
result = -EAI_MEMORY;
goto free_and_return;
}
- canon = canonbuf;
}
- goto process_list;
- }
-
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
-
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, addr);
- else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
-
- if (e > 0)
- {
- at = alloca_account (sizeof (struct gaih_addrtuple),
- alloca_used);
- at->scopeid = 0;
- at->next = NULL;
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- {
- memcpy (at->addr, addr, sizeof (at->addr));
- at->family = AF_INET6;
- }
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (addr))
+ if (rc == 0)
{
- at->addr[0] = addr[3];
- at->addr[1] = addr[1];
- at->addr[2] = addr[2];
- at->addr[3] = addr[3];
- at->family = AF_INET;
+ if (h != NULL)
+ {
+ /* We found data, convert it. */
+ if (!convert_hostent_to_gaih_addrtuple
+ (req, AF_INET, h, &addrmem))
+ {
+ result = -EAI_MEMORY;
+ goto free_and_return;
+ }
+ res.at = addrmem;
+ }
+ else
+ {
+ if (h_errno == NO_DATA)
+ result = -EAI_NODATA;
+ else
+ result = -EAI_NONAME;
+ goto free_and_return;
+ }
}
else
{
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
+ if (h_errno == NETDB_INTERNAL)
+ result = -EAI_SYSTEM;
+ else if (h_errno == TRY_AGAIN)
+ result = -EAI_AGAIN;
+ else
+ /* We made requests but they turned out no data.
+ The name is known, though. */
+ result = -EAI_NODATA;
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
goto free_and_return;
}
- if (req->ai_flags & AI_CANONNAME)
+ goto process_list;
+ }
+
+#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)
{
- char *canonbuf = __strdup (name);
- if (canonbuf == 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;
}
- canon = canonbuf;
- }
- goto process_list;
- }
-
- if ((req->ai_flags & AI_NUMERICHOST) == 0)
- {
- 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;
- bool do_merge = false;
-
- /* If we do not have to look for IPv6 addresses or the canonical
- name, use the simple, old functions, which do not support
- IPv6 scope ids, nor retrieving the canonical name. */
- if (req->ai_family == AF_INET
- && (req->ai_flags & AI_CANONNAME) == 0)
- {
- int rc;
- struct hostent th;
- struct hostent *h;
+ struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &res.at;
- while (1)
+ for (int i = 0; i < air->naddrs; ++i)
{
- rc = __gethostbyname2_r (name, AF_INET, &th,
- tmpbuf->data, tmpbuf->length,
- &h, &h_errno);
- if (rc != ERANGE || h_errno != NETDB_INTERNAL)
- break;
- if (!scratch_buffer_grow (tmpbuf))
+ 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))
{
- result = -EAI_MEMORY;
- goto free_and_return;
+ /* Skip over non-matching result. */
+ addrs += size;
+ continue;
}
- }
- if (rc == 0)
- {
- if (h != NULL)
+ 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)
{
- /* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple
- (req, AF_INET, h, &addrmem))
+ char *canonbuf = __strdup (air->canon);
+ if (canonbuf == NULL)
{
result = -EAI_MEMORY;
goto free_and_return;
}
- at = addrmem;
+ res.canon = (*pat)->name = canonbuf;
}
- else
+
+ if (air->family[i] == AF_INET
+ && req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED))
{
- if (h_errno == NO_DATA)
- result = -EAI_NODATA;
- else
- result = -EAI_NONAME;
- goto free_and_return;
+ (*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;
}
- else
- {
- if (h_errno == NETDB_INTERNAL)
- result = -EAI_SYSTEM;
- else if (h_errno == TRY_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;
- }
+ 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;
-#ifdef USE_NSCD
- if (__nss_not_use_nscd_hosts > 0
- && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
- __nss_not_use_nscd_hosts = 0;
+ goto free_and_return;
+ }
+ }
+#endif
+
+ no_more = !__nss_database_get (nss_database_hosts, &nip);
- if (!__nss_not_use_nscd_hosts
- && !__nss_database_custom[NSS_DBSIDX_hosts])
+ /* 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)
+ {
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ res.at = NULL;
+ free (res.canon);
+ free (addrmem);
+ res.canon = NULL;
+ addrmem = NULL;
+ got_ipv6 = false;
+
+ if (do_merge)
{
- /* Try to use nscd. */
- struct nscd_ai_result *air = NULL;
- int err = __nscd_getai (name, &air, &h_errno);
- if (air != NULL)
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
+ 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)
+ {
+ while (1)
{
- /* Transform into gaih_addrtuple list. */
- bool added_canon = (req->ai_flags & AI_CANONNAME) == 0;
- char *addrs = air->addrs;
+ status = DL_CALL_FCT (fct4, (name, &res.at,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno,
+ NULL));
+ if (status == NSS_STATUS_SUCCESS)
+ break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ res.at = NULL;
+ 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;
+ }
- addrmem = calloc (air->naddrs, sizeof (*addrmem));
- if (addrmem == NULL)
+ if (!scratch_buffer_grow (tmpbuf))
{
+ __resolv_context_put (res_ctx);
result = -EAI_MEMORY;
goto free_and_return;
}
+ }
- struct gaih_addrtuple *addrfree = addrmem;
- struct gaih_addrtuple **pat = &at;
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ assert (!no_data);
+ no_data = 1;
- for (int i = 0; i < air->naddrs; ++i)
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res.canon == NULL)
{
- 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))
+ char *canonbuf = __strdup (res.at->name);
+ if (canonbuf == NULL)
{
- /* Skip over non-matching result. */
- addrs += size;
- continue;
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto free_and_return;
}
+ res.canon = canonbuf;
+ }
- 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 (canon == NULL)
- {
- char *canonbuf = __strdup (air->canon);
- if (canonbuf == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- canon = (*pat)->name = canonbuf;
- }
+ struct gaih_addrtuple **pat = &res.at;
- if (air->family[i] == AF_INET
+ while (*pat != NULL)
+ {
+ if ((*pat)->family == AF_INET
&& req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED))
+ && (req->ai_flags & AI_V4MAPPED) != 0)
{
+ uint32_t *pataddr = (*pat)->addr;
(*pat)->family = AF_INET6;
- pataddr[3] = *(uint32_t *) addrs;
+ pataddr[3] = pataddr[0];
pataddr[2] = htonl (0xffff);
pataddr[1] = 0;
pataddr[0] = 0;
pat = &((*pat)->next);
- added_canon = true;
+ no_data = 0;
}
else if (req->ai_family == AF_UNSPEC
- || air->family[i] == req->ai_family)
+ || (*pat)->family == req->ai_family)
{
- (*pat)->family = air->family[i];
- memcpy (pataddr, addrs, size);
pat = &((*pat)->next);
- added_canon = true;
- if (air->family[i] == AF_INET6)
+
+ no_data = 0;
+ if (req->ai_family == AF_INET6)
got_ipv6 = true;
}
- addrs += size;
+ else
+ *pat = ((*pat)->next);
}
-
- 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;
- }
+ no_inet6_data = no_data;
}
-#endif
-
- 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)
+ else
{
- /* Always start afresh; continue should discard previous results
- and the hosts database does not support merge. */
- at = NULL;
- free (canon);
- free (addrmem);
- canon = NULL;
- addrmem = NULL;
- got_ipv6 = false;
-
- if (do_merge)
+ 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)
{
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- break;
- }
-
- 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");
+ struct gaih_addrtuple **pat = &res.at;
- if (fct4 != NULL)
- {
- while (1)
+ if (req->ai_family == AF_INET6
+ || req->ai_family == AF_UNSPEC)
{
- status = DL_CALL_FCT (fct4, (name, &at,
- tmpbuf->data, tmpbuf->length,
- &errno, &h_errno,
- NULL));
- if (status == NSS_STATUS_SUCCESS)
- break;
- /* gethostbyname4_r may write into AT, so reset it. */
- at = NULL;
- 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;
- }
+ 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 (!scratch_buffer_grow (tmpbuf))
+ if (req->ai_family == AF_INET)
{
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
+ no_inet6_data = no_data;
+ inet6_status = status;
}
}
- if (status == NSS_STATUS_SUCCESS)
+ /* 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)
{
- assert (!no_data);
- no_data = 1;
-
- if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
+ if ((req->ai_flags & AI_CANONNAME) != 0
+ && res.canon == NULL)
{
- char *canonbuf = __strdup (at->name);
+ char *canonbuf = getcanonname (nip, res.at, name);
if (canonbuf == NULL)
{
__resolv_context_put (res_ctx);
result = -EAI_MEMORY;
goto free_and_return;
}
- canon = canonbuf;
- }
-
- struct gaih_addrtuple **pat = &at;
-
- 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)
- {
- struct gaih_addrtuple **pat = &at;
-
- 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;
+ res.canon = canonbuf;
}
+ status = NSS_STATUS_SUCCESS;
}
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);
+ /* 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;
+ if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+ break;
- /* The hosts database does not support MERGE. */
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
- do_merge = true;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
- nip++;
- if (nip->module == NULL)
- no_more = -1;
- }
+ nip++;
+ if (nip->module == NULL)
+ no_more = -1;
+ }
- __resolv_context_put (res_ctx);
+ __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 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;
+ 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;
- goto free_and_return;
- }
+ goto free_and_return;
}
process_list:
- if (at == NULL)
+ if (res.at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;
@@ -1032,21 +1044,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
{
struct gaih_addrtuple *atr;
- atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- memset (at, '\0', sizeof (struct gaih_addrtuple));
+ atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ memset (res.at, '\0', sizeof (struct gaih_addrtuple));
if (req->ai_family == AF_UNSPEC)
{
- at->next = __alloca (sizeof (struct gaih_addrtuple));
- memset (at->next, '\0', sizeof (struct gaih_addrtuple));
+ res.at->next = __alloca (sizeof (struct gaih_addrtuple));
+ memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
}
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
{
- at->family = AF_INET6;
+ res.at->family = AF_INET6;
if ((req->ai_flags & AI_PASSIVE) == 0)
- memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
- atr = at->next;
+ memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+ atr = res.at->next;
}
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
@@ -1059,10 +1072,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
/* Set up the canonical name if we need it. */
- if ((result = process_canonname (req, orig_name, &canon)) != 0)
+ if ((result = process_canonname (req, orig_name, &res)) != 0)
goto free_and_return;
- struct gaih_addrtuple *at2 = at;
+ struct gaih_addrtuple *at2 = res.at;
size_t socklen;
sa_family_t family;
@@ -1105,8 +1118,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
ai->ai_addr = (void *) (ai + 1);
/* We only add the canonical name once. */
- ai->ai_canonname = (char *) canon;
- canon = NULL;
+ ai->ai_canonname = res.canon;
+ res.canon = NULL;
#ifdef _HAVE_SA_LEN
ai->ai_addr->sa_len = socklen;
@@ -1152,7 +1165,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canon);
+ free (res.canon);
return result;
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 06/12] gaih_inet: Split simple gethostbyname into its own function
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (4 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 05/12] gaih_inet: make numeric lookup a separate routine Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 07/12] gaih_inet: Split nscd lookup code " Siddhesh Poyarekar
` (5 subsequent siblings)
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Add a free_at flag in gaih_result to indicate if res.at needs to be
freed by the caller.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 127 ++++++++++++++++++------------------
1 file changed, 64 insertions(+), 63 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 19bb13db59..1137c959ac 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -120,6 +120,7 @@ struct gaih_result
{
struct gaih_addrtuple *at;
char *canon;
+ bool free_at;
};
/* Values for `protoflag'. */
@@ -565,6 +566,62 @@ out:
return result;
}
+/* If possible, call the simple, old functions, which do not support IPv6 scope
+ ids, nor retrieving the canonical name. */
+
+static int
+try_simple_gethostbyname (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf,
+ struct gaih_result *res)
+{
+ res->at = NULL;
+
+ if (req->ai_family != AF_INET || (req->ai_flags & AI_CANONNAME) != 0)
+ return 0;
+
+ int rc;
+ struct hostent th;
+ struct hostent *h;
+
+ while (1)
+ {
+ rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf->data,
+ tmpbuf->length, &h, &h_errno);
+ if (rc != ERANGE || h_errno != NETDB_INTERNAL)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+
+ if (rc == 0)
+ {
+ if (h != NULL)
+ {
+ /* We found data, convert it. RES->AT from the conversion will
+ either be an allocated block or NULL, both of which are safe to
+ pass to free (). */
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ return -EAI_MEMORY;
+
+ res->free_at = true;
+ return 0;
+ }
+ if (h_errno == NO_DATA)
+ return -EAI_NODATA;
+
+ return -EAI_NONAME;
+ }
+
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ return -EAI_AGAIN;
+
+ /* We made requests but they turned out no data.
+ The name is known, though. */
+ return -EAI_NODATA;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -610,6 +667,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
else if (res.at != NULL)
goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
+
int no_data = 0;
int no_inet6_data = 0;
nss_action_list nip;
@@ -619,69 +681,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct resolv_context *res_ctx = NULL;
bool do_merge = false;
- /* If we do not have to look for IPv6 addresses or the canonical
- name, use the simple, old functions, which do not support
- IPv6 scope ids, nor retrieving the canonical name. */
- if (req->ai_family == AF_INET
- && (req->ai_flags & AI_CANONNAME) == 0)
- {
- int rc;
- struct hostent th;
- struct hostent *h;
-
- while (1)
- {
- rc = __gethostbyname2_r (name, AF_INET, &th,
- tmpbuf->data, tmpbuf->length,
- &h, &h_errno);
- if (rc != ERANGE || h_errno != NETDB_INTERNAL)
- break;
- if (!scratch_buffer_grow (tmpbuf))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
-
- if (rc == 0)
- {
- if (h != NULL)
- {
- /* We found data, convert it. */
- if (!convert_hostent_to_gaih_addrtuple
- (req, AF_INET, h, &addrmem))
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.at = addrmem;
- }
- else
- {
- if (h_errno == NO_DATA)
- result = -EAI_NODATA;
- else
- result = -EAI_NONAME;
- goto free_and_return;
- }
- }
- else
- {
- if (h_errno == NETDB_INTERNAL)
- result = -EAI_SYSTEM;
- else if (h_errno == TRY_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;
- }
-
- goto process_list;
- }
-
#ifdef USE_NSCD
if (__nss_not_use_nscd_hosts > 0
&& ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY)
@@ -1165,6 +1164,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (malloc_name)
free ((char *) name);
free (addrmem);
+ if (res.free_at)
+ free (res.at);
free (res.canon);
return result;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 07/12] gaih_inet: Split nscd lookup code into its own function.
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (5 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 06/12] gaih_inet: Split simple gethostbyname into its own function Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 22:02 ` DJ Delorie
2022-03-17 8:11 ` [PATCH v3 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
` (4 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
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>
---
sysdeps/posix/getaddrinfo.c | 248 +++++++++++++++++++-----------------
1 file changed, 134 insertions(+), 114 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 1137c959ac..01be932b3f 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;
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 08/12] gaih_inet: separate nss lookup loop into its own function
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (6 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 07/12] gaih_inet: Split nscd lookup code " Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 22:05 ` DJ Delorie
2022-03-17 8:11 ` [PATCH v3 09/12] gaih_inet: make gethosts into a function Siddhesh Poyarekar
` (3 subsequent siblings)
11 siblings, 1 reply; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
---
sysdeps/posix/getaddrinfo.c | 563 ++++++++++++++++++------------------
1 file changed, 286 insertions(+), 277 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 01be932b3f..f70ce2c76b 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -159,6 +159,14 @@ static const struct addrinfo default_hints =
.ai_next = NULL
};
+static void
+gaih_result_reset (struct gaih_result *res)
+{
+ if (res->free_at)
+ free (res->at);
+ free (res->canon);
+ memset (res, 0, sizeof (*res));
+}
static int
gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
@@ -197,13 +205,10 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name
is not copied, and the struct hostent object must not be deallocated
- prematurely. The new addresses are appended to the tuple array in
- RESULT. */
+ prematurely. The new addresses are appended to the tuple array in RES. */
static bool
-convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
- int family,
- struct hostent *h,
- struct gaih_addrtuple **result)
+convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
+ struct hostent *h, struct gaih_result *res)
{
/* Count the number of addresses in h->h_addr_list. */
size_t count = 0;
@@ -215,7 +220,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr))
return true;
- struct gaih_addrtuple *array = *result;
+ struct gaih_addrtuple *array = res->at;
size_t old = 0;
while (array != NULL)
@@ -224,12 +229,14 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
array = array->next;
}
- array = realloc (*result, (old + count) * sizeof (*array));
+ array = realloc (res->at, (old + count) * sizeof (*array));
if (array == NULL)
return false;
- *result = array;
+ res->got_ipv6 = family == AF_INET6;
+ res->at = array;
+ res->free_at = true;
/* Update the next pointers on reallocation. */
for (size_t i = 0; i < old; i++)
@@ -278,7 +285,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_MEMORY; \
- goto free_and_return; \
+ goto out; \
} \
} \
if (status == NSS_STATUS_NOTFOUND \
@@ -288,7 +295,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
if (h_errno == TRY_AGAIN) \
no_data = EAI_AGAIN; \
@@ -297,27 +304,24 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
else if (status == NSS_STATUS_SUCCESS) \
{ \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \
+ if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- *pat = addrmem; \
\
- if (localcanon != NULL && res.canon == NULL) \
+ if (localcanon != NULL && res->canon == NULL) \
{ \
char *canonbuf = __strdup (localcanon); \
if (canonbuf == NULL) \
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto out; \
} \
- res.canon = canonbuf; \
+ res->canon = canonbuf; \
} \
- if (_family == AF_INET6 && *pat != NULL) \
- res.got_ipv6 = true; \
} \
}
@@ -590,6 +594,260 @@ out:
}
#endif
+static int
+get_nss_addresses (const char *name, const struct addrinfo *req,
+ struct scratch_buffer *tmpbuf, struct gaih_result *res)
+{
+ 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;
+ bool do_merge = false;
+ int result = 0;
+
+ 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)
+ {
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ gaih_result_reset (res);
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
+ 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)
+ {
+ while (1)
+ {
+ status = DL_CALL_FCT (fct4, (name, &res->at,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno,
+ NULL));
+ if (status == NSS_STATUS_SUCCESS)
+ break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ res->at = NULL;
+ 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;
+ }
+
+ if (!scratch_buffer_grow (tmpbuf))
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ assert (!no_data);
+ no_data = 1;
+
+ if ((req->ai_flags & AI_CANONNAME) != 0 && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (res->at->name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->canon = canonbuf;
+ }
+
+ struct gaih_addrtuple **pat = &res->at;
+
+ 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
+ && res->canon == NULL)
+ {
+ char *canonbuf = getcanonname (nip, res->at, name);
+ if (canonbuf == NULL)
+ {
+ __resolv_context_put (res_ctx);
+ result = -EAI_MEMORY;
+ goto out;
+ }
+ res->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;
+
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
+ 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 out;
+ }
+
+ 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;
+ }
+
+out:
+ if (result != 0)
+ gaih_result_reset (res);
+ return result;
+}
+
/* 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
@@ -723,7 +981,7 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
/* We found data, convert it. RES->AT from the conversion will
either be an allocated block or NULL, both of which are safe to
pass to free (). */
- if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, &res->at))
+ if (!convert_hostent_to_gaih_addrtuple (req, AF_INET, h, res))
return -EAI_MEMORY;
res->free_at = true;
@@ -801,264 +1059,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto process_list;
#endif
- 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;
- bool do_merge = false;
-
- 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)
- {
- /* Always start afresh; continue should discard previous results
- and the hosts database does not support merge. */
- res.at = NULL;
- free (res.canon);
- free (addrmem);
- res.canon = NULL;
- addrmem = NULL;
- got_ipv6 = false;
-
- if (do_merge)
- {
- __set_h_errno (NETDB_INTERNAL);
- __set_errno (EBUSY);
- break;
- }
-
- 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)
- {
- while (1)
- {
- status = DL_CALL_FCT (fct4, (name, &res.at,
- tmpbuf->data, tmpbuf->length,
- &errno, &h_errno,
- NULL));
- if (status == NSS_STATUS_SUCCESS)
- break;
- /* gethostbyname4_r may write into AT, so reset it. */
- res.at = NULL;
- 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;
- }
-
- if (!scratch_buffer_grow (tmpbuf))
- {
- __resolv_context_put (res_ctx);
- 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 && res.canon == NULL)
- {
- char *canonbuf = __strdup (res.at->name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.canon = canonbuf;
- }
-
- struct gaih_addrtuple **pat = &res.at;
-
- 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)
- {
- struct gaih_addrtuple **pat = &res.at;
-
- 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
- && res.canon == NULL)
- {
- char *canonbuf = getcanonname (nip, res.at, name);
- if (canonbuf == NULL)
- {
- __resolv_context_put (res_ctx);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- res.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;
-
- /* The hosts database does not support MERGE. */
- if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
- do_merge = true;
-
- 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 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;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- process_list:
- if (res.at == NULL)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
}
else
{
@@ -1089,6 +1097,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
+process_list:
{
/* Set up the canonical name if we need it. */
if ((result = process_canonname (req, orig_name, &res)) != 0)
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v3 08/12] gaih_inet: separate nss lookup loop into its own function
2022-03-17 8:11 ` [PATCH v3 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
@ 2022-03-17 22:05 ` DJ Delorie
0 siblings, 0 replies; 68+ messages in thread
From: DJ Delorie @ 2022-03-17 22:05 UTC (permalink / raw)
To: Siddhesh Poyarekar; +Cc: libc-alpha
Siddhesh Poyarekar <siddhesh@sourceware.org> writes:
> @@ -224,12 +229,14 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
> array = array->next;
> }
>
> - array = realloc (*result, (old + count) * sizeof (*array));
> + array = realloc (res->at, (old + count) * sizeof (*array));
>
> if (array == NULL)
> return false;
>
> - *result = array;
> + res->got_ipv6 = family == AF_INET6;
> + res->at = array;
> + res->free_at = true;
Ok.
Rest essentially unchanged from v2
LGTM
Reviewed-by: DJ Delorie <dj@redhat.com>
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 09/12] gaih_inet: make gethosts into a function
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (7 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 08/12] gaih_inet: separate nss lookup loop " Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 10/12] gaih_inet: split loopback lookup into its own function Siddhesh Poyarekar
` (2 subsequent siblings)
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
The macro is quite a pain to debug, so make gethosts into a function to
make it easier to maintain.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 117 ++++++++++++++++++------------------
1 file changed, 59 insertions(+), 58 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index f70ce2c76b..bc385dd322 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -268,63 +268,54 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family,
return true;
}
-#define gethosts(_family) \
- { \
- struct hostent th; \
- char *localcanon = NULL; \
- no_data = 0; \
- while (1) \
- { \
- status = DL_CALL_FCT (fct, (name, _family, &th, \
- tmpbuf->data, tmpbuf->length, \
- &errno, &h_errno, NULL, &localcanon)); \
- if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL \
- || errno != ERANGE) \
- break; \
- if (!scratch_buffer_grow (tmpbuf)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_MEMORY; \
- goto out; \
- } \
- } \
- if (status == NSS_STATUS_NOTFOUND \
- || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \
- { \
- if (h_errno == NETDB_INTERNAL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- if (h_errno == TRY_AGAIN) \
- no_data = EAI_AGAIN; \
- else \
- no_data = h_errno == NO_DATA; \
- } \
- else if (status == NSS_STATUS_SUCCESS) \
- { \
- if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, res)) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- \
- if (localcanon != NULL && res->canon == NULL) \
- { \
- char *canonbuf = __strdup (localcanon); \
- if (canonbuf == NULL) \
- { \
- __resolv_context_put (res_ctx); \
- result = -EAI_SYSTEM; \
- goto out; \
- } \
- res->canon = canonbuf; \
- } \
- } \
- }
+static int
+gethosts (nss_gethostbyname3_r fct, int family, const char *name,
+ const struct addrinfo *req, struct scratch_buffer *tmpbuf,
+ struct gaih_result *res, enum nss_status *statusp, int *no_datap)
+{
+ struct hostent th;
+ char *localcanon = NULL;
+ enum nss_status status;
+
+ *no_datap = 0;
+ while (1)
+ {
+ *statusp = status = DL_CALL_FCT (fct, (name, family, &th,
+ tmpbuf->data, tmpbuf->length,
+ &errno, &h_errno, NULL,
+ &localcanon));
+ if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL
+ || errno != ERANGE)
+ break;
+ if (!scratch_buffer_grow (tmpbuf))
+ return -EAI_MEMORY;
+ }
+ if (status == NSS_STATUS_NOTFOUND
+ || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL)
+ {
+ if (h_errno == NETDB_INTERNAL)
+ return -EAI_SYSTEM;
+ if (h_errno == TRY_AGAIN)
+ *no_datap = EAI_AGAIN;
+ else
+ *no_datap = h_errno == NO_DATA;
+ }
+ else if (status == NSS_STATUS_SUCCESS)
+ {
+ if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
+ return -EAI_SYSTEM;
+
+ if (localcanon != NULL && res->canon == NULL)
+ {
+ char *canonbuf = __strdup (localcanon);
+ if (canonbuf == NULL)
+ return -EAI_SYSTEM;
+ res->canon = canonbuf;
+ }
+ }
+ return 0;
+}
/* This function is called if a canonical name is requested, but if
the service function did not provide it. It tries to obtain the
@@ -741,7 +732,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
- gethosts (AF_INET6);
+ if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
no_inet6_data = no_data;
inet6_status = status;
}
@@ -753,7 +749,12 @@ get_nss_addresses (const char *name, const struct addrinfo *req,
know we are not going to need them. */
&& ((req->ai_flags & AI_ALL) || !res->got_ipv6)))
{
- gethosts (AF_INET);
+ if ((result = gethosts (fct, AF_INET, name, req, tmpbuf,
+ res, &status, &no_data)) != 0)
+ {
+ __resolv_context_put (res_ctx);
+ goto out;
+ }
if (req->ai_family == AF_INET)
{
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 10/12] gaih_inet: split loopback lookup into its own function
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (8 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 09/12] gaih_inet: make gethosts into a function Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 11/12] gaih_inet: Split result generation " Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 12/12] gethosts: Return EAI_MEMORY on allocation failure Siddhesh Poyarekar
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Flatten the condition nesting and replace the alloca for RET.AT/ATR with
a single array LOCAL_AT[2]. This gets rid of alloca and alloca
accounting.
`git diff -b` is probably the best way to view this change since much of
the diff is whitespace changes.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 127 ++++++++++++++++++------------------
1 file changed, 62 insertions(+), 65 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index bc385dd322..47c41d332d 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1004,6 +1004,32 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
return -EAI_NODATA;
}
+/* Add local address information into RES. RES->AT is assumed to have enough
+ space for two tuples and is zeroed out. */
+
+static void
+get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
+{
+ struct gaih_addrtuple *atr = res->at;
+ if (req->ai_family == AF_UNSPEC)
+ res->at->next = res->at + 1;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ res->at->family = AF_INET6;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ memcpy (res->at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+ atr = res->at->next;
+ }
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+ {
+ atr->family = AF_INET;
+ if ((req->ai_flags & AI_PASSIVE) == 0)
+ atr->addr[0] = htonl (INADDR_LOOPBACK);
+ }
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1014,10 +1040,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
const char *orig_name = name;
- /* Reserve stack memory for the scratch buffer in the getaddrinfo
- function. */
- size_t alloca_used = sizeof (struct scratch_buffer);
-
int rc;
if ((rc = get_servtuples (service, req, st, tmpbuf)) != 0)
return rc;
@@ -1027,76 +1049,51 @@ gaih_inet (const char *name, const struct gaih_service *service,
int result = 0;
struct gaih_result res = {0};
- if (name != NULL)
+ struct gaih_addrtuple local_at[2] = {0};
+
+ res.at = local_at;
+
+ if (__glibc_unlikely (name == NULL))
{
- if (req->ai_flags & AI_IDN)
- {
- char *out;
- result = __idna_to_dns_encoding (name, &out);
- if (result != 0)
- return -result;
- name = out;
- malloc_name = true;
- }
+ get_local_addresses (req, &res);
+ goto process_list;
+ }
- res.at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- res.at->scopeid = 0;
- res.at->next = NULL;
+ if (req->ai_flags & AI_IDN)
+ {
+ char *out;
+ result = __idna_to_dns_encoding (name, &out);
+ if (result != 0)
+ return -result;
+ name = out;
+ malloc_name = true;
+ }
- if ((result = text_to_binary_address (name, req, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = text_to_binary_address (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
+ if ((result = try_simple_gethostbyname (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ 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;
+ if ((result = get_nscd_addresses (name, req, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
#endif
- if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
- goto free_and_return;
- else if (res.at != NULL)
- goto process_list;
-
- /* None of the lookups worked, so name not found. */
- result = -EAI_NONAME;
- goto free_and_return;
- }
- else
- {
- struct gaih_addrtuple *atr;
- atr = res.at = alloca_account (sizeof (struct gaih_addrtuple),
- alloca_used);
- memset (res.at, '\0', sizeof (struct gaih_addrtuple));
-
- if (req->ai_family == AF_UNSPEC)
- {
- res.at->next = __alloca (sizeof (struct gaih_addrtuple));
- memset (res.at->next, '\0', sizeof (struct gaih_addrtuple));
- }
-
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- {
- res.at->family = AF_INET6;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- memcpy (res.at->addr, &in6addr_loopback, sizeof (struct in6_addr));
- atr = res.at->next;
- }
+ if ((result = get_nss_addresses (name, req, tmpbuf, &res)) != 0)
+ goto free_and_return;
+ else if (res.at != NULL)
+ goto process_list;
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- {
- atr->family = AF_INET;
- if ((req->ai_flags & AI_PASSIVE) == 0)
- atr->addr[0] = htonl (INADDR_LOOPBACK);
- }
- }
+ /* None of the lookups worked, so name not found. */
+ result = -EAI_NONAME;
+ goto free_and_return;
process_list:
{
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 11/12] gaih_inet: Split result generation into its own function
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (9 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 10/12] gaih_inet: split loopback lookup into its own function Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
2022-03-17 8:11 ` [PATCH v3 12/12] gethosts: Return EAI_MEMORY on allocation failure Siddhesh Poyarekar
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
Simplify the loop a wee bit and clean up variable names too.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 176 ++++++++++++++++++------------------
1 file changed, 86 insertions(+), 90 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 47c41d332d..f5d4a5cfd9 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1030,6 +1030,87 @@ get_local_addresses (const struct addrinfo *req, struct gaih_result *res)
}
}
+/* Generate results in PAI and its count in NADDRS. Return 0 on success or an
+ error code on failure. */
+
+static int
+generate_addrinfo (const struct addrinfo *req, struct gaih_result *res,
+ const struct gaih_servtuple *st, struct addrinfo **pai,
+ unsigned int *naddrs)
+{
+ size_t socklen;
+ sa_family_t family;
+
+ /* Buffer is the size of an unformatted IPv6 address in printable format. */
+ for (struct gaih_addrtuple *at = res->at; at != NULL; at = at->next)
+ {
+ family = at->family;
+ if (family == AF_INET6)
+ {
+ socklen = sizeof (struct sockaddr_in6);
+
+ /* 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 (res->got_ipv6
+ && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
+ && IN6_IS_ADDR_V4MAPPED (at->addr))
+ continue;
+ }
+ else
+ socklen = sizeof (struct sockaddr_in);
+
+ for (int i = 0; st[i].set; i++)
+ {
+ struct addrinfo *ai;
+ ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
+ if (ai == NULL)
+ return -EAI_MEMORY;
+
+ ai->ai_flags = req->ai_flags;
+ ai->ai_family = family;
+ ai->ai_socktype = st[i].socktype;
+ ai->ai_protocol = st[i].protocol;
+ ai->ai_addrlen = socklen;
+ ai->ai_addr = (void *) (ai + 1);
+
+ /* We only add the canonical name once. */
+ ai->ai_canonname = res->canon;
+ res->canon = NULL;
+
+#ifdef _HAVE_SA_LEN
+ ai->ai_addr->sa_len = socklen;
+#endif /* _HAVE_SA_LEN */
+ ai->ai_addr->sa_family = family;
+
+ /* In case of an allocation error the list must be NULL
+ terminated. */
+ ai->ai_next = NULL;
+
+ if (family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) ai->ai_addr;
+ sin6p->sin6_port = st[i].port;
+ sin6p->sin6_flowinfo = 0;
+ memcpy (&sin6p->sin6_addr, at->addr, sizeof (struct in6_addr));
+ sin6p->sin6_scope_id = at->scopeid;
+ }
+ else
+ {
+ struct sockaddr_in *sinp = (struct sockaddr_in *) ai->ai_addr;
+ sinp->sin_port = st[i].port;
+ memcpy (&sinp->sin_addr, at->addr, sizeof (struct in_addr));
+ memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+ }
+
+ pai = &(ai->ai_next);
+ }
+
+ ++*naddrs;
+ }
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -1096,98 +1177,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
goto free_and_return;
process_list:
- {
- /* Set up the canonical name if we need it. */
- if ((result = process_canonname (req, orig_name, &res)) != 0)
- goto free_and_return;
-
- struct gaih_addrtuple *at2 = res.at;
- size_t socklen;
- sa_family_t family;
-
- /*
- buffer is the size of an unformatted IPv6 address in printable format.
- */
- while (at2 != NULL)
- {
- family = at2->family;
- if (family == AF_INET6)
- {
- socklen = sizeof (struct sockaddr_in6);
-
- /* 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 (res.got_ipv6
- && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
- && IN6_IS_ADDR_V4MAPPED (at2->addr))
- goto ignore;
- }
- else
- socklen = sizeof (struct sockaddr_in);
-
- for (int i = 0; st[i].set; i++)
- {
- struct addrinfo *ai;
- ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
- if (ai == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
-
- ai->ai_flags = req->ai_flags;
- ai->ai_family = family;
- ai->ai_socktype = st[i].socktype;
- ai->ai_protocol = st[i].protocol;
- ai->ai_addrlen = socklen;
- ai->ai_addr = (void *) (ai + 1);
-
- /* We only add the canonical name once. */
- ai->ai_canonname = res.canon;
- res.canon = NULL;
-
-#ifdef _HAVE_SA_LEN
- ai->ai_addr->sa_len = socklen;
-#endif /* _HAVE_SA_LEN */
- ai->ai_addr->sa_family = family;
-
- /* In case of an allocation error the list must be NULL
- terminated. */
- ai->ai_next = NULL;
-
- if (family == AF_INET6)
- {
- struct sockaddr_in6 *sin6p =
- (struct sockaddr_in6 *) ai->ai_addr;
-
- sin6p->sin6_port = st[i].port;
- sin6p->sin6_flowinfo = 0;
- memcpy (&sin6p->sin6_addr,
- at2->addr, sizeof (struct in6_addr));
- sin6p->sin6_scope_id = at2->scopeid;
- }
- else
- {
- struct sockaddr_in *sinp =
- (struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st[i].port;
- memcpy (&sinp->sin_addr,
- at2->addr, sizeof (struct in_addr));
- memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
- }
-
- pai = &(ai->ai_next);
- }
-
- ++*naddrs;
+ /* Set up the canonical name if we need it. */
+ if ((result = process_canonname (req, orig_name, &res)) != 0)
+ goto free_and_return;
- ignore:
- at2 = at2->next;
- }
- }
+ result = generate_addrinfo (req, &res, st, pai, naddrs);
- free_and_return:
+free_and_return:
if (malloc_name)
free ((char *) name);
free (addrmem);
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 12/12] gethosts: Return EAI_MEMORY on allocation failure
2022-03-17 8:11 ` [PATCH v3 " Siddhesh Poyarekar
` (10 preceding siblings ...)
2022-03-17 8:11 ` [PATCH v3 11/12] gaih_inet: Split result generation " Siddhesh Poyarekar
@ 2022-03-17 8:11 ` Siddhesh Poyarekar
11 siblings, 0 replies; 68+ messages in thread
From: Siddhesh Poyarekar @ 2022-03-17 8:11 UTC (permalink / raw)
To: libc-alpha
All other cases of failures due to lack of memory return EAI_MEMORY, so
it seems wrong to return EAI_SYSTEM here. The only reason
convert_hostent_to_gaih_addrtuple could fail is on calloc failure.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
sysdeps/posix/getaddrinfo.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index f5d4a5cfd9..0ece3b46b7 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -303,13 +303,13 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name,
else if (status == NSS_STATUS_SUCCESS)
{
if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res))
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
if (localcanon != NULL && res->canon == NULL)
{
char *canonbuf = __strdup (localcanon);
if (canonbuf == NULL)
- return -EAI_SYSTEM;
+ return -EAI_MEMORY;
res->canon = canonbuf;
}
}
--
2.35.1
^ permalink raw reply [flat|nested] 68+ messages in thread