mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-05 17:11:06 +00:00
The old code uses errno as the primary indicator for success or
failure. This is wrong because errno is only set for specific
combinations of the status return value and the h_errno variable.
(cherry picked from commit f4a6be2582
)
This commit is contained in:
parent
7966331555
commit
a71a3374cd
14
ChangeLog
14
ChangeLog
@ -1,3 +1,17 @@
|
||||
2017-09-01 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #21915]
|
||||
[BZ #21922]
|
||||
* sysdeps/posix/getaddrinfo.c (gethosts): Look at NSS function
|
||||
result to determine success or failure, not the errno value.
|
||||
* nss/Makefile (tests): Add tst-nss-files-hosts-erange.
|
||||
(tst-nss-files-hosts-erange): Link with -ldl.
|
||||
* nss/tst-nss-files-hosts-erange.c: New file.
|
||||
* nss/tst-resolv-basic.c (response): Handle nodata.example.
|
||||
(do_test): Add NO_DATA tests.
|
||||
* resolv/tst-resolv-basic.c (test_nodata_nxdomain): New function.
|
||||
(do_test): Call it.
|
||||
|
||||
2017-09-01 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #21922]
|
||||
|
1
NEWS
1
NEWS
@ -22,6 +22,7 @@ The following bugs are resolved with this release:
|
||||
[21780] posix: Set p{read,write}v2 to return ENOTSUP
|
||||
[21871] x86-64: Use _dl_runtime_resolve_opt only with AVX512F
|
||||
[21885] getaddrinfo: Release resolver context on error in gethosts
|
||||
[21915] getaddrinfo: incorrect result handling for NSS service modules
|
||||
[21922] getaddrinfo with AF_INET(6) returns EAI_NONAME, not EAI_NODATA
|
||||
[21930] Do not use __builtin_types_compatible_p in C++ mode
|
||||
[21932] Unpaired __resolv_context_get in generic get*_r implementation
|
||||
|
@ -58,6 +58,11 @@ tests = test-netdb test-digits-dots tst-nss-getpwent bug17079 \
|
||||
tst-nss-test5
|
||||
xtests = bug-erange
|
||||
|
||||
# Tests which need libdl
|
||||
ifeq (yes,$(build-shared))
|
||||
tests += tst-nss-files-hosts-erange
|
||||
endif
|
||||
|
||||
# If we have a thread library then we can test cancellation against
|
||||
# some routines like getpwuid_r.
|
||||
ifeq (yes,$(have-thread-library))
|
||||
@ -154,3 +159,5 @@ $(patsubst %,$(objpfx)%.out,$(tests)) : \
|
||||
ifeq (yes,$(have-thread-library))
|
||||
$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
|
||||
endif
|
||||
|
||||
$(objpfx)tst-nss-files-hosts-erange: $(libdl)
|
||||
|
109
nss/tst-nss-files-hosts-erange.c
Normal file
109
nss/tst-nss-files-hosts-erange.c
Normal file
@ -0,0 +1,109 @@
|
||||
/* Parse /etc/hosts in multi mode with a trailing long line (bug 21915).
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include <netdb.h>
|
||||
#include <nss.h>
|
||||
#include <support/check.h>
|
||||
#include <support/check_nss.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
struct support_chroot *chroot_env;
|
||||
|
||||
#define X10 "XXXXXXXXXX"
|
||||
#define X100 X10 X10 X10 X10 X10 X10 X10 X10 X10 X10
|
||||
#define X1000 X100 X100 X100 X100 X100 X100 X100 X100 X100 X100
|
||||
|
||||
static void
|
||||
prepare (int argc, char **argv)
|
||||
{
|
||||
chroot_env = support_chroot_create
|
||||
((struct support_chroot_configuration)
|
||||
{
|
||||
.resolv_conf = "",
|
||||
.hosts =
|
||||
"127.0.0.1 localhost localhost.localdomain\n"
|
||||
"::1 localhost localhost.localdomain\n"
|
||||
"192.0.2.1 example.com\n"
|
||||
"#" X1000 X100 "\n",
|
||||
.host_conf = "multi on\n",
|
||||
});
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
support_become_root ();
|
||||
if (!support_can_chroot ())
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
__nss_configure_lookup ("hosts", "files");
|
||||
if (dlopen (LIBNSS_FILES_SO, RTLD_LAZY) == NULL)
|
||||
FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
|
||||
|
||||
xchroot (chroot_env->path_chroot);
|
||||
|
||||
errno = ERANGE;
|
||||
h_errno = NETDB_INTERNAL;
|
||||
check_hostent ("gethostbyname example.com",
|
||||
gethostbyname ("example.com"),
|
||||
"name: example.com\n"
|
||||
"address: 192.0.2.1\n");
|
||||
errno = ERANGE;
|
||||
h_errno = NETDB_INTERNAL;
|
||||
check_hostent ("gethostbyname2 AF_INET example.com",
|
||||
gethostbyname2 ("example.com", AF_INET),
|
||||
"name: example.com\n"
|
||||
"address: 192.0.2.1\n");
|
||||
{
|
||||
struct addrinfo hints =
|
||||
{
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_protocol = IPPROTO_TCP,
|
||||
};
|
||||
errno = ERANGE;
|
||||
h_errno = NETDB_INTERNAL;
|
||||
struct addrinfo *ai;
|
||||
int ret = getaddrinfo ("example.com", "80", &hints, &ai);
|
||||
check_addrinfo ("example.com AF_UNSPEC", ai, ret,
|
||||
"address: STREAM/TCP 192.0.2.1 80\n");
|
||||
if (ret == 0)
|
||||
freeaddrinfo (ai);
|
||||
|
||||
hints.ai_family = AF_INET;
|
||||
errno = ERANGE;
|
||||
h_errno = NETDB_INTERNAL;
|
||||
ret = getaddrinfo ("example.com", "80", &hints, &ai);
|
||||
check_addrinfo ("example.com AF_INET", ai, ret,
|
||||
"address: STREAM/TCP 192.0.2.1 80\n");
|
||||
if (ret == 0)
|
||||
freeaddrinfo (ai);
|
||||
}
|
||||
|
||||
support_chroot_free (chroot_env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PREPARE prepare
|
||||
#include <support/test-driver.c>
|
@ -50,7 +50,7 @@ response (const struct resolv_response_context *ctx,
|
||||
qname_compare = qname + 2;
|
||||
else
|
||||
qname_compare = qname;
|
||||
enum {www, alias, nxdomain, long_name} requested_qname;
|
||||
enum {www, alias, nxdomain, long_name, nodata} requested_qname;
|
||||
if (strcmp (qname_compare, "www.example") == 0)
|
||||
requested_qname = www;
|
||||
else if (strcmp (qname_compare, "alias.example") == 0)
|
||||
@ -59,6 +59,8 @@ response (const struct resolv_response_context *ctx,
|
||||
requested_qname = nxdomain;
|
||||
else if (strcmp (qname_compare, LONG_NAME) == 0)
|
||||
requested_qname = long_name;
|
||||
else if (strcmp (qname_compare, "nodata.example") == 0)
|
||||
requested_qname = nodata;
|
||||
else
|
||||
{
|
||||
support_record_failure ();
|
||||
@ -87,6 +89,8 @@ response (const struct resolv_response_context *ctx,
|
||||
resolv_response_close_record (b);
|
||||
resolv_response_open_record (b, "www.example", qclass, qtype, 0);
|
||||
break;
|
||||
case nodata:
|
||||
return;
|
||||
case nxdomain:
|
||||
FAIL_EXIT1 ("unreachable");
|
||||
}
|
||||
@ -267,6 +271,55 @@ test_bug_21295 (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Run tests which do not expect any data. */
|
||||
static void
|
||||
test_nodata_nxdomain (void)
|
||||
{
|
||||
/* Iterate through different address families. */
|
||||
int families[] = { AF_UNSPEC, AF_INET, AF_INET6, -1 };
|
||||
for (int i = 0; families[i] >= 0; ++i)
|
||||
/* If do_tcp, prepend "t." to the name to trigger TCP
|
||||
fallback. */
|
||||
for (int do_tcp = 0; do_tcp < 2; ++do_tcp)
|
||||
/* If do_nxdomain, trigger an NXDOMAIN error (DNS failure),
|
||||
otherwise use a NODATA response (empty but successful
|
||||
answer). */
|
||||
for (int do_nxdomain = 0; do_nxdomain < 2; ++do_nxdomain)
|
||||
{
|
||||
int family = families[i];
|
||||
char *name = xasprintf ("%s%s.example",
|
||||
do_tcp ? "t." : "",
|
||||
do_nxdomain ? "nxdomain" : "nodata");
|
||||
|
||||
if (family != AF_UNSPEC)
|
||||
{
|
||||
if (do_nxdomain)
|
||||
check_h (name, family, "error: HOST_NOT_FOUND\n");
|
||||
else
|
||||
check_h (name, family, "error: NO_ADDRESS\n");
|
||||
}
|
||||
|
||||
const char *expected;
|
||||
if (do_nxdomain)
|
||||
expected = "error: Name or service not known\n";
|
||||
else
|
||||
expected = "error: No address associated with hostname\n";
|
||||
|
||||
check_ai (name, "80", family, expected);
|
||||
|
||||
struct addrinfo hints =
|
||||
{
|
||||
.ai_family = family,
|
||||
.ai_flags = AI_V4MAPPED | AI_ALL,
|
||||
};
|
||||
check_ai_hints (name, "80", hints, expected);
|
||||
hints.ai_flags |= AI_CANONNAME;
|
||||
check_ai_hints (name, "80", hints, expected);
|
||||
|
||||
free (name);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
@ -439,29 +492,8 @@ do_test (void)
|
||||
"address: DGRAM/UDP 2001:db8::4 80\n"
|
||||
"address: RAW/IP 2001:db8::4 80\n");
|
||||
|
||||
check_h ("nxdomain.example", AF_INET,
|
||||
"error: HOST_NOT_FOUND\n");
|
||||
check_h ("nxdomain.example", AF_INET6,
|
||||
"error: HOST_NOT_FOUND\n");
|
||||
check_ai ("nxdomain.example", "80", AF_UNSPEC,
|
||||
"error: Name or service not known\n");
|
||||
check_ai ("nxdomain.example", "80", AF_INET,
|
||||
"error: Name or service not known\n");
|
||||
check_ai ("nxdomain.example", "80", AF_INET6,
|
||||
"error: Name or service not known\n");
|
||||
|
||||
check_h ("t.nxdomain.example", AF_INET,
|
||||
"error: HOST_NOT_FOUND\n");
|
||||
check_h ("t.nxdomain.example", AF_INET6,
|
||||
"error: HOST_NOT_FOUND\n");
|
||||
check_ai ("t.nxdomain.example", "80", AF_UNSPEC,
|
||||
"error: Name or service not known\n");
|
||||
check_ai ("t.nxdomain.example", "80", AF_INET,
|
||||
"error: Name or service not known\n");
|
||||
check_ai ("t.nxdomain.example", "80", AF_INET6,
|
||||
"error: Name or service not known\n");
|
||||
|
||||
test_bug_21295 ();
|
||||
test_nodata_nxdomain ();
|
||||
|
||||
resolv_test_end (aux);
|
||||
|
||||
|
@ -242,28 +242,26 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
|
||||
#define gethosts(_family, _type) \
|
||||
{ \
|
||||
struct hostent th; \
|
||||
struct hostent *h; \
|
||||
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 (errno != ERANGE || h_errno != NETDB_INTERNAL) \
|
||||
break; \
|
||||
if (!scratch_buffer_grow (tmpbuf)) \
|
||||
{ \
|
||||
__resolv_context_enable_inet6 (res_ctx, res_enable_inet6); \
|
||||
__resolv_context_put (res_ctx); \
|
||||
result = -EAI_MEMORY; \
|
||||
goto free_and_return; \
|
||||
} \
|
||||
} \
|
||||
if (status == NSS_STATUS_SUCCESS && errno == 0) \
|
||||
h = &th; \
|
||||
else \
|
||||
h = NULL; \
|
||||
if (errno != 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_enable_inet6 (res_ctx, res_enable_inet6); \
|
||||
__resolv_context_put (res_ctx); \
|
||||
result = -EAI_MEMORY; \
|
||||
goto free_and_return; \
|
||||
} \
|
||||
} \
|
||||
if (status == NSS_STATUS_NOTFOUND \
|
||||
|| status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) \
|
||||
{ \
|
||||
if (h_errno == NETDB_INTERNAL) \
|
||||
{ \
|
||||
@ -277,9 +275,9 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
|
||||
else \
|
||||
no_data = h_errno == NO_DATA; \
|
||||
} \
|
||||
else if (h != NULL) \
|
||||
else if (status == NSS_STATUS_SUCCESS) \
|
||||
{ \
|
||||
if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem)) \
|
||||
if (!convert_hostent_to_gaih_addrtuple (req, _family, &th, &addrmem)) \
|
||||
{ \
|
||||
__resolv_context_enable_inet6 (res_ctx, res_enable_inet6); \
|
||||
__resolv_context_put (res_ctx); \
|
||||
|
Loading…
Reference in New Issue
Block a user