mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 22:10:13 +00:00
Update.
* 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:
parent
1e6d2101ea
commit
28977c2c1a
20
ChangeLog
20
ChangeLog
@ -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.
|
||||
|
13
elf/Makefile
13
elf/Makefile
@ -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
74
elf/tst-dlopenrpath.c
Normal 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
36
elf/tst-dlopenrpathmod.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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
137
resolv/nss_dns/dns-canon.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user