diff options
author | Ulrich Drepper <drepper@redhat.com> | 2004-08-15 20:23:40 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2004-08-15 20:23:40 +0000 |
commit | 28977c2c1acb789660ad47e0d88e42486059c916 (patch) | |
tree | d1b43dafc0c36dc311a9bbc2177167334ff5354c | |
parent | 1e6d2101ea891d63c11e8ad096f049fbb7e35242 (diff) | |
download | glibc-28977c2c1acb789660ad47e0d88e42486059c916.tar glibc-28977c2c1acb789660ad47e0d88e42486059c916.tar.gz glibc-28977c2c1acb789660ad47e0d88e42486059c916.tar.bz2 glibc-28977c2c1acb789660ad47e0d88e42486059c916.zip |
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.
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | elf/Makefile | 13 | ||||
-rw-r--r-- | elf/tst-dlopenrpath.c | 74 | ||||
-rw-r--r-- | elf/tst-dlopenrpathmod.c | 36 | ||||
-rw-r--r-- | resolv/Makefile | 2 | ||||
-rw-r--r-- | resolv/Versions | 2 | ||||
-rw-r--r-- | resolv/nss_dns/dns-canon.c | 137 | ||||
-rw-r--r-- | sysdeps/posix/getaddrinfo.c | 404 |
8 files changed, 446 insertions, 242 deletions
@@ -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. diff --git a/elf/Makefile b/elf/Makefile index 9bbc304455..ac8319bc5f 100644 --- a/elf/Makefile +++ b/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 diff --git a/elf/tst-dlopenrpath.c b/elf/tst-dlopenrpath.c new file mode 100644 index 0000000000..964f103b8c --- /dev/null +++ b/elf/tst-dlopenrpath.c @@ -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" diff --git a/elf/tst-dlopenrpathmod.c b/elf/tst-dlopenrpathmod.c new file mode 100644 index 0000000000..8fe7873c9d --- /dev/null +++ b/elf/tst-dlopenrpathmod.c @@ -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; +} diff --git a/resolv/Makefile b/resolv/Makefile index a91e8a6f44..f6230da8fb 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -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 diff --git a/resolv/Versions b/resolv/Versions index a809508aa0..0e4fea5e19 100644 --- a/resolv/Versions +++ b/resolv/Versions @@ -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; } } diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c new file mode 100644 index 0000000000..e5b38f5e7c --- /dev/null +++ b/resolv/nss_dns/dns-canon.c @@ -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; +} diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index bdfdcfbcad..23b74296c1 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -89,7 +89,7 @@ struct gaih_addrtuple { struct gaih_addrtuple *next; int family; - char addr[16]; + uint32_t addr[4]; uint32_t scopeid; }; @@ -290,92 +290,6 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, 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; \ - struct hostent th; \ - char *tmpbuf = NULL; \ - tmpbuflen = 512; \ - no_data = 0; \ - do { \ - tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ rc = 0; \ status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, \ tmpbuflen, &rc, &herrno)); \ @@ -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) - { - service_user *nip = NULL; - 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) - { - no_more = 0; - nip = __nss_hosts_database; - } - else - no_more = __nss_database_lookup ("hosts", NULL, - "dns [!UNAVAIL=return] files", - &nip); + old_res_options = _res.options; + _res.options &= ~RES_USE_INET6; - 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"); - while (!no_more) + if (fct != NULL) { - 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 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 + || req->ai_family == AF_UNSPEC + || (req->ai_family == AF_INET6 + && (req->ai_flags & AI_V4MAPPED))) + { + gethosts (AF_INET, struct in_addr); - if (nss_next_action (nip, status) == NSS_ACTION_RETURN) - break; + if (req->ai_family == AF_INET) + { + no_inet6_data = no_data; + inet6_status = status; + } + } - if (nip->next == NULL) - no_more = -1; - else - nip = nip->next; + /* 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; + + 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; - } + do + { + 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); - 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) + if (rc != 0 && herrno == NETDB_INTERNAL) { - struct addrinfo *p = NULL; - struct addrinfo **end = &p; - struct addrinfo localreq = *req; - struct addrinfo *runp; - - 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); + __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; |