mirror of
git://sourceware.org/git/glibc.git
synced 2025-01-18 12:16:13 +08: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.
This commit is contained in:
parent
5f8340f583
commit
f4a6be2582
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]
|
||||
|
@ -60,6 +60,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))
|
||||
@ -156,3 +161,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