diff options
| author | Arjun Shankar <arjun@redhat.com> | 2023-10-02 14:55:27 +0200 |
|---|---|---|
| committer | Arjun Shankar <arjun@redhat.com> | 2023-10-24 12:31:00 +0200 |
| commit | 7f602256ab5b85db1dbfb5f40bd109c4b37b68c8 (patch) | |
| tree | 88cf9fb3bc04eae6ae9ca3816fac75d78f691740 /sysdeps | |
| parent | 1d74d2f042a405982661267394e16126db70dc5f (diff) | |
| download | glibc-7f602256ab5b85db1dbfb5f40bd109c4b37b68c8.tar.xz glibc-7f602256ab5b85db1dbfb5f40bd109c4b37b68c8.zip | |
Move getaddrinfo from 'posix' into 'nss'
getaddrinfo is an entry point for nss functionality. This commit moves
it from 'sysdeps/posix' to 'nss', gets rid of the stub in 'posix', and
moves all associated tests as well.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'sysdeps')
| -rw-r--r-- | sysdeps/posix/getaddrinfo.c | 2625 |
1 files changed, 0 insertions, 2625 deletions
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c deleted file mode 100644 index 531124958d..0000000000 --- a/sysdeps/posix/getaddrinfo.c +++ /dev/null @@ -1,2625 +0,0 @@ -/* Host and service name lookups using Name Service Switch modules. - Copyright (C) 1996-2023 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -/* The Inner Net License, Version 2.00 - - The author(s) grant permission for redistribution and use in source and -binary forms, with or without modification, of the software and documentation -provided that the following conditions are met: - -0. If you receive a version of the software that is specifically labelled - as not being for redistribution (check the version message and/or README), - you are not permitted to redistribute that version of the software in any - way or form. -1. All terms of the all other applicable copyrights and licenses must be - followed. -2. Redistributions of source code must retain the authors' copyright - notice(s), this list of conditions, and the following disclaimer. -3. Redistributions in binary form must reproduce the authors' copyright - notice(s), this list of conditions, and the following disclaimer in the - documentation and/or other materials provided with the distribution. -4. [The copyright holder has authorized the removal of this clause.] -5. Neither the name(s) of the author(s) nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - If these license terms cause you a real problem, contact the author. */ - -/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */ - -#include <assert.h> -#include <ctype.h> -#include <errno.h> -#include <ifaddrs.h> -#include <netdb.h> -#include <nss.h> -#include <resolv/resolv-internal.h> -#include <resolv/resolv_context.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdio_ext.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <arpa/inet.h> -#include <net/if.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/un.h> -#include <sys/utsname.h> -#include <unistd.h> -#include <nsswitch.h> -#include <libc-lock.h> -#include <not-cancel.h> -#include <nscd/nscd-client.h> -#include <nscd/nscd_proto.h> -#include <scratch_buffer.h> -#include <inet/net-internal.h> - -/* Former AI_IDN_ALLOW_UNASSIGNED and AI_IDN_USE_STD3_ASCII_RULES - flags, now ignored. */ -#define DEPRECATED_AI_IDN 0x300 - -#if IS_IN (libc) -# define feof_unlocked(fp) __feof_unlocked (fp) -#endif - -struct gaih_service - { - const char *name; - int num; - }; - -struct gaih_servtuple - { - int socktype; - int protocol; - int port; - bool set; - }; - - -struct gaih_typeproto - { - int socktype; - int protocol; - uint8_t protoflag; - bool defaultflag; - char name[8]; - }; - -struct gaih_result -{ - struct gaih_addrtuple *at; - char *canon; - char *h_name; - bool free_at; - bool got_ipv6; -}; - -/* Values for `protoflag'. */ -#define GAI_PROTO_NOSERVICE 1 -#define GAI_PROTO_PROTOANY 2 - -static const struct gaih_typeproto gaih_inet_typeproto[] = -{ - { 0, 0, 0, false, "" }, - { SOCK_STREAM, IPPROTO_TCP, 0, true, "tcp" }, - { SOCK_DGRAM, IPPROTO_UDP, 0, true, "udp" }, -#if defined SOCK_DCCP && defined IPPROTO_DCCP - { SOCK_DCCP, IPPROTO_DCCP, 0, false, "dccp" }, -#endif -#ifdef IPPROTO_UDPLITE - { SOCK_DGRAM, IPPROTO_UDPLITE, 0, false, "udplite" }, -#endif -#ifdef IPPROTO_SCTP - { SOCK_STREAM, IPPROTO_SCTP, 0, false, "sctp" }, - { SOCK_SEQPACKET, IPPROTO_SCTP, 0, false, "sctp" }, -#endif - { SOCK_RAW, 0, GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, true, "raw" }, - { 0, 0, 0, false, "" } -}; - -static const struct addrinfo default_hints = - { - .ai_flags = AI_DEFAULT, - .ai_family = PF_UNSPEC, - .ai_socktype = 0, - .ai_protocol = 0, - .ai_addrlen = 0, - .ai_addr = NULL, - .ai_canonname = NULL, - .ai_next = NULL - }; - -static void -gaih_result_reset (struct gaih_result *res) -{ - if (res->free_at) - free (res->at); - free (res->canon); - free (res->h_name); - memset (res, 0, sizeof (*res)); -} - -static int -gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, - const struct addrinfo *req, struct gaih_servtuple *st, - struct scratch_buffer *tmpbuf) -{ - struct servent *s; - struct servent ts; - int r; - - do - { - r = __getservbyname_r (servicename, tp->name, &ts, - tmpbuf->data, tmpbuf->length, &s); - if (r != 0 || s == NULL) - { - if (r == ERANGE) - { - if (!scratch_buffer_grow (tmpbuf)) - return -EAI_MEMORY; - } - else - return -EAI_SERVICE; - } - } - while (r); - - st->socktype = tp->socktype; - st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) - ? req->ai_protocol : tp->protocol); - st->port = s->s_port; - st->set = true; - - return 0; -} - -/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new - addresses are appended to the tuple array in RES. */ -static bool -convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, - struct hostent *h, struct gaih_result *res) -{ - /* Count the number of addresses in h->h_addr_list. */ - size_t count = 0; - for (char **p = h->h_addr_list; *p != NULL; ++p) - ++count; - - /* Report no data if no addresses are available, or if the incoming - address size is larger than what we can store. */ - if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr)) - return true; - - struct gaih_addrtuple *array = res->at; - size_t old = 0; - - while (array != NULL) - { - old++; - array = array->next; - } - - array = realloc (res->at, (old + count) * sizeof (*array)); - - if (array == NULL) - return false; - - res->got_ipv6 = family == AF_INET6; - res->at = array; - res->free_at = true; - - /* Duplicate h_name because it may get reclaimed when the underlying storage - is freed. */ - if (res->h_name == NULL) - { - res->h_name = __strdup (h->h_name); - if (res->h_name == NULL) - return false; - } - - /* Update the next pointers on reallocation. */ - for (size_t i = 0; i < old; i++) - array[i].next = array + i + 1; - - array += old; - - memset (array, 0, count * sizeof (*array)); - - for (size_t i = 0; i < count; ++i) - { - if (family == AF_INET && req->ai_family == AF_INET6) - { - /* Perform address mapping. */ - array[i].family = AF_INET6; - memcpy(array[i].addr + 3, h->h_addr_list[i], sizeof (uint32_t)); - array[i].addr[2] = htonl (0xffff); - } - else - { - array[i].family = family; - memcpy (array[i].addr, h->h_addr_list[i], h->h_length); - } - array[i].next = array + i + 1; - } - array[count - 1].next = NULL; - - return true; -} - -static int -gethosts (nss_gethostbyname3_r fct, int family, const char *name, - const struct addrinfo *req, struct scratch_buffer *tmpbuf, - struct gaih_result *res, enum nss_status *statusp, int *no_datap) -{ - struct hostent th; - char *localcanon = NULL; - enum nss_status status; - - *no_datap = 0; - while (1) - { - *statusp = status = DL_CALL_FCT (fct, (name, family, &th, - tmpbuf->data, tmpbuf->length, - &errno, &h_errno, NULL, - &localcanon)); - if (status != NSS_STATUS_TRYAGAIN || h_errno != NETDB_INTERNAL - || errno != ERANGE) - break; - if (!scratch_buffer_grow (tmpbuf)) - return -EAI_MEMORY; - } - if (status == NSS_STATUS_NOTFOUND - || status == NSS_STATUS_TRYAGAIN || status == NSS_STATUS_UNAVAIL) - { - if (h_errno == NETDB_INTERNAL) - return -EAI_SYSTEM; - if (h_errno == TRY_AGAIN) - *no_datap = EAI_AGAIN; - else - *no_datap = h_errno == NO_DATA; - } - else if (status == NSS_STATUS_SUCCESS) - { - if (!convert_hostent_to_gaih_addrtuple (req, family, &th, res)) - return -EAI_MEMORY; - - if (localcanon != NULL && res->canon == NULL) - { - char *canonbuf = __strdup (localcanon); - if (canonbuf == NULL) - return -EAI_MEMORY; - res->canon = canonbuf; - } - } - - return 0; -} - -/* This function is called if a canonical name is requested, but if - the service function did not provide it. It tries to obtain the - name using getcanonname_r from the same service NIP. If the name - cannot be canonicalized, return a copy of NAME. Return NULL on - memory allocation failure. The returned string is allocated on the - heap; the caller has to free it. */ -static char * -getcanonname (nss_action_list nip, const char *hname, const char *name) -{ - nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); - char *s = (char *) name; - if (cfct != NULL) - { - char buf[256]; - if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno, - &h_errno)) != NSS_STATUS_SUCCESS) - /* If the canonical name cannot be determined, use the passed - string. */ - s = (char *) name; - } - return __strdup (s); -} - -/* Process looked up canonical name and if necessary, decode to IDNA. Result - is a new string written to CANONP and the earlier string is freed. */ - -static int -process_canonname (const struct addrinfo *req, const char *orig_name, - struct gaih_result *res) -{ - char *canon = res->canon; - - if ((req->ai_flags & AI_CANONNAME) != 0) - { - bool do_idn = req->ai_flags & AI_CANONIDN; - if (do_idn) - { - char *out; - int rc = __idna_from_dns_encoding (canon ?: orig_name, &out); - if (rc == 0) - { - free (canon); - canon = out; - } - else if (rc == EAI_IDN_ENCODE) - /* Use the punycode name as a fallback. */ - do_idn = false; - else - return -rc; - } - if (!do_idn && canon == NULL && (canon = __strdup (orig_name)) == NULL) - return -EAI_MEMORY; - } - - res->canon = canon; - return 0; -} - -static int -get_servtuples (const struct gaih_service *service, const struct addrinfo *req, - struct gaih_servtuple *st, struct scratch_buffer *tmpbuf) -{ - int i; - const struct gaih_typeproto *tp = gaih_inet_typeproto; - - if (req->ai_protocol || req->ai_socktype) - { - ++tp; - - while (tp->name[0] - && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype) - || (req->ai_protocol != 0 - && !(tp->protoflag & GAI_PROTO_PROTOANY) - && req->ai_protocol != tp->protocol))) - ++tp; - - if (! tp->name[0]) - { - if (req->ai_socktype) - return -EAI_SOCKTYPE; - else - return -EAI_SERVICE; - } - } - - if (service != NULL && (tp->protoflag & GAI_PROTO_NOSERVICE) != 0) - return -EAI_SERVICE; - - if (service == NULL || service->num >= 0) - { - int port = service != NULL ? htons (service->num) : 0; - - if (req->ai_socktype || req->ai_protocol) - { - st[0].socktype = tp->socktype; - st[0].protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) - ? req->ai_protocol : tp->protocol); - st[0].port = port; - st[0].set = true; - - return 0; - } - - /* Neither socket type nor protocol is set. Return all socket types - we know about. */ - for (i = 0, ++tp; tp->name[0]; ++tp) - if (tp->defaultflag) - { - st[i].socktype = tp->socktype; - st[i].protocol = tp->protocol; - st[i].port = port; - st[i++].set = true; - } - - return 0; - } - - if (tp->name[0]) - return gaih_inet_serv (service->name, tp, req, st, tmpbuf); - - for (i = 0, tp++; tp->name[0]; tp++) - { - if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) - continue; - - if (req->ai_socktype != 0 - && req->ai_socktype != tp->socktype) - continue; - if (req->ai_protocol != 0 - && !(tp->protoflag & GAI_PROTO_PROTOANY) - && req->ai_protocol != tp->protocol) - continue; - - if (gaih_inet_serv (service->name, - tp, req, &st[i], tmpbuf) != 0) - continue; - - i++; - } - - if (!st[0].set) - return -EAI_SERVICE; - - return 0; -} - -#ifdef USE_NSCD -/* Query addresses from nscd cache, returning a non-zero value on error. - RES members have the lookup result; RES->AT is NULL if there were no errors - but also no results. */ - -static int -get_nscd_addresses (const char *name, const struct addrinfo *req, - struct gaih_result *res) -{ - if (__nss_not_use_nscd_hosts > 0 - && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) - __nss_not_use_nscd_hosts = 0; - - res->at = NULL; - - if (__nss_not_use_nscd_hosts || __nss_database_custom[NSS_DBSIDX_hosts]) - return 0; - - /* Try to use nscd. */ - struct nscd_ai_result *air = NULL; - int err = __nscd_getai (name, &air, &h_errno); - - if (__glibc_unlikely (air == NULL)) - { - /* The database contains a negative entry. */ - if (err == 0) - return -EAI_NONAME; - if (__nss_not_use_nscd_hosts == 0) - { - if (h_errno == NETDB_INTERNAL && errno == ENOMEM) - return -EAI_MEMORY; - if (h_errno == TRY_AGAIN) - return -EAI_AGAIN; - return -EAI_SYSTEM; - } - return 0; - } - - /* Transform into gaih_addrtuple list. */ - int result = 0; - char *addrs = air->addrs; - - struct gaih_addrtuple *addrfree = calloc (air->naddrs, sizeof (*addrfree)); - struct gaih_addrtuple *at = calloc (air->naddrs, sizeof (*at)); - if (at == NULL) - { - result = -EAI_MEMORY; - goto out; - } - - res->free_at = true; - - int count = 0; - for (int i = 0; i < air->naddrs; ++i) - { - socklen_t size = (air->family[i] == AF_INET - ? INADDRSZ : IN6ADDRSZ); - - if (!((air->family[i] == AF_INET - && req->ai_family == AF_INET6 - && (req->ai_flags & AI_V4MAPPED) != 0) - || req->ai_family == AF_UNSPEC - || air->family[i] == req->ai_family)) - { - /* Skip over non-matching result. */ - addrs += size; - continue; - } - - if (air->family[i] == AF_INET && req->ai_family == AF_INET6 - && (req->ai_flags & AI_V4MAPPED)) - { - at[count].family = AF_INET6; - at[count].addr[3] = *(uint32_t *) addrs; - at[count].addr[2] = htonl (0xffff); - } - else if (req->ai_family == AF_UNSPEC - || air->family[i] == req->ai_family) - { - at[count].family = air->family[i]; - memcpy (at[count].addr, addrs, size); - if (air->family[i] == AF_INET6) - res->got_ipv6 = true; - } - at[count].next = at + count + 1; - count++; - addrs += size; - } - - if ((req->ai_flags & AI_CANONNAME) && air->canon != NULL) - { - char *canonbuf = __strdup (air->canon); - if (canonbuf == NULL) - { - result = -EAI_MEMORY; - goto out; - } - res->canon = canonbuf; - } - - if (count == 0) - { - result = -EAI_NONAME; - goto out; - } - - at[count - 1].next = NULL; - - res->at = at; - -out: - free (air); - if (result != 0) - { - free (at); - res->free_at = false; - } - - return result; -} -#endif - -static int -get_nss_addresses (const char *name, const struct addrinfo *req, - struct scratch_buffer *tmpbuf, struct gaih_result *res) -{ - int no_data = 0; - int no_inet6_data = 0; - nss_action_list nip; - enum nss_status inet6_status = NSS_STATUS_UNAVAIL; - enum nss_status status = NSS_STATUS_UNAVAIL; - int no_more; - struct resolv_context *res_ctx = NULL; - bool do_merge = false; - int result = 0; - - no_more = !__nss_database_get (nss_database_hosts, &nip); - - /* 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, so we use the no_inet6 - function variant. */ - res_ctx = __resolv_context_get (); - if (res_ctx == NULL) - no_more = 1; - - while (!no_more) - { - /* Always start afresh; continue should discard previous results - and the hosts database does not support merge. */ - gaih_result_reset (res); - - if (do_merge) - { - __set_h_errno (NETDB_INTERNAL); - __set_errno (EBUSY); - break; - } - - no_data = 0; - nss_gethostbyname4_r *fct4 = NULL; - - /* gethostbyname4_r sends out parallel A and AAAA queries and - is thus only suitable for PF_UNSPEC. */ - if (req->ai_family == PF_UNSPEC) - fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); - - if (fct4 != NULL) - { - while (1) - { - status = DL_CALL_FCT (fct4, (name, &res->at, - tmpbuf->data, tmpbuf->length, - &errno, &h_errno, - NULL)); - if (status == NSS_STATUS_SUCCESS) - break; - /* gethostbyname4_r may write into AT, so reset it. */ - res->at = NULL; - if (status != NSS_STATUS_TRYAGAIN - || errno != ERANGE || h_errno != NETDB_INTERNAL) - { - if (h_errno == TRY_AGAIN) - no_data = EAI_AGAIN; - else - no_data = h_errno == NO_DATA; - break; - } - - if (!scratch_buffer_grow (tmpbuf)) - { - __resolv_context_put (res_ctx); - result = -EAI_MEMORY; - goto out; - } - } - - if (status == NSS_STATUS_SUCCESS) - { - assert (!no_data); - no_data = 1; - - if ((req->ai_flags & AI_CANONNAME) != 0 && res->canon == NULL) - { - char *canonbuf = __strdup (res->at->name); - if (canonbuf == NULL) - { - __resolv_context_put (res_ctx); - result = -EAI_MEMORY; - goto out; - } - res->canon = canonbuf; - } - - struct gaih_addrtuple **pat = &res->at; - - while (*pat != NULL) - { - if ((*pat)->family == AF_INET - && req->ai_family == AF_INET6 - && (req->ai_flags & AI_V4MAPPED) != 0) - { - uint32_t *pataddr = (*pat)->addr; - (*pat)->family = AF_INET6; - pataddr[3] = pataddr[0]; - pataddr[2] = htonl (0xffff); - pataddr[1] = 0; - pataddr[0] = 0; - pat = &((*pat)->next); - no_data = 0; - } - else if (req->ai_family == AF_UNSPEC - || (*pat)->family == req->ai_family) - { - pat = &((*pat)->next); - - no_data = 0; - if (req->ai_family == AF_INET6) - res->got_ipv6 = true; - } - else - *pat = ((*pat)->next); - } - } - - no_inet6_data = no_data; - } - else - { - nss_gethostbyname3_r *fct = NULL; - if (req->ai_flags & AI_CANONNAME) - /* No need to use this function if we do not look for - the canonical name. The function does not exist in - all NSS modules and therefore the lookup would - often fail. */ - fct = __nss_lookup_function (nip, "gethostbyname3_r"); - if (fct == NULL) - /* We are cheating here. The gethostbyname2_r - function does not have the same interface as - gethostbyname3_r but the extra arguments the - latter takes are added at the end. So the - gethostbyname2_r code will just ignore them. */ - fct = __nss_lookup_function (nip, "gethostbyname2_r"); - - if (fct != NULL) - { - if (req->ai_family == AF_INET6 - || req->ai_family == AF_UNSPEC) - { - if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf, - res, &status, &no_data)) != 0) - { - __resolv_context_put (res_ctx); - goto out; - } - no_inet6_data = no_data; - inet6_status = status; - } - if (req->ai_family == AF_INET - || req->ai_family == AF_UNSPEC - || (req->ai_family == AF_INET6 - && (req->ai_flags & AI_V4MAPPED) - /* Avoid generating the mapped addresses if we - know we are not going to need them. */ - && ((req->ai_flags & AI_ALL) || !res->got_ipv6))) - { - if ((resu |
