Simplify allocations and fix merge and continue actions [BZ #28931]

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>
This commit is contained in:
Siddhesh Poyarekar 2022-03-17 11:44:34 +05:30
parent 9df157b4ed
commit 1c37b8022e
5 changed files with 752 additions and 54 deletions

View File

@ -76,6 +76,7 @@ tests-container := \
tst-nss-db-endgrent \ tst-nss-db-endgrent \
tst-nss-db-endpwent \ tst-nss-db-endpwent \
tst-nss-files-hosts-long \ tst-nss-files-hosts-long \
tst-nss-gai-actions \
tst-nss-test3 \ tst-nss-test3 \
tst-reload1 \ tst-reload1 \
tst-reload2 \ tst-reload2 \

149
nss/tst-nss-gai-actions.c Normal file
View File

@ -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>

View File

@ -0,0 +1 @@
multi on

View File

@ -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

View File

@ -458,11 +458,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (name != NULL) 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) if (req->ai_flags & AI_IDN)
{ {
char *out; char *out;
@ -473,13 +468,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true; 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) if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
{
memcpy (at->addr, addr, sizeof (at->addr));
at->family = AF_INET; at->family = AF_INET;
}
else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) 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[2] = htonl (0xffff);
at->addr[1] = 0; at->addr[1] = 0;
at->addr[0] = 0; at->addr[0] = 0;
@ -493,24 +496,37 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_flags & AI_CANONNAME) if (req->ai_flags & AI_CANONNAME)
canon = name; canon = name;
goto process_list;
} }
else if (at->family == AF_UNSPEC)
{
char *scope_delim = strchr (name, SCOPE_DELIMITER); char *scope_delim = strchr (name, SCOPE_DELIMITER);
int e; int e;
if (scope_delim == NULL) if (scope_delim == NULL)
e = inet_pton (AF_INET6, name, at->addr); e = inet_pton (AF_INET6, name, addr);
else else
e = __inet_pton_length (AF_INET6, name, scope_delim - name, e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
at->addr);
if (e > 0) 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) 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]; 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; at->family = AF_INET;
} }
else else
@ -530,12 +546,12 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_flags & AI_CANONNAME) if (req->ai_flags & AI_CANONNAME)
canon = name; 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_data = 0;
int no_inet6_data = 0; int no_inet6_data = 0;
nss_action_list nip; 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; enum nss_status status = NSS_STATUS_UNAVAIL;
int no_more; int no_more;
struct resolv_context *res_ctx = NULL; struct resolv_context *res_ctx = NULL;
bool do_merge = false;
/* If we do not have to look for IPv6 addresses or the canonical /* If we do not have to look for IPv6 addresses or the canonical
name, use the simple, old functions, which do not support 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; result = -EAI_MEMORY;
goto free_and_return; goto free_and_return;
} }
*pat = addrmem; at = addrmem;
} }
else else
{ {
@ -632,6 +649,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
} }
struct gaih_addrtuple *addrfree = addrmem; struct gaih_addrtuple *addrfree = addrmem;
struct gaih_addrtuple **pat = &at;
for (int i = 0; i < air->naddrs; ++i) for (int i = 0; i < air->naddrs; ++i)
{ {
socklen_t size = (air->family[i] == AF_INET socklen_t size = (air->family[i] == AF_INET
@ -695,12 +714,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
free (air); free (air);
if (at->family == AF_UNSPEC)
{
result = -EAI_NONAME;
goto free_and_return;
}
goto process_list; goto process_list;
} }
else if (err == 0) else if (err == 0)
@ -732,6 +745,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more) 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; no_data = 0;
nss_gethostbyname4_r *fct4 = NULL; nss_gethostbyname4_r *fct4 = NULL;
@ -744,12 +773,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
{ {
while (1) while (1)
{ {
status = DL_CALL_FCT (fct4, (name, pat, status = DL_CALL_FCT (fct4, (name, &at,
tmpbuf->data, tmpbuf->length, tmpbuf->data, tmpbuf->length,
&errno, &h_errno, &errno, &h_errno,
NULL)); NULL));
if (status == NSS_STATUS_SUCCESS) if (status == NSS_STATUS_SUCCESS)
break; break;
/* gethostbyname4_r may write into AT, so reset it. */
at = NULL;
if (status != NSS_STATUS_TRYAGAIN if (status != NSS_STATUS_TRYAGAIN
|| errno != ERANGE || h_errno != NETDB_INTERNAL) || errno != ERANGE || h_errno != NETDB_INTERNAL)
{ {
@ -774,7 +805,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1; no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
canon = (*pat)->name; canon = at->name;
struct gaih_addrtuple **pat = &at;
while (*pat != NULL) while (*pat != NULL)
{ {
@ -826,6 +859,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (fct != NULL) if (fct != NULL)
{ {
struct gaih_addrtuple **pat = &at;
if (req->ai_family == AF_INET6 if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC) || 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) if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break; break;
/* The hosts database does not support MERGE. */
if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
do_merge = true;
nip++; nip++;
if (nip->module == NULL) if (nip->module == NULL)
no_more = -1; no_more = -1;
@ -930,7 +969,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
} }
process_list: process_list:
if (at->family == AF_UNSPEC) if (at == NULL)
{ {
result = -EAI_NONAME; result = -EAI_NONAME;
goto free_and_return; goto free_and_return;