]> sourceware.org Git - glibc.git/commitdiff
Simplify allocations and fix merge and continue actions [BZ #28931]
authorSiddhesh Poyarekar <siddhesh@sourceware.org>
Thu, 17 Mar 2022 06:14:34 +0000 (11:44 +0530)
committerSiddhesh Poyarekar <siddhesh@sourceware.org>
Tue, 22 Mar 2022 14:08:36 +0000 (19:38 +0530)
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>
Reviewed-by: DJ Delorie <dj@redhat.com>
nss/Makefile
nss/tst-nss-gai-actions.c [new file with mode: 0644]
nss/tst-nss-gai-actions.root/etc/host.conf [new file with mode: 0644]
nss/tst-nss-gai-actions.root/etc/hosts [new file with mode: 0644]
sysdeps/posix/getaddrinfo.c

index 42a59535cb20f172eb020cbe930908864feb1b35..d8b06b44fb4ba81952572d424409605032147ae6 100644 (file)
@@ -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 (file)
index 0000000..efca6cd
--- /dev/null
@@ -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 (file)
index 0000000..d1a59f7
--- /dev/null
@@ -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 (file)
index 0000000..50ce977
--- /dev/null
@@ -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
index 18dccd5924e88a67d856ca60552ab3491166db46..3d9bea60c6638ffaf230fe2ca3c7160ef846673b 100644 (file)
@@ -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;
This page took 0.061416 seconds and 5 git commands to generate.