* sysdeps/posix/getaddrinfo.c (gaih_addrtuple): Change type of
	addr to avoid casts.
	(gethosts): Removed.
	(gethosts2): Renamed to gethosts.  Make it usable for family !=
	AF_UNSPEC.  Fix AI_V4MAPPED.
	(gaih_inet): Remove use of old gethosts.  Always use what used to be
	gethosts2.  If entry is found, try to use the same NSS module's
	getcanonname_r function.  Use gethostbyaddr for AI_CANONNAME only
	if getcanonname_r was not available.  Fix filtering of AI_V4MAPPED
	addresses.  Numerous cleanups.
	* resolv/nss_dns/dns-canon.c: New file.
	* resolv/Makefile (libnss_dns-routines): Add dns-canon.
	* resolv/Versions (libnss_dns): Add _nss_dns_getcanonname_r.

	* elf/Makefile: Add rules to build and run tst-dlopenrpath.
	* elf/tst-dlopenrpath.c: New file.
	* elf/tst-dlopenrpathmod.c: New file.

	* intl/tst-gettext.sh: Adjust for change of de.po file to UTF-8.
This commit is contained in:
Ulrich Drepper 2004-08-15 20:23:40 +00:00
parent 1e6d2101ea
commit 28977c2c1a
8 changed files with 445 additions and 241 deletions

View File

@ -1,6 +1,24 @@
2004-08-15 Ulrich Drepper <drepper@redhat.com> 2004-08-15 Ulrich Drepper <drepper@redhat.com>
* intl/tst-gettext.sh: Adjust for change for de.po file to UTF-8. * sysdeps/posix/getaddrinfo.c (gaih_addrtuple): Change type of
addr to avoid casts.
(gethosts): Removed.
(gethosts2): Renamed to gethosts. Make it usable for family !=
AF_UNSPEC. Fix AI_V4MAPPED.
(gaih_inet): Remove use of old gethosts. Always use what used to be
gethosts2. If entry is found, try to use the same NSS module's
getcanonname_r function. Use gethostbyaddr for AI_CANONNAME only
if getcanonname_r was not available. Fix filtering of AI_V4MAPPED
addresses. Numerous cleanups.
* resolv/nss_dns/dns-canon.c: New file.
* resolv/Makefile (libnss_dns-routines): Add dns-canon.
* resolv/Versions (libnss_dns): Add _nss_dns_getcanonname_r.
* elf/Makefile: Add rules to build and run tst-dlopenrpath.
* elf/tst-dlopenrpath.c: New file.
* elf/tst-dlopenrpathmod.c: New file.
* intl/tst-gettext.sh: Adjust for change of de.po file to UTF-8.
* intl/tst-gettext.c: Likewise. * intl/tst-gettext.c: Likewise.
* nss/getent.c (ahosts_keys_int): Correctly print IPv6 addresses. * nss/getent.c (ahosts_keys_int): Correctly print IPv6 addresses.

View File

@ -82,7 +82,7 @@ distribute := rtld-Rules \
tst-array1.exp tst-array2.exp tst-array4.exp \ tst-array1.exp tst-array2.exp tst-array4.exp \
tst-array2dep.c tst-piemod1.c \ tst-array2dep.c tst-piemod1.c \
tst-execstack-mod.c tst-dlmodcount.c \ tst-execstack-mod.c tst-dlmodcount.c \
check-textrel.c dl-sysdep.h check-textrel.c dl-sysdep.h test-dlopenrpathmod.c
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@ -152,7 +152,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \ restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \ circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
$(tests-execstack-$(have-z-execstack)) tst-dlmodcount $(tests-execstack-$(have-z-execstack)) tst-dlmodcount tst-dlopenrpath
# reldep9 # reldep9
test-srcs = tst-pathopt test-srcs = tst-pathopt
tests-vis-yes = vismain tests-vis-yes = vismain
@ -184,7 +184,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
circlemod3 circlemod3a \ circlemod3 circlemod3a \
reldep8mod1 reldep8mod2 reldep8mod3 \ reldep8mod1 reldep8mod2 reldep8mod3 \
reldep9mod1 reldep9mod2 reldep9mod3 \ reldep9mod1 reldep9mod2 reldep9mod3 \
tst-alignmod $(modules-execstack-$(have-z-execstack)) tst-alignmod $(modules-execstack-$(have-z-execstack)) \
tst-dlopenrpathmod
ifeq (yes,$(have-initfini-array)) ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep modules-names += tst-array2dep
endif endif
@ -747,3 +748,9 @@ $(objpfx)tst-dlmodcount: $(libdl)
$(objpfx)tst-dlmodcount.out: $(test-modules) $(objpfx)tst-dlmodcount.out: $(test-modules)
endif endif
$(objpfx)tst-dlopenrpathmod.so: $(libdl)
$(objpfx)tst-dlopenrpath: $(objpfx)tst-dlopenrpathmod.so $(libdl)
CFLAGS-tst-dlopenrpath.c += -DPFX=\"$(objpfx)\"
LDFLAGS-tst-dlopenrpathmod.so += -Wl,-rpath,\$$ORIGIN/test-subdir
$(objpfx)tst-dlopenrpath.out: $(objpfx)firstobj.so

74
elf/tst-dlopenrpath.c Normal file
View File

@ -0,0 +1,74 @@
/* Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <dlfcn.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
extern int foo (void);
static const char testsubdir[] = PFX "test-subdir";
static int
do_test (void)
{
struct stat64 st;
int result = 1;
if (mkdir (testsubdir, 0777) != 0
&& (errno != EEXIST
|| stat64 (testsubdir, &st) != 0
|| !S_ISDIR (st.st_mode)))
{
printf ("cannot create directory %s\n", testsubdir);
return 1;
}
if (system ("cp " PFX "firstobj.so " PFX "test-subdir/in-subdir.so") != 0)
{
puts ("cannot copy DSO");
return 1;
}
void *p = dlopen ("in-subdir.so", RTLD_LAZY|RTLD_LOCAL);
if (p != NULL)
{
puts ("succeeded in opening in-subdir.so from do_test");
dlclose (p);
goto out;
}
result = foo ();
out:
#if 0
unlink (PFX "test-subdir/in-subdir.so");
rmdir (testsubdir);
#endif
return result;
}
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

36
elf/tst-dlopenrpathmod.c Normal file
View File

@ -0,0 +1,36 @@
/* Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <dlfcn.h>
#include <stdio.h>
int
foo (void)
{
void *p = dlopen ("in-subdir.so", RTLD_LAZY|RTLD_LOCAL);
if (p != NULL)
{
dlclose (p);
return 0;
}
puts ("couldn't open in-subdir.so from foo");
return 1;
}

View File

@ -57,7 +57,7 @@ libanl-routines := gai_cancel gai_error gai_misc gai_notify gai_suspend \
subdir-dirs = nss_dns subdir-dirs = nss_dns
vpath %.c nss_dns vpath %.c nss_dns
libnss_dns-routines := dns-host dns-network libnss_dns-routines := dns-host dns-network dns-canon
ifneq ($(build-static-nss),yes) ifneq ($(build-static-nss),yes)
libnss_dns-inhibit-o = $(filter-out .os,$(object-suffixes)) libnss_dns-inhibit-o = $(filter-out .os,$(object-suffixes))
endif endif

View File

@ -86,7 +86,7 @@ libnss_dns {
GLIBC_PRIVATE { GLIBC_PRIVATE {
_nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_r; _nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_r;
_nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r; _nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r;
_nss_dns_getnetbyname_r; _nss_dns_getnetbyname_r; _nss_dns_getcanonname_r;
} }
} }

137
resolv/nss_dns/dns-canon.c Normal file
View File

@ -0,0 +1,137 @@
/* Copyright (C) 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdlib.h>
#include <arpa/nameser.h>
#include <nsswitch.h>
#if PACKETSZ > 65536
# define MAXPACKET PACKETSZ
#else
# define MAXPACKET 65536
#endif
/* We need this time later. */
typedef union querybuf
{
HEADER hdr;
unsigned char buf[MAXPACKET];
} querybuf;
enum nss_status
_nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
char **result,int *errnop, int *h_errnop)
{
/* Just an alibi buffer, res_nquery will allocate a real buffer for
us. */
unsigned char buf[20];
union
{
querybuf *buf;
unsigned char *ptr;
} ansp = { .ptr = buf };
enum nss_status status;
int r = __libc_res_nquery (&_res, name, ns_c_in, ns_t_cname,
buf, sizeof (buf), &ansp.ptr);
if (r > 0)
{
/* We need to decode the response. Just one question record.
And if we got no answers we bail out, too. */
if (ansp.buf->hdr.qdcount != htons (1)
|| ansp.buf->hdr.ancount == 0)
goto unavail;
/* Beginning and end of the buffer with query, answer, and the
rest. */
unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
unsigned char *endptr = ansp.ptr + r;
/* Skip over the query. This is the name, type, and class. */
int s = __dn_skipname (ptr, endptr);
if (s < 0)
goto unavail;
/* Skip over the name and the two 16-bit values containing type
and class. */
ptr += s + 2 * sizeof (uint16_t);
/* Now the reply. First again the name from the query, then
type, class, TTL, and the length of the RDATA. */
s = __dn_skipname (ptr, endptr);
if (s < 0)
goto unavail;
ptr += s;
/* Check whether type and class match. */
if (*(uint16_t *) ptr != htons (ns_t_cname))
goto unavail;
ptr += sizeof (uint16_t);
if (*(uint16_t *) ptr != htons (ns_c_in))
goto unavail;
/* Also skip over the TTL and rdata length. */
ptr += sizeof (uint16_t) + sizeof (uint32_t) + sizeof (int16_t);
/* Now the name we are looking for. */
s = __dn_expand (ansp.buf->buf, endptr, ptr, buffer, buflen);
if (s < 0)
{
if (errno != EMSGSIZE)
goto unavail;
/* The buffer is too small. */
*errnop = ERANGE;
status = NSS_STATUS_TRYAGAIN;
h_errno = NETDB_INTERNAL;
}
else
{
/* Success. */
*result = buffer;
status = NSS_STATUS_SUCCESS;
}
}
else if (h_errno == TRY_AGAIN)
{
again:
status = NSS_STATUS_TRYAGAIN;
*errnop = errno;
}
else
{
unavail:
status = NSS_STATUS_UNAVAIL;
*errnop = errno;
}
*h_errnop = h_errno;
if (ansp.ptr != buf)
free (ansp.ptr);
return status;
}

View File

@ -89,7 +89,7 @@ struct gaih_addrtuple
{ {
struct gaih_addrtuple *next; struct gaih_addrtuple *next;
int family; int family;
char addr[16]; uint32_t addr[4];
uint32_t scopeid; uint32_t scopeid;
}; };
@ -281,92 +281,6 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
} }
#define gethosts(_family, _type) \ #define gethosts(_family, _type) \
{ \
int i, herrno; \
size_t tmpbuflen; \
struct hostent th; \
char *tmpbuf = NULL; \
tmpbuflen = 512; \
no_data = 0; \
do { \
tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
tmpbuflen, &h, &herrno); \
} while (rc == ERANGE && herrno == NETDB_INTERNAL); \
if (rc != 0) \
{ \
if (herrno == NETDB_INTERNAL) \
{ \
__set_h_errno (herrno); \
return -EAI_SYSTEM; \
} \
if (herrno == TRY_AGAIN) \
no_data = EAI_AGAIN; \
else \
no_data = herrno == NO_DATA; \
} \
else if (h != NULL) \
{ \
for (i = 0; h->h_addr_list[i]; i++) \
{ \
if (*pat == NULL) { \
*pat = __alloca (sizeof (struct gaih_addrtuple)); \
(*pat)->scopeid = 0; \
} \
(*pat)->next = NULL; \
(*pat)->family = _family; \
memcpy ((*pat)->addr, h->h_addr_list[i], \
sizeof(_type)); \
pat = &((*pat)->next); \
} \
if (_family == AF_INET6) \
got_ipv6 = true; \
} \
else if (_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) \
{ \
/* We have to add V4 mapped addresses. Maybe we discard them \
later again but we get them anyhow for now. */ \
while ((rc = __gethostbyname2_r (name, AF_INET6, &th, tmpbuf, \
tmpbuflen, &h, &herrno)) == ERANGE \
&& herrno == NETDB_INTERNAL) \
tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \
\
if (rc != 0) \
{ \
if (herrno == NETDB_INTERNAL) \
{ \
__set_h_errno (herrno); \
return -EAI_SYSTEM; \
} \
if (herrno == TRY_AGAIN) \
no_data = EAI_AGAIN; \
else \
no_data = herrno == NO_DATA; \
} \
else if (h != NULL) \
{ \
for (i = 0; h->h_addr_list[i]; ++i) \
{ \
if (*pat == NULL) \
{ \
*pat = __alloca (sizeof (struct gaih_addrtuple)); \
(*pat)->scopeid = 0; \
} \
uint32_t *addr = (uint32_t *) (*pat)->addr; \
(*pat)->next = NULL; \
(*pat)->family = _family; \
addr[3] = *(uint32_t *) h->h_addr_list[i]; \
addr[2] = htonl (0xffff); \
addr[1] = 0; \
addr[0] = 0; \
pat = &((*pat)->next); \
} \
} \
} \
}
#define gethosts2(_family, _type) \
{ \ { \
int i, herrno; \ int i, herrno; \
size_t tmpbuflen; \ size_t tmpbuflen; \
@ -400,23 +314,42 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
{ \ { \
for (i = 0; h->h_addr_list[i]; i++) \ for (i = 0; h->h_addr_list[i]; i++) \
{ \ { \
if (*pat == NULL) { \ if (*pat == NULL) \
*pat = __alloca (sizeof (struct gaih_addrtuple)); \ { \
(*pat)->scopeid = 0; \ *pat = __alloca (sizeof (struct gaih_addrtuple)); \
} \ (*pat)->scopeid = 0; \
} \
uint32_t *addr = (*pat)->addr; \
(*pat)->next = NULL; \ (*pat)->next = NULL; \
(*pat)->family = _family; \ if (_family == AF_INET && req->ai_family == AF_INET6) \
memcpy ((*pat)->addr, h->h_addr_list[i], \ { \
sizeof(_type)); \ (*pat)->family = AF_INET6; \
addr[3] = *(uint32_t *) h->h_addr_list[i]; \
addr[2] = htonl (0xffff); \
addr[1] = 0; \
addr[0] = 0; \
} \
else \
{ \
(*pat)->family = _family; \
memcpy (addr, h->h_addr_list[i], sizeof(_type)); \
} \
pat = &((*pat)->next); \ pat = &((*pat)->next); \
} \ } \
\
if (_family == AF_INET6 && i > 0) \
got_ipv6 = true; \
} \ } \
} }
typedef enum nss_status (*nss_gethostbyname2_r) typedef enum nss_status (*nss_gethostbyname2_r)
(const char *name, int af, struct hostent *host, (const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop, char *buffer, size_t buflen, int *errnop,
int *h_errnop); int *h_errnop);
typedef enum nss_status (*nss_getcanonname_r)
(const char *name, char *buffer, size_t buflen, char **result,
int *errnop, int *h_errnop);
extern service_user *__nss_hosts_database attribute_hidden; extern service_user *__nss_hosts_database attribute_hidden;
static int static int
@ -428,6 +361,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple *at = NULL; struct gaih_addrtuple *at = NULL;
int rc; int rc;
bool got_ipv6 = false; bool got_ipv6 = false;
const char *canon = NULL;
if (req->ai_protocol || req->ai_socktype) if (req->ai_protocol || req->ai_socktype)
{ {
@ -581,10 +515,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
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)
{ {
((uint32_t *) at->addr)[3] = *(uint32_t *) at->addr; at->addr[3] = at->addr[0];
((uint32_t *) at->addr)[2] = htonl (0xffff); at->addr[2] = htonl (0xffff);
((uint32_t *) at->addr)[1] = 0; at->addr[1] = 0;
((uint32_t *) at->addr)[0] = 0; at->addr[0] = 0;
at->family = AF_INET6; at->family = AF_INET6;
} }
else else
@ -607,7 +541,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else if (req->ai_family == AF_INET else if (req->ai_family == AF_INET
&& IN6_IS_ADDR_V4MAPPED (at->addr)) && IN6_IS_ADDR_V4MAPPED (at->addr))
{ {
*(uint32_t *) at->addr = ((uint32_t *) at->addr)[3]; at->addr[0] = at->addr[3];
at->family = AF_INET; at->family = AF_INET;
} }
else else
@ -645,82 +579,110 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple **pat = &at; struct gaih_addrtuple **pat = &at;
int no_data = 0; int no_data = 0;
int no_inet6_data = 0; int no_inet6_data = 0;
service_user *nip = NULL;
enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
enum nss_status status = NSS_STATUS_UNAVAIL;
int no_more;
nss_gethostbyname2_r fct;
int old_res_options;
if (__nss_hosts_database != NULL)
{
no_more = 0;
nip = __nss_hosts_database;
}
else
no_more = __nss_database_lookup ("hosts", NULL,
"dns [!UNAVAIL=return] files",
&nip);
if (__res_maybe_init (&_res, 0) == -1)
no_more = 1;
/* If we are looking for both IPv4 and IPv6 address we don't /* If we are looking for both IPv4 and IPv6 address we don't
want the lookup functions to automatically promote IPv4 want the lookup functions to automatically promote IPv4
addresses to IPv6 addresses. Currently this is decided addresses to IPv6 addresses. Currently this is decided
by setting the RES_USE_INET6 bit in _res.options. */ by setting the RES_USE_INET6 bit in _res.options. */
if (req->ai_family == AF_UNSPEC) old_res_options = _res.options;
_res.options &= ~RES_USE_INET6;
while (!no_more)
{ {
service_user *nip = NULL; fct = __nss_lookup_function (nip, "gethostbyname2_r");
enum nss_status inet6_status, status = NSS_STATUS_UNAVAIL;
int no_more;
nss_gethostbyname2_r fct;
int old_res_options;
if (__nss_hosts_database != NULL) if (fct != NULL)
{ {
no_more = 0; if (req->ai_family == AF_INET6
nip = __nss_hosts_database; || req->ai_family == AF_UNSPEC)
}
else
no_more = __nss_database_lookup ("hosts", NULL,
"dns [!UNAVAIL=return] files",
&nip);
if (__res_maybe_init (&_res, 0) == -1)
no_more = 1;
old_res_options = _res.options;
_res.options &= ~RES_USE_INET6;
while (!no_more)
{
fct = __nss_lookup_function (nip, "gethostbyname2_r");
if (fct != NULL)
{ {
gethosts2 (AF_INET6, struct in6_addr); gethosts (AF_INET6, struct in6_addr);
no_inet6_data = no_data; no_inet6_data = no_data;
inet6_status = status; inet6_status = status;
gethosts2 (AF_INET, struct in_addr); }
if (req->ai_family == AF_INET
|| req->ai_family == AF_UNSPEC
|| (req->ai_family == AF_INET6
&& (req->ai_flags & AI_V4MAPPED)))
{
gethosts (AF_INET, struct in_addr);
/* If we found one address for AF_INET or AF_INET6, if (req->ai_family == AF_INET)
don't continue the search. */ {
if (inet6_status == NSS_STATUS_SUCCESS || no_inet6_data = no_data;
status == NSS_STATUS_SUCCESS) inet6_status = status;
break; }
/* We can have different states for AF_INET
and AF_INET6. Try to find a usefull 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;
} }
if (nss_next_action (nip, status) == NSS_ACTION_RETURN) /* If we found one address for AF_INET or AF_INET6,
break; don't continue the search. */
if (inet6_status == NSS_STATUS_SUCCESS
|| status == NSS_STATUS_SUCCESS)
{
/* If we need the canonical name, get it from the same
service as the result. */
nss_getcanonname_r cfct;
int herrno;
if (nip->next == NULL) cfct = __nss_lookup_function (nip, "getcanonname_r");
no_more = -1; if (cfct != NULL)
else {
nip = nip->next; const size_t max_fqdn_len = 256;
char *buf = alloca (max_fqdn_len);
char *s;
if (DL_CALL_FCT (cfct, (name, buf, max_fqdn_len,
&s, &rc, &herrno))
== NSS_STATUS_SUCCESS)
canon = s;
else
/* Set to name now to avoid using
gethostbyaddr. */
canon = name;
}
break;
}
/* 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.options = old_res_options; if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
} break;
else if (req->ai_family == AF_INET6)
{ if (nip->next == NULL)
gethosts (AF_INET6, struct in6_addr); no_more = -1;
no_inet6_data = no_data; else
} nip = nip->next;
else if (req->ai_family == AF_INET)
{
gethosts (AF_INET, struct in_addr);
no_inet6_data = no_data;
} }
_res.options = old_res_options;
if (no_data != 0 && no_inet6_data != 0) if (no_data != 0 && no_inet6_data != 0)
{ {
/* If both requests timed out report this. */ /* If both requests timed out report this. */
@ -742,13 +704,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
atr = at = __alloca (sizeof (struct gaih_addrtuple)); atr = at = __alloca (sizeof (struct gaih_addrtuple));
memset (at, '\0', sizeof (struct gaih_addrtuple)); memset (at, '\0', sizeof (struct gaih_addrtuple));
if (req->ai_family == 0) if (req->ai_family == AF_UNSPEC)
{ {
at->next = __alloca (sizeof (struct gaih_addrtuple)); at->next = __alloca (sizeof (struct gaih_addrtuple));
memset (at->next, '\0', sizeof (struct gaih_addrtuple)); memset (at->next, '\0', sizeof (struct gaih_addrtuple));
} }
if (req->ai_family == 0 || req->ai_family == AF_INET6) if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
{ {
at->family = AF_INET6; at->family = AF_INET6;
if ((req->ai_flags & AI_PASSIVE) == 0) if ((req->ai_flags & AI_PASSIVE) == 0)
@ -756,11 +718,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
atr = at->next; atr = at->next;
} }
if (req->ai_family == 0 || req->ai_family == AF_INET) if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
{ {
atr->family = AF_INET; atr->family = AF_INET;
if ((req->ai_flags & AI_PASSIVE) == 0) if ((req->ai_flags & AI_PASSIVE) == 0)
*(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK); atr->addr[0] = htonl (INADDR_LOOPBACK);
} }
} }
@ -770,7 +732,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
{ {
struct gaih_servtuple *st2; struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at; struct gaih_addrtuple *at2 = at;
size_t socklen, namelen; size_t socklen;
size_t canonlen;
sa_family_t family; sa_family_t family;
/* /*
@ -778,77 +741,46 @@ gaih_inet (const char *name, const struct gaih_service *service,
*/ */
while (at2 != NULL) while (at2 != NULL)
{ {
const char *c = NULL;
/* Only the first entry gets the canonical name. */ /* Only the first entry gets the canonical name. */
if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0) if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
{ {
struct hostent *h = NULL; if (canon == NULL)
int herrno;
struct hostent th;
size_t tmpbuflen = 512;
char *tmpbuf = NULL;
do
{ {
tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2); struct hostent *h = NULL;
rc = __gethostbyaddr_r (at2->addr, int herrno;
((at2->family == AF_INET6) struct hostent th;
? sizeof(struct in6_addr) size_t tmpbuflen = 512;
: sizeof(struct in_addr)), char *tmpbuf = NULL;
at2->family, &th, tmpbuf, tmpbuflen,
&h, &herrno);
} do
while (rc == ERANGE && herrno == NETDB_INTERNAL);
if (rc != 0 && herrno == NETDB_INTERNAL)
{
__set_h_errno (herrno);
return -EAI_SYSTEM;
}
if (h != NULL)
c = h->h_name;
else
{
/* We have to try to get the canonical in some other
way. If we are looking for either AF_INET or
AF_INET6 try the other line. */
if (req->ai_family == AF_UNSPEC)
{ {
struct addrinfo *p = NULL; tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
struct addrinfo **end = &p; rc = __gethostbyaddr_r (at2->addr,
struct addrinfo localreq = *req; ((at2->family == AF_INET6)
struct addrinfo *runp; ? sizeof (struct in6_addr)
: sizeof (struct in_addr)),
at2->family, &th, tmpbuf,
tmpbuflen, &h, &herrno);
}
while (rc == ERANGE && herrno == NETDB_INTERNAL);
localreq.ai_family = AF_INET + AF_INET6 - at2->family; if (rc != 0 && herrno == NETDB_INTERNAL)
(void) gaih_inet (name, service, &localreq, end); {
__set_h_errno (herrno);
runp = p; return -EAI_SYSTEM;
while (runp != NULL)
{
if (p->ai_canonname != name)
{
c = strdupa (p->ai_canonname);
break;
}
runp = runp->ai_next;
}
freeaddrinfo (p);
} }
/* If this code is used the missing canonical name is if (h != NULL)
substituted with the name passed in by the user. */ canon = h->h_name;
if (c == NULL) else
c = name; {
assert (name != NULL);
/* If the canonical name cannot be determined, use
the passed in string. */
canon = name;
}
} }
if (c == NULL)
return GAIH_OKIFUNSPEC | -EAI_NONAME;
#ifdef HAVE_LIBIDN #ifdef HAVE_LIBIDN
if (req->ai_flags & AI_CANONIDN) if (req->ai_flags & AI_CANONIDN)
{ {
@ -859,7 +791,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
idn_flags |= IDNA_USE_STD3_ASCII_RULES; idn_flags |= IDNA_USE_STD3_ASCII_RULES;
char *out; char *out;
int rc = __idna_to_unicode_lzlz (c, &out, idn_flags); int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags);
if (rc != IDNA_SUCCESS) if (rc != IDNA_SUCCESS)
{ {
if (rc == IDNA_MALLOC_ERROR) if (rc == IDNA_MALLOC_ERROR)
@ -870,18 +802,18 @@ gaih_inet (const char *name, const struct gaih_service *service,
} }
/* In case the output string is the same as the input /* In case the output string is the same as the input
string no new string has been allocated. */ string no new string has been allocated. */
if (out != c) if (out != canon)
{ {
c = strdupa (out); canon = strdupa (out);
free (out); free (out);
} }
} }
#endif #endif
namelen = strlen (c) + 1; canonlen = strlen (canon) + 1;
} }
else else
namelen = 0; canonlen = 0;
if (at2->family == AF_INET6) if (at2->family == AF_INET6)
{ {
@ -891,7 +823,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
/* If we looked up IPv4 mapped address discard them here if /* If we looked up IPv4 mapped address discard them here if
the caller isn't interested in all address and we have the caller isn't interested in all address and we have
found at least one IPv6 address. */ found at least one IPv6 address. */
if (! got_ipv6 if (got_ipv6
&& (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
&& IN6_IS_ADDR_V4MAPPED (at2->addr)) && IN6_IS_ADDR_V4MAPPED (at2->addr))
goto ignore; goto ignore;
@ -904,7 +836,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
for (st2 = st; st2 != NULL; st2 = st2->next) for (st2 = st; st2 != NULL; st2 = st2->next)
{ {
*pai = malloc (sizeof (struct addrinfo) + socklen + namelen); *pai = malloc (sizeof (struct addrinfo) + socklen + canonlen);
if (*pai == NULL) if (*pai == NULL)
return -EAI_MEMORY; return -EAI_MEMORY;
@ -913,7 +845,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
(*pai)->ai_socktype = st2->socktype; (*pai)->ai_socktype = st2->socktype;
(*pai)->ai_protocol = st2->protocol; (*pai)->ai_protocol = st2->protocol;
(*pai)->ai_addrlen = socklen; (*pai)->ai_addrlen = socklen;
(*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo); (*pai)->ai_addr = (void *) (*pai + 1);
#if SALEN #if SALEN
(*pai)->ai_addr->sa_len = socklen; (*pai)->ai_addr->sa_len = socklen;
#endif /* SALEN */ #endif /* SALEN */
@ -924,30 +856,30 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct sockaddr_in6 *sin6p = struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) (*pai)->ai_addr; (struct sockaddr_in6 *) (*pai)->ai_addr;
sin6p->sin6_port = st2->port;
sin6p->sin6_flowinfo = 0; sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr, memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr)); at2->addr, sizeof (struct in6_addr));
sin6p->sin6_port = st2->port;
sin6p->sin6_scope_id = at2->scopeid; sin6p->sin6_scope_id = at2->scopeid;
} }
else else
{ {
struct sockaddr_in *sinp = struct sockaddr_in *sinp =
(struct sockaddr_in *) (*pai)->ai_addr; (struct sockaddr_in *) (*pai)->ai_addr;
sinp->sin_port = st2->port;
memcpy (&sinp->sin_addr, memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr)); at2->addr, sizeof (struct in_addr));
sinp->sin_port = st2->port;
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero)); memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
} }
if (namelen != 0) if (canonlen != 0)
{ {
(*pai)->ai_canonname = ((void *) (*pai) + (*pai)->ai_canonname = ((void *) (*pai) +
sizeof (struct addrinfo) + socklen); sizeof (struct addrinfo) + socklen);
strcpy ((*pai)->ai_canonname, c); strcpy ((*pai)->ai_canonname, canon);
/* We do not need to allocate the canonical name anymore. */ /* We do not need to allocate the canonical name anymore. */
namelen = 0; canonlen = 0;
} }
else else
(*pai)->ai_canonname = NULL; (*pai)->ai_canonname = NULL;