diff options
author | des <des@FreeBSD.org> | 2004-09-24 19:48:50 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2004-09-24 19:48:50 +0000 |
commit | bd20f820eed84d93e9324f7de3865ce58a0c7731 (patch) | |
tree | bb3edb8dcc07615d426eb359f46c1741e4c22575 /contrib/bind/lib/irs/getaddrinfo.c | |
parent | 3fe60073ff63db1d6dc640928a53105d35a80da4 (diff) | |
download | FreeBSD-src-bd20f820eed84d93e9324f7de3865ce58a0c7731.zip FreeBSD-src-bd20f820eed84d93e9324f7de3865ce58a0c7731.tar.gz |
Retire the BIND 8 sources.
Diffstat (limited to 'contrib/bind/lib/irs/getaddrinfo.c')
-rw-r--r-- | contrib/bind/lib/irs/getaddrinfo.c | 1229 |
1 files changed, 0 insertions, 1229 deletions
diff --git a/contrib/bind/lib/irs/getaddrinfo.c b/contrib/bind/lib/irs/getaddrinfo.c deleted file mode 100644 index 89db519..0000000 --- a/contrib/bind/lib/irs/getaddrinfo.c +++ /dev/null @@ -1,1229 +0,0 @@ -/* $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project 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 THE PROJECT 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 PROJECT 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. - */ - -/* - * Issues to be discussed: - * - Thread safe-ness must be checked. - * - Return values. There are nonstandard return values defined and used - * in the source code. This is because RFC2553 is silent about which error - * code must be returned for which situation. - * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 - * says to use inet_aton() to convert IPv4 numeric to binary (allows - * classful form as a result). - * current code - disallow classful form for IPv4 (due to use of inet_pton). - * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is - * invalid. - * current code - SEGV on freeaddrinfo(NULL) - * Note: - * - We use getipnodebyname() just for thread-safeness. There's no intent - * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to - * getipnodebyname(). - * - The code filters out AFs that are not supported by the kernel, - * when globbing NULL hostname (to loopback, or wildcard). Is it the right - * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG - * in ai_flags? - * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. - * (1) what should we do against numeric hostname (2) what should we do - * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? - * non-loopback address configured? global address configured? - * - To avoid search order issue, we have a big amount of code duplicate - * from gethnamaddr.c and some other places. The issues that there's no - * lower layer function to lookup "IPv4 or IPv6" record. Calling - * gethostbyname2 from getaddrinfo will end up in wrong search order, as - * follows: - * - The code makes use of following calls when asked to resolver with - * ai_family = PF_UNSPEC: - * getipnodebyname(host, AF_INET6); - * getipnodebyname(host, AF_INET); - * This will result in the following queries if the node is configure to - * prefer /etc/hosts than DNS: - * lookup /etc/hosts for IPv6 address - * lookup DNS for IPv6 address - * lookup /etc/hosts for IPv4 address - * lookup DNS for IPv4 address - * which may not meet people's requirement. - * The right thing to happen is to have underlying layer which does - * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. - * This would result in a bit of code duplicate with _dns_ghbyname() and - * friends. - */ - -#include "port_before.h" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <netinet/in.h> - -#include <arpa/inet.h> -#include <arpa/nameser.h> - -#include <netdb.h> -#include <resolv.h> -#include <string.h> -#include <stdlib.h> -#include <stddef.h> -#include <ctype.h> -#include <unistd.h> -#include <stdio.h> -#include <errno.h> - -#include <stdarg.h> - -#include <irs.h> -#include <isc/assertions.h> - -#include "port_after.h" - -#include "irs_data.h" - -#define SUCCESS 0 -#define ANY 0 -#define YES 1 -#define NO 0 - -static const char in_addrany[] = { 0, 0, 0, 0 }; -static const char in6_addrany[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; -static const char in_loopback[] = { 127, 0, 0, 1 }; -static const char in6_loopback[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 -}; - -static const struct afd { - int a_af; - int a_addrlen; - int a_socklen; - int a_off; - const char *a_addrany; - const char *a_loopback; - int a_scoped; -} afdl [] = { - {PF_INET6, sizeof(struct in6_addr), - sizeof(struct sockaddr_in6), - offsetof(struct sockaddr_in6, sin6_addr), - in6_addrany, in6_loopback, 1}, - {PF_INET, sizeof(struct in_addr), - sizeof(struct sockaddr_in), - offsetof(struct sockaddr_in, sin_addr), - in_addrany, in_loopback, 0}, - {0, 0, 0, 0, NULL, NULL, 0}, -}; - -struct explore { - int e_af; - int e_socktype; - int e_protocol; - const char *e_protostr; - int e_wild; -#define WILD_AF(ex) ((ex)->e_wild & 0x01) -#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) -#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) -}; - -static const struct explore explore[] = { -#if 0 - { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, -#endif - { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, - { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, - { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, - { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, - { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, - { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, - { -1, 0, 0, NULL, 0 }, -}; - -#define PTON_MAX 16 - -static int str_isnumber __P((const char *)); -static int explore_fqdn __P((const struct addrinfo *, const char *, - const char *, struct addrinfo **)); -static int explore_copy __P((const struct addrinfo *, const struct addrinfo *, - struct addrinfo **)); -static int explore_null __P((const struct addrinfo *, - const char *, struct addrinfo **)); -static int explore_numeric __P((const struct addrinfo *, const char *, - const char *, struct addrinfo **)); -static int explore_numeric_scope __P((const struct addrinfo *, const char *, - const char *, struct addrinfo **)); -static int get_canonname __P((const struct addrinfo *, - struct addrinfo *, const char *)); -static struct addrinfo *get_ai __P((const struct addrinfo *, - const struct afd *, const char *)); -static struct addrinfo *copy_ai __P((const struct addrinfo *)); -static int get_portmatch __P((const struct addrinfo *, const char *)); -static int get_port __P((const struct addrinfo *, const char *, int)); -static const struct afd *find_afd __P((int)); -static int addrconfig __P((int)); -static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *, - u_int32_t *scopeidp)); -static struct net_data *init __P((void)); - -struct addrinfo *hostent2addrinfo __P((struct hostent *, - const struct addrinfo *)); -struct addrinfo *addr2addrinfo __P((const struct addrinfo *, - const char *)); - -#if 0 -static const char *ai_errlist[] = { - "Success", - "Address family for hostname not supported", /* EAI_ADDRFAMILY */ - "Temporary failure in name resolution", /* EAI_AGAIN */ - "Invalid value for ai_flags", /* EAI_BADFLAGS */ - "Non-recoverable failure in name resolution", /* EAI_FAIL */ - "ai_family not supported", /* EAI_FAMILY */ - "Memory allocation failure", /* EAI_MEMORY */ - "No address associated with hostname", /* EAI_NODATA */ - "hostname nor servname provided, or not known", /* EAI_NONAME */ - "servname not supported for ai_socktype", /* EAI_SERVICE */ - "ai_socktype not supported", /* EAI_SOCKTYPE */ - "System error returned in errno", /* EAI_SYSTEM */ - "Invalid value for hints", /* EAI_BADHINTS */ - "Resolved protocol is unknown", /* EAI_PROTOCOL */ - "Unknown error", /* EAI_MAX */ -}; -#endif - -/* XXX macros that make external reference is BAD. */ - -#define GET_AI(ai, afd, addr) \ -do { \ - /* external reference: pai, error, and label free */ \ - (ai) = get_ai(pai, (afd), (addr)); \ - if ((ai) == NULL) { \ - error = EAI_MEMORY; \ - goto free; \ - } \ -} while (/*CONSTCOND*/0) - -#define GET_PORT(ai, serv) \ -do { \ - /* external reference: error and label free */ \ - error = get_port((ai), (serv), 0); \ - if (error != 0) \ - goto free; \ -} while (/*CONSTCOND*/0) - -#define GET_CANONNAME(ai, str) \ -do { \ - /* external reference: pai, error and label free */ \ - error = get_canonname(pai, (ai), (str)); \ - if (error != 0) \ - goto free; \ -} while (/*CONSTCOND*/0) - -#define ERR(err) \ -do { \ - /* external reference: error, and label bad */ \ - error = (err); \ - goto bad; \ - /*NOTREACHED*/ \ -} while (/*CONSTCOND*/0) - -#define MATCH_FAMILY(x, y, w) \ - ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) -#define MATCH(x, y, w) \ - ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) - -#if 0 /* bind8 has its own version */ -char * -gai_strerror(ecode) - int ecode; -{ - if (ecode < 0 || ecode > EAI_MAX) - ecode = EAI_MAX; - return ai_errlist[ecode]; -} -#endif - -void -freeaddrinfo(ai) - struct addrinfo *ai; -{ - struct addrinfo *next; - - do { - next = ai->ai_next; - if (ai->ai_canonname) - free(ai->ai_canonname); - /* no need to free(ai->ai_addr) */ - free(ai); - ai = next; - } while (ai); -} - -static int -str_isnumber(p) - const char *p; -{ - char *ep; - - if (*p == '\0') - return NO; - ep = NULL; - errno = 0; - (void)strtoul(p, &ep, 10); - if (errno == 0 && ep && *ep == '\0') - return YES; - else - return NO; -} - -int -getaddrinfo(hostname, servname, hints, res) - const char *hostname, *servname; - const struct addrinfo *hints; - struct addrinfo **res; -{ - struct addrinfo sentinel; - struct addrinfo *cur; - int error = 0; - struct addrinfo ai, ai0, *afai = NULL; - struct addrinfo *pai; - const struct explore *ex; - - memset(&sentinel, 0, sizeof(sentinel)); - cur = &sentinel; - pai = &ai; - pai->ai_flags = 0; - pai->ai_family = PF_UNSPEC; - pai->ai_socktype = ANY; - pai->ai_protocol = ANY; - pai->ai_addrlen = 0; - pai->ai_canonname = NULL; - pai->ai_addr = NULL; - pai->ai_next = NULL; - - if (hostname == NULL && servname == NULL) - return EAI_NONAME; - if (hints) { - /* error check for hints */ - if (hints->ai_addrlen || hints->ai_canonname || - hints->ai_addr || hints->ai_next) - ERR(EAI_BADHINTS); /* xxx */ - if (hints->ai_flags & ~AI_MASK) - ERR(EAI_BADFLAGS); - switch (hints->ai_family) { - case PF_UNSPEC: - case PF_INET: - case PF_INET6: - break; - default: - ERR(EAI_FAMILY); - } - memcpy(pai, hints, sizeof(*pai)); - - /* - * if both socktype/protocol are specified, check if they - * are meaningful combination. - */ - if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { - for (ex = explore; ex->e_af >= 0; ex++) { - if (pai->ai_family != ex->e_af) - continue; - if (ex->e_socktype == ANY) - continue; - if (ex->e_protocol == ANY) - continue; - if (pai->ai_socktype == ex->e_socktype && - pai->ai_protocol != ex->e_protocol) { - ERR(EAI_BADHINTS); - } - } - } - } - - /* - * post-2553: AI_ALL and AI_V4MAPPED are effective only against - * AF_INET6 query. They needs to be ignored if specified in other - * occassions. - */ - switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { - case AI_V4MAPPED: - case AI_ALL | AI_V4MAPPED: - if (pai->ai_family != AF_INET6) - pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); - break; - case AI_ALL: -#if 1 - /* illegal */ - ERR(EAI_BADFLAGS); -#else - pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); - break; -#endif - } - - /* - * check for special cases. (1) numeric servname is disallowed if - * socktype/protocol are left unspecified. (2) servname is disallowed - * for raw and other inet{,6} sockets. - */ - if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) -#ifdef PF_INET6 - || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) -#endif - ) { - ai0 = *pai; /* backup *pai */ - - if (pai->ai_family == PF_UNSPEC) { -#ifdef PF_INET6 - pai->ai_family = PF_INET6; -#else - pai->ai_family = PF_INET; -#endif - } - error = get_portmatch(pai, servname); - if (error) - ERR(error); - - *pai = ai0; - } - - ai0 = *pai; - - /* NULL hostname, or numeric hostname */ - for (ex = explore; ex->e_af >= 0; ex++) { - *pai = ai0; - - if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) - continue; - if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) - continue; - if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) - continue; - - if (pai->ai_family == PF_UNSPEC) - pai->ai_family = ex->e_af; - if (pai->ai_socktype == ANY && ex->e_socktype != ANY) - pai->ai_socktype = ex->e_socktype; - if (pai->ai_protocol == ANY && ex->e_protocol != ANY) - pai->ai_protocol = ex->e_protocol; - - /* - * if the servname does not match socktype/protocol, ignore it. - */ - if (get_portmatch(pai, servname) != 0) - continue; - - if (hostname == NULL) { - /* - * filter out AFs that are not supported by the kernel - * XXX errno? - */ - if (!addrconfig(pai->ai_family)) - continue; - error = explore_null(pai, servname, &cur->ai_next); - } else - error = explore_numeric_scope(pai, hostname, servname, - &cur->ai_next); - - if (error) - goto free; - - while (cur && cur->ai_next) - cur = cur->ai_next; - } - - /* - * XXX - * If numreic representation of AF1 can be interpreted as FQDN - * representation of AF2, we need to think again about the code below. - */ - if (sentinel.ai_next) - goto good; - - if (pai->ai_flags & AI_NUMERICHOST) - ERR(EAI_NONAME); - if (hostname == NULL) - ERR(EAI_NONAME); - - /* - * hostname as alphabetical name. - * We'll make sure that - * - if returning addrinfo list is empty, return non-zero error - * value (already known one or EAI_NONAME). - * - otherwise, - * + if we haven't had any errors, return 0 (i.e. success). - * + if we've had an error, free the list and return the error. - * without any assumption on the behavior of explore_fqdn(). - */ - - /* first, try to query DNS for all possible address families. */ - *pai = ai0; - error = explore_fqdn(pai, hostname, servname, &afai); - if (error) { - if (afai != NULL) - freeaddrinfo(afai); - goto free; - } - if (afai == NULL) { - error = EAI_NONAME; /* we've had no errors. */ - goto free; - } - - /* - * we would like to prefer AF_INET6 than AF_INET, so we'll make an - * outer loop by AFs. - */ - for (ex = explore; ex->e_af >= 0; ex++) { - *pai = ai0; - - if (pai->ai_family == PF_UNSPEC) - pai->ai_family = ex->e_af; - - if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) - continue; - if (!MATCH(pai->ai_socktype, ex->e_socktype, - WILD_SOCKTYPE(ex))) { - continue; - } - if (!MATCH(pai->ai_protocol, ex->e_protocol, - WILD_PROTOCOL(ex))) { - continue; - } - -#ifdef AI_ADDRCONFIG - /* - * If AI_ADDRCONFIG is specified, check if we are - * expected to return the address family or not. - */ - if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && - !addrconfig(pai->ai_family)) - continue; -#endif - - if (pai->ai_family == PF_UNSPEC) - pai->ai_family = ex->e_af; - if (pai->ai_socktype == ANY && ex->e_socktype != ANY) - pai->ai_socktype = ex->e_socktype; - if (pai->ai_protocol == ANY && ex->e_protocol != ANY) - pai->ai_protocol = ex->e_protocol; - - /* - * if the servname does not match socktype/protocol, ignore it. - */ - if (get_portmatch(pai, servname) != 0) - continue; - - if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) { - freeaddrinfo(afai); - goto free; - } - - while (cur && cur->ai_next) - cur = cur->ai_next; - } - - freeaddrinfo(afai); /* afai must not be NULL at this point. */ - - /* we must not have got any errors. */ - if (error != 0) /* just for diagnosis */ - abort(); - - if (sentinel.ai_next) { -good: - *res = sentinel.ai_next; - return(SUCCESS); - } else { - /* - * All the process succeeded, but we've had an empty list. - * This can happen if the given hints do not match our - * candidates. - */ - error = EAI_NONAME; - } - -free: -bad: - if (sentinel.ai_next) - freeaddrinfo(sentinel.ai_next); - *res = NULL; - return(error); -} - -/* - * FQDN hostname, DNS lookup - */ -static int -explore_fqdn(pai, hostname, servname, res) - const struct addrinfo *pai; - const char *hostname; - const char *servname; - struct addrinfo **res; -{ - struct addrinfo *result; - struct addrinfo *cur; - struct net_data *net_data = init(); - struct irs_ho *ho; - int error = 0; - char tmp[NS_MAXDNAME]; - const char *cp; - - INSIST(res != NULL && *res == NULL); - - /* - * if the servname does not match socktype/protocol, ignore it. - */ - if (get_portmatch(pai, servname) != 0) - return(0); - - if (!net_data || !(ho = net_data->ho)) - return(0); -#if 0 /* XXX (notyet) */ - if (net_data->ho_stayopen && net_data->ho_last && - net_data->ho_last->h_addrtype == af) { - if (ns_samename(name, net_data->ho_last->h_name) == 1) - return (net_data->ho_last); - for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++) - if (ns_samename(name, *hap) == 1) - return (net_data->ho_last); - } -#endif - if (!strchr(hostname, '.') && - (cp = res_hostalias(net_data->res, hostname, - tmp, sizeof(tmp)))) - hostname = cp; - result = (*ho->addrinfo)(ho, hostname, pai); - if (!net_data->ho_stayopen) { - (*ho->minimize)(ho); - } - if (result == NULL) { - int e = h_errno; - - switch(e) { - case NETDB_INTERNAL: - error = EAI_SYSTEM; - break; - case TRY_AGAIN: - error = EAI_AGAIN; - break; - case NO_RECOVERY: - error = EAI_FAIL; - break; - case HOST_NOT_FOUND: - case NO_DATA: - error = EAI_NONAME; - break; - default: - case NETDB_SUCCESS: /* should be impossible... */ - error = EAI_NONAME; - break; - } - goto free; - } - - for (cur = result; cur; cur = cur->ai_next) { - GET_PORT(cur, servname); /* XXX: redundant lookups... */ - /* canonname should already be filled. */ - } - - *res = result; - - return(0); - -free: - if (result) - freeaddrinfo(result); - return error; -} - -static int -explore_copy(pai, src0, res) - const struct addrinfo *pai; /* seed */ - const struct addrinfo *src0; /* source */ - struct addrinfo **res; -{ - int error; - struct addrinfo sentinel, *cur; - const struct addrinfo *src; - - error = 0; - sentinel.ai_next = NULL; - cur = &sentinel; - - for (src = src0; src != NULL; src = src->ai_next) { - if (src->ai_family != pai->ai_family) - continue; - - cur->ai_next = copy_ai(src); - if (!cur->ai_next) { - error = EAI_MEMORY; - goto fail; - } - - cur->ai_next->ai_socktype = pai->ai_socktype; - cur->ai_next->ai_protocol = pai->ai_protocol; - cur = cur->ai_next; - } - - *res = sentinel.ai_next; - return 0; - -fail: - freeaddrinfo(sentinel.ai_next); - return error; -} - -/* - * hostname == NULL. - * passive socket -> anyaddr (0.0.0.0 or ::) - * non-passive socket -> localhost (127.0.0.1 or ::1) - */ -static int -explore_null(pai, servname, res) - const struct addrinfo *pai; - const char *servname; - struct addrinfo **res; -{ - const struct afd *afd; - struct addrinfo *cur; - struct addrinfo sentinel; - int error; - - *res = NULL; - sentinel.ai_next = NULL; - cur = &sentinel; - - afd = find_afd(pai->ai_family); - if (afd == NULL) - return 0; - - if (pai->ai_flags & AI_PASSIVE) { - GET_AI(cur->ai_next, afd, afd->a_addrany); - /* xxx meaningless? - * GET_CANONNAME(cur->ai_next, "anyaddr"); - */ - GET_PORT(cur->ai_next, servname); - } else { - GET_AI(cur->ai_next, afd, afd->a_loopback); - /* xxx meaningless? - * GET_CANONNAME(cur->ai_next, "localhost"); - */ - GET_PORT(cur->ai_next, servname); - } - cur = cur->ai_next; - - *res = sentinel.ai_next; - return 0; - -free: - if (sentinel.ai_next) - freeaddrinfo(sentinel.ai_next); - return error; -} - -/* - * numeric hostname - */ -static int -explore_numeric(pai, hostname, servname, res) - const struct addrinfo *pai; - const char *hostname; - const char *servname; - struct addrinfo **res; -{ - const struct afd *afd; - struct addrinfo *cur; - struct addrinfo sentinel; - int error; - char pton[PTON_MAX]; - - *res = NULL; - sentinel.ai_next = NULL; - cur = &sentinel; - - afd = find_afd(pai->ai_family); - if (afd == NULL) - return 0; - - switch (afd->a_af) { -#if 0 /*X/Open spec*/ - case AF_INET: - if (inet_aton(hostname, (struct in_addr *)pton) == 1) { - if (pai->ai_family == afd->a_af || - pai->ai_family == PF_UNSPEC /*?*/) { - GET_AI(cur->ai_next, afd, pton); - GET_PORT(cur->ai_next, servname); - while (cur && cur->ai_next) - cur = cur->ai_next; - } else - ERR(EAI_FAMILY); /*xxx*/ - } - break; -#endif - default: - if (inet_pton(afd->a_af, hostname, pton) == 1) { - if (pai->ai_family == afd->a_af || - pai->ai_family == PF_UNSPEC /*?*/) { - GET_AI(cur->ai_next, afd, pton); - GET_PORT(cur->ai_next, servname); - while (cur && cur->ai_next) - cur = cur->ai_next; - } else - ERR(EAI_FAMILY); /*xxx*/ - } - break; - } - - *res = sentinel.ai_next; - return 0; - -free: -bad: - if (sentinel.ai_next) - freeaddrinfo(sentinel.ai_next); - return error; -} - -/* - * numeric hostname with scope - */ -static int -explore_numeric_scope(pai, hostname, servname, res) - const struct addrinfo *pai; - const char *hostname; - const char *servname; - struct addrinfo **res; -{ -#ifndef SCOPE_DELIMITER - return explore_numeric(pai, hostname, servname, res); -#else - const struct afd *afd; - struct addrinfo *cur; - int error; - char *cp, *hostname2 = NULL, *scope, *addr; - struct sockaddr_in6 *sin6; - - afd = find_afd(pai->ai_family); - if (afd == NULL) - return 0; - - if (!afd->a_scoped) - return explore_numeric(pai, hostname, servname, res); - - cp = strchr(hostname, SCOPE_DELIMITER); - if (cp == NULL) - return explore_numeric(pai, hostname, servname, res); - - /* - * Handle special case of <scoped_address><delimiter><scope id> - */ - hostname2 = strdup(hostname); - if (hostname2 == NULL) - return EAI_MEMORY; - /* terminate at the delimiter */ - hostname2[cp - hostname] = '\0'; - addr = hostname2; - scope = cp + 1; - - error = explore_numeric(pai, addr, servname, res); - if (error == 0) { - u_int32_t scopeid = 0; - - for (cur = *res; cur; cur = cur->ai_next) { - if (cur->ai_family != AF_INET6) - continue; - sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; - if (!ip6_str2scopeid(scope, sin6, &scopeid)) { - free(hostname2); - return(EAI_NONAME); /* XXX: is return OK? */ - } -#ifdef HAVE_SIN6_SCOPE_ID - sin6->sin6_scope_id = scopeid; -#endif - } - } - - free(hostname2); - - return error; -#endif -} - -static int -get_canonname(pai, ai, str) - const struct addrinfo *pai; - struct addrinfo *ai; - const char *str; -{ - if ((pai->ai_flags & AI_CANONNAME) != 0) { - ai->ai_canonname = (char *)malloc(strlen(str) + 1); - if (ai->ai_canonname == NULL) - return EAI_MEMORY; - strcpy(ai->ai_canonname, str); - } - return 0; -} - -static struct addrinfo * -get_ai(pai, afd, addr) - const struct addrinfo *pai; - const struct afd *afd; - const char *addr; -{ - char *p; - struct addrinfo *ai; - - ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) - + (afd->a_socklen)); - if (ai == NULL) - return NULL; - - memcpy(ai, pai, sizeof(struct addrinfo)); - ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); - memset(ai->ai_addr, 0, (size_t)afd->a_socklen); -#ifdef HAVE_SA_LEN - ai->ai_addr->sa_len = afd->a_socklen; -#endif - ai->ai_addrlen = afd->a_socklen; - ai->ai_addr->sa_family = ai->ai_family = afd->a_af; - p = (char *)(void *)(ai->ai_addr); - memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); - return ai; -} - -/* XXX need to malloc() the same way we do from other functions! */ -static struct addrinfo * -copy_ai(pai) - const struct addrinfo *pai; -{ - struct addrinfo *ai; - size_t l; - - l = sizeof(*ai) + pai->ai_addrlen; - if ((ai = (struct addrinfo *)malloc(l)) == NULL) - return NULL; - memset(ai, 0, l); - memcpy(ai, pai, sizeof(*ai)); - ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); - memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen); - - if (pai->ai_canonname) { - l = strlen(pai->ai_canonname) + 1; - if ((ai->ai_canonname = malloc(l)) == NULL) { - free(ai); - return NULL; - } -#ifdef HAVE_STRLCPY - strlcpy(ai->ai_canonname, pai->ai_canonname, l); -#else - strncpy(ai->ai_canonname, pai->ai_canonname, l); -#endif - } else { - /* just to make sure */ - ai->ai_canonname = NULL; - } - - ai->ai_next = NULL; - - return ai; -} - -static int -get_portmatch(const struct addrinfo *ai, const char *servname) { - - /* get_port does not touch first argument. when matchonly == 1. */ - /* LINTED const cast */ - return get_port((const struct addrinfo *)ai, servname, 1); -} - -static int -get_port(const struct addrinfo *ai, const char *servname, int matchonly) { - const char *proto; - struct servent *sp; - int port; - int allownumeric; - - if (servname == NULL) - return 0; - switch (ai->ai_family) { - case AF_INET: -#ifdef AF_INET6 - case AF_INET6: -#endif - break; - default: - return 0; - } - - switch (ai->ai_socktype) { - case SOCK_RAW: - return EAI_SERVICE; - case SOCK_DGRAM: - case SOCK_STREAM: - allownumeric = 1; - break; - case ANY: - switch (ai->ai_family) { - case AF_INET: -#ifdef AF_INET6 - case AF_INET6: -#endif - allownumeric = 1; - break; - default: - allownumeric = 0; - break; - } - break; - default: - return EAI_SOCKTYPE; - } - - if (str_isnumber(servname)) { - if (!allownumeric) - return EAI_SERVICE; - port = atoi(servname); - if (port < 0 || port > 65535) - return EAI_SERVICE; - port = htons(port); - } else { - switch (ai->ai_socktype) { - case SOCK_DGRAM: - proto = "udp"; - break; - case SOCK_STREAM: - proto = "tcp"; - break; - default: - proto = NULL; - break; - } - - if ((sp = getservbyname(servname, proto)) == NULL) - return EAI_SERVICE; - port = sp->s_port; - } - - if (!matchonly) { - switch (ai->ai_family) { - case AF_INET: - ((struct sockaddr_in *)(void *) - ai->ai_addr)->sin_port = port; - break; - case AF_INET6: - ((struct sockaddr_in6 *)(void *) - ai->ai_addr)->sin6_port = port; - break; - } - } - - return 0; -} - -static const struct afd * -find_afd(af) - int af; -{ - const struct afd *afd; - - if (af == PF_UNSPEC) - return NULL; - for (afd = afdl; afd->a_af; afd++) { - if (afd->a_af == af) - return afd; - } - return NULL; -} - -/* - * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend - * will take care of it. - * the semantics of AI_ADDRCONFIG is not defined well. we are not sure - * if the code is right or not. - */ -static int -addrconfig(af) - int af; -{ - int s; - - /* XXX errno */ - s = socket(af, SOCK_DGRAM, 0); - if (s < 0) { - if (errno != EMFILE) - return 0; - } else - close(s); - return 1; -} - -/* convert a string to a scope identifier. XXX: IPv6 specific */ -static int -ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, - u_int32_t *scopeidp) -{ - u_int32_t scopeid; - u_long lscopeid; - struct in6_addr *a6 = &sin6->sin6_addr; - char *ep; - - /* empty scopeid portion is invalid */ - if (*scope == '\0') - return (0); - -#ifdef USE_IFNAMELINKID - if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { - /* - * Using interface names as link indices can be allowed - * only when we can assume a one-to-one mappings between - * links and interfaces. See comments in getnameinfo.c. - */ - scopeid = if_nametoindex(scope); - if (scopeid == 0) - *scopeidp = scopeid; - return (1); - } -#endif - - /* still unclear about literal, allow numeric only - placeholder */ - if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) - goto trynumeric; - if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) - goto trynumeric; - else - goto trynumeric; /* global */ - - /* try to convert to a numeric id as a last resort */ -trynumeric: - errno = 0; - lscopeid = strtoul(scope, &ep, 10); - scopeid = lscopeid & 0xffffffff; - if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) { - *scopeidp = scopeid; - return (1); - } else - return (0); -} - -struct addrinfo * -hostent2addrinfo(hp, pai) - struct hostent *hp; - const struct addrinfo *pai; -{ - int i, af, error = 0; - char **aplist = NULL, *ap; - struct addrinfo sentinel, *cur; - const struct afd *afd; - - af = hp->h_addrtype; - if (pai->ai_family != AF_UNSPEC && af != pai->ai_family) - return(NULL); - - afd = find_afd(af); - if (afd == NULL) - return(NULL); - - aplist = hp->h_addr_list; - - memset(&sentinel, 0, sizeof(sentinel)); - cur = &sentinel; - - for (i = 0; (ap = aplist[i]) != NULL; i++) { -#if 0 /* the trick seems too much */ - af = hp->h_addr_list; - if (af == AF_INET6 && - IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { - af = AF_INET; - ap = ap + sizeof(struct in6_addr) - - sizeof(struct in_addr); - } - afd = find_afd(af); - if (afd == NULL) - continue; -#endif /* 0 */ - - GET_AI(cur->ai_next, afd, ap); - - /* GET_PORT(cur->ai_next, servname); */ - if ((pai->ai_flags & AI_CANONNAME) != 0) { - /* - * RFC2553 says that ai_canonname will be set only for - * the first element. we do it for all the elements, - * just for convenience. - */ - GET_CANONNAME(cur->ai_next, hp->h_name); - } - while (cur && cur->ai_next) /* no need to loop, actually. */ - cur = cur->ai_next; - continue; - - free: - if (cur->ai_next) - freeaddrinfo(cur->ai_next); - cur->ai_next = NULL; - /* continue, without tht pointer CUR advanced. */ - } - - return(sentinel.ai_next); -} - -struct addrinfo * -addr2addrinfo(pai, cp) - const struct addrinfo *pai; - const char *cp; -{ - const struct afd *afd; - - afd = find_afd(pai->ai_family); - if (afd == NULL) - return(NULL); - - return(get_ai(pai, afd, cp)); -} - -static struct net_data * -init() -{ - struct net_data *net_data; - - if (!(net_data = net_data_init(NULL))) - goto error; - if (!net_data->ho) { - net_data->ho = (*net_data->irs->ho_map)(net_data->irs); - if (!net_data->ho || !net_data->res) { -error: - errno = EIO; - if (net_data && net_data->res) - RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL); - return (NULL); - } - - (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL); - } - - return (net_data); -} |