* 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>
* 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.
* 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-array2dep.c tst-piemod1.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-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 \
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 \
$(tests-execstack-$(have-z-execstack)) tst-dlmodcount
$(tests-execstack-$(have-z-execstack)) tst-dlmodcount tst-dlopenrpath
# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
@ -184,7 +184,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
circlemod3 circlemod3a \
reldep8mod1 reldep8mod2 reldep8mod3 \
reldep9mod1 reldep9mod2 reldep9mod3 \
tst-alignmod $(modules-execstack-$(have-z-execstack))
tst-alignmod $(modules-execstack-$(have-z-execstack)) \
tst-dlopenrpathmod
ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep
endif
@ -747,3 +748,9 @@ $(objpfx)tst-dlmodcount: $(libdl)
$(objpfx)tst-dlmodcount.out: $(test-modules)
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
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)
libnss_dns-inhibit-o = $(filter-out .os,$(object-suffixes))
endif

View File

@ -86,7 +86,7 @@ libnss_dns {
GLIBC_PRIVATE {
_nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_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;
int family;
char addr[16];
uint32_t addr[4];
uint32_t scopeid;
};
@ -281,92 +281,6 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
#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; \
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++) \
{ \
if (*pat == NULL) { \
*pat = __alloca (sizeof (struct gaih_addrtuple)); \
(*pat)->scopeid = 0; \
} \
if (*pat == NULL) \
{ \
*pat = __alloca (sizeof (struct gaih_addrtuple)); \
(*pat)->scopeid = 0; \
} \
uint32_t *addr = (*pat)->addr; \
(*pat)->next = NULL; \
(*pat)->family = _family; \
memcpy ((*pat)->addr, h->h_addr_list[i], \
sizeof(_type)); \
if (_family == AF_INET && req->ai_family == AF_INET6) \
{ \
(*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); \
} \
\
if (_family == AF_INET6 && i > 0) \
got_ipv6 = true; \
} \
}
typedef enum nss_status (*nss_gethostbyname2_r)
(const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *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;
static int
@ -428,6 +361,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple *at = NULL;
int rc;
bool got_ipv6 = false;
const char *canon = NULL;
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;
else if (req->ai_family == AF_INET6 && req->ai_flags & AI_V4MAPPED)
{
((uint32_t *) at->addr)[3] = *(uint32_t *) at->addr;
((uint32_t *) at->addr)[2] = htonl (0xffff);
((uint32_t *) at->addr)[1] = 0;
((uint32_t *) at->addr)[0] = 0;
at->addr[3] = at->addr[0];
at->addr[2] = htonl (0xffff);
at->addr[1] = 0;
at->addr[0] = 0;
at->family = AF_INET6;
}
else
@ -607,7 +541,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else if (req->ai_family == AF_INET
&& 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;
}
else
@ -645,82 +579,110 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple **pat = &at;
int no_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
want the lookup functions to automatically promote IPv4
addresses to IPv6 addresses. Currently this is decided
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;
enum nss_status inet6_status, status = NSS_STATUS_UNAVAIL;
int no_more;
nss_gethostbyname2_r fct;
int old_res_options;
fct = __nss_lookup_function (nip, "gethostbyname2_r");
if (__nss_hosts_database != NULL)
if (fct != 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;
old_res_options = _res.options;
_res.options &= ~RES_USE_INET6;
while (!no_more)
{
fct = __nss_lookup_function (nip, "gethostbyname2_r");
if (fct != NULL)
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
gethosts2 (AF_INET6, struct in6_addr);
gethosts (AF_INET6, struct in6_addr);
no_inet6_data = no_data;
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,
don't continue the search. */
if (inet6_status == NSS_STATUS_SUCCESS ||
status == NSS_STATUS_SUCCESS)
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 (req->ai_family == AF_INET)
{
no_inet6_data = no_data;
inet6_status = status;
}
}
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
/* If we found one address for AF_INET or AF_INET6,
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)
no_more = -1;
else
nip = nip->next;
cfct = __nss_lookup_function (nip, "getcanonname_r");
if (cfct != NULL)
{
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;
}
else if (req->ai_family == AF_INET6)
{
gethosts (AF_INET6, struct in6_addr);
no_inet6_data = no_data;
}
else if (req->ai_family == AF_INET)
{
gethosts (AF_INET, struct in_addr);
no_inet6_data = no_data;
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
if (nip->next == NULL)
no_more = -1;
else
nip = nip->next;
}
_res.options = old_res_options;
if (no_data != 0 && no_inet6_data != 0)
{
/* 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));
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));
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;
if ((req->ai_flags & AI_PASSIVE) == 0)
@ -756,11 +718,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
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;
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_addrtuple *at2 = at;
size_t socklen, namelen;
size_t socklen;
size_t canonlen;
sa_family_t family;
/*
@ -778,77 +741,46 @@ gaih_inet (const char *name, const struct gaih_service *service,
*/
while (at2 != NULL)
{
const char *c = NULL;
/* Only the first entry gets the canonical name. */
if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
{
struct hostent *h = NULL;
int herrno;
struct hostent th;
size_t tmpbuflen = 512;
char *tmpbuf = NULL;
do
if (canon == NULL)
{
tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
rc = __gethostbyaddr_r (at2->addr,
((at2->family == AF_INET6)
? sizeof(struct in6_addr)
: sizeof(struct in_addr)),
at2->family, &th, tmpbuf, tmpbuflen,
&h, &herrno);
struct hostent *h = NULL;
int herrno;
struct hostent th;
size_t tmpbuflen = 512;
char *tmpbuf = NULL;
}
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)
do
{
struct addrinfo *p = NULL;
struct addrinfo **end = &p;
struct addrinfo localreq = *req;
struct addrinfo *runp;
tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
rc = __gethostbyaddr_r (at2->addr,
((at2->family == AF_INET6)
? 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;
(void) gaih_inet (name, service, &localreq, end);
runp = p;
while (runp != NULL)
{
if (p->ai_canonname != name)
{
c = strdupa (p->ai_canonname);
break;
}
runp = runp->ai_next;
}
freeaddrinfo (p);
if (rc != 0 && herrno == NETDB_INTERNAL)
{
__set_h_errno (herrno);
return -EAI_SYSTEM;
}
/* If this code is used the missing canonical name is
substituted with the name passed in by the user. */
if (c == NULL)
c = name;
if (h != NULL)
canon = h->h_name;
else
{
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
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;
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_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
string no new string has been allocated. */
if (out != c)
if (out != canon)
{
c = strdupa (out);
canon = strdupa (out);
free (out);
}
}
#endif
namelen = strlen (c) + 1;
canonlen = strlen (canon) + 1;
}
else
namelen = 0;
canonlen = 0;
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
the caller isn't interested in all address and we have
found at least one IPv6 address. */
if (! got_ipv6
if (got_ipv6
&& (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
&& IN6_IS_ADDR_V4MAPPED (at2->addr))
goto ignore;
@ -904,7 +836,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
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)
return -EAI_MEMORY;
@ -913,7 +845,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
(*pai)->ai_socktype = st2->socktype;
(*pai)->ai_protocol = st2->protocol;
(*pai)->ai_addrlen = socklen;
(*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
(*pai)->ai_addr = (void *) (*pai + 1);
#if SALEN
(*pai)->ai_addr->sa_len = socklen;
#endif /* SALEN */
@ -924,30 +856,30 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) (*pai)->ai_addr;
sin6p->sin6_port = st2->port;
sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr));
sin6p->sin6_port = st2->port;
sin6p->sin6_scope_id = at2->scopeid;
}
else
{
struct sockaddr_in *sinp =
(struct sockaddr_in *) (*pai)->ai_addr;
sinp->sin_port = st2->port;
memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr));
sinp->sin_port = st2->port;
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
}
if (namelen != 0)
if (canonlen != 0)
{
(*pai)->ai_canonname = ((void *) (*pai) +
sizeof (struct addrinfo) + socklen);
strcpy ((*pai)->ai_canonname, c);
strcpy ((*pai)->ai_canonname, canon);
/* We do not need to allocate the canonical name anymore. */
namelen = 0;
canonlen = 0;
}
else
(*pai)->ai_canonname = NULL;