Home | History | Annotate | Line # | Download | only in net
getaddrinfo.c revision 1.31
      1 /*	$NetBSD: getaddrinfo.c,v 1.31 2000/02/17 17:06:17 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Issues to be discussed:
     34  * - Thread safe-ness must be checked.
     35  * - Return values.  There are nonstandard return values defined and used
     36  *   in the source code.  This is because RFC2553 is silent about which error
     37  *   code must be returned for which situation.
     38  * - IPv4 classful (shortened) form.  RFC2553 is silent about it.  XNET 5.2
     39  *   says to use inet_aton() to convert IPv4 numeric to binary (alows
     40  *   classful form as a result).
     41  *   current code - disallow classful form for IPv4 (due to use of inet_pton).
     42  * - freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
     43  *   invalid.
     44  *   current code - SEGV on freeaddrinfo(NULL)
     45  * Note:
     46  * - We use getipnodebyname() just for thread-safeness.  There's no intent
     47  *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
     48  *   getipnodebyname().
     49  * - The code filters out AFs that are not supported by the kernel,
     50  *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
     51  *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
     52  *   in ai_flags?
     53  * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
     54  *   (1) what should we do against numeric hostname (2) what should we do
     55  *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
     56  *   non-loopback address configured?  global address configured?
     57  * - The code makes use of following calls when asked to resolver with
     58  *   ai_family  = PF_UNSPEC:
     59  *	getipnodebyname(host, AF_INET6);
     60  *	getipnodebyname(host, AF_INET);
     61  *   This will result in the following queries if the node is configure to
     62  *   prefer /etc/hosts than DNS:
     63  *	lookup /etc/hosts for IPv6 address
     64  *	lookup DNS for IPv6 address
     65  *	lookup /etc/hosts for IPv4 address
     66  *	lookup DNS for IPv4 address
     67  *   which may not meet people's requirement.
     68  *   The right thing to happen is to have underlying layer which does
     69  *   PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
     70  *   This would result in a bit of code duplicate with _dns_ghbyname() and
     71  *   friends.
     72  */
     73 
     74 #include <sys/types.h>
     75 #include <sys/param.h>
     76 #include <sys/socket.h>
     77 #include <net/if.h>
     78 #include <netinet/in.h>
     79 #include <arpa/inet.h>
     80 #include <arpa/nameser.h>
     81 #include <netdb.h>
     82 #include <resolv.h>
     83 #include <string.h>
     84 #include <stdlib.h>
     85 #include <stddef.h>
     86 #include <ctype.h>
     87 #include <unistd.h>
     88 #include <stdio.h>
     89 #include <errno.h>
     90 
     91 #define SUCCESS 0
     92 #define ANY 0
     93 #define YES 1
     94 #define NO  0
     95 
     96 static const char in_addrany[] = { 0, 0, 0, 0 };
     97 static const char in6_addrany[] = {
     98 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
     99 };
    100 static const char in_loopback[] = { 127, 0, 0, 1 };
    101 static const char in6_loopback[] = {
    102 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
    103 };
    104 
    105 struct sockinet {
    106 	u_char	si_len;
    107 	u_char	si_family;
    108 	u_short	si_port;
    109 	u_int32_t si_scope_id;
    110 };
    111 
    112 static const struct afd {
    113 	int a_af;
    114 	int a_addrlen;
    115 	int a_socklen;
    116 	int a_off;
    117 	const char *a_addrany;
    118 	const char *a_loopback;
    119 	int a_scoped;
    120 } afdl [] = {
    121 #ifdef INET6
    122 	{PF_INET6, sizeof(struct in6_addr),
    123 	 sizeof(struct sockaddr_in6),
    124 	 offsetof(struct sockaddr_in6, sin6_addr),
    125 	 in6_addrany, in6_loopback, 1},
    126 #endif
    127 	{PF_INET, sizeof(struct in_addr),
    128 	 sizeof(struct sockaddr_in),
    129 	 offsetof(struct sockaddr_in, sin_addr),
    130 	 in_addrany, in_loopback, 0},
    131 	{0, 0, 0, 0, NULL, NULL, 0},
    132 };
    133 
    134 struct explore {
    135 	int e_af;
    136 	int e_socktype;
    137 	int e_protocol;
    138 	const char *e_protostr;
    139 	int e_wild;
    140 #define WILD_AF(ex)		((ex)->e_wild & 0x01)
    141 #define WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
    142 #define WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
    143 };
    144 
    145 static const struct explore explore[] = {
    146 #if 0
    147 	{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
    148 #endif
    149 #ifdef INET6
    150 	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
    151 	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
    152 	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
    153 #endif
    154 	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
    155 	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
    156 	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
    157 	{ -1, 0, 0, NULL, 0 },
    158 };
    159 
    160 #ifdef INET6
    161 #define PTON_MAX	16
    162 #else
    163 #define PTON_MAX	4
    164 #endif
    165 
    166 
    167 static int str_isnumber __P((const char *));
    168 static int explore_fqdn __P((const struct addrinfo *, const char *,
    169 	const char *, struct addrinfo **));
    170 static int explore_null __P((const struct addrinfo *,
    171 	const char *, struct addrinfo **));
    172 static int explore_numeric __P((const struct addrinfo *, const char *,
    173 	const char *, struct addrinfo **));
    174 static int explore_numeric_scope __P((const struct addrinfo *, const char *,
    175 	const char *, struct addrinfo **));
    176 static int get_canonname __P((const struct addrinfo *,
    177 	struct addrinfo *, const char *));
    178 static struct addrinfo *get_ai __P((const struct addrinfo *,
    179 	const struct afd *, const char *));
    180 static int get_portmatch __P((const struct addrinfo *, const char *));
    181 static int get_port __P((struct addrinfo *, const char *, int));
    182 static const struct afd *find_afd __P((int));
    183 static int addrconfig __P((const struct addrinfo *));
    184 #ifdef INET6
    185 static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
    186 #endif
    187 
    188 static char *ai_errlist[] = {
    189 	"Success",
    190 	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
    191 	"Temporary failure in name resolution",		/* EAI_AGAIN      */
    192 	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
    193 	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
    194 	"ai_family not supported",			/* EAI_FAMILY     */
    195 	"Memory allocation failure", 			/* EAI_MEMORY     */
    196 	"No address associated with hostname", 		/* EAI_NODATA     */
    197 	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
    198 	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
    199 	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
    200 	"System error returned in errno", 		/* EAI_SYSTEM     */
    201 	"Invalid value for hints",			/* EAI_BADHINTS	  */
    202 	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
    203 	"Unknown error", 				/* EAI_MAX        */
    204 };
    205 
    206 /* XXX macros that make external reference is BAD. */
    207 
    208 #define GET_AI(ai, afd, addr) \
    209 do { \
    210 	/* external reference: pai, error, and label free */ \
    211 	(ai) = get_ai(pai, (afd), (addr)); \
    212 	if ((ai) == NULL) { \
    213 		error = EAI_MEMORY; \
    214 		goto free; \
    215 	} \
    216 } while (/*CONSTCOND*/0)
    217 
    218 #define GET_PORT(ai, serv) \
    219 do { \
    220 	/* external reference: error and label free */ \
    221 	error = get_port((ai), (serv), 0); \
    222 	if (error != 0) \
    223 		goto free; \
    224 } while (/*CONSTCOND*/0)
    225 
    226 #define GET_CANONNAME(ai, str) \
    227 do { \
    228 	/* external reference: pai, error and label free */ \
    229 	error = get_canonname(pai, (ai), (str)); \
    230 	if (error != 0) \
    231 		goto free; \
    232 } while (/*CONSTCOND*/0)
    233 
    234 #define ERR(err) \
    235 do { \
    236 	/* external reference: error, and label bad */ \
    237 	error = (err); \
    238 	goto bad; \
    239 } while (/*CONSTCOND*/0)
    240 
    241 #define MATCH_FAMILY(x, y, w) \
    242 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
    243 #define MATCH(x, y, w) \
    244 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
    245 
    246 char *
    247 gai_strerror(ecode)
    248 	int ecode;
    249 {
    250 	if (ecode < 0 || ecode > EAI_MAX)
    251 		ecode = EAI_MAX;
    252 	return ai_errlist[ecode];
    253 }
    254 
    255 void
    256 freeaddrinfo(ai)
    257 	struct addrinfo *ai;
    258 {
    259 	struct addrinfo *next;
    260 
    261 	do {
    262 		next = ai->ai_next;
    263 		if (ai->ai_canonname)
    264 			free(ai->ai_canonname);
    265 		/* no need to free(ai->ai_addr) */
    266 		free(ai);
    267 		ai = next;
    268 	} while (ai);
    269 }
    270 
    271 static int
    272 str_isnumber(p)
    273 	const char *p;
    274 {
    275 	const char *q = (const char *)p;
    276 	while (*q) {
    277 		if (!isdigit(*q))
    278 			return NO;
    279 		q++;
    280 	}
    281 	return YES;
    282 }
    283 
    284 int
    285 getaddrinfo(hostname, servname, hints, res)
    286 	const char *hostname, *servname;
    287 	const struct addrinfo *hints;
    288 	struct addrinfo **res;
    289 {
    290 	struct addrinfo sentinel;
    291 	struct addrinfo *cur;
    292 	int error = 0;
    293 	struct addrinfo ai;
    294 	struct addrinfo ai0;
    295 	struct addrinfo *pai;
    296 	const struct afd *afd;
    297 	const struct explore *ex;
    298 
    299 	sentinel.ai_next = NULL;
    300 	cur = &sentinel;
    301 	pai = &ai;
    302 	pai->ai_flags = 0;
    303 	pai->ai_family = PF_UNSPEC;
    304 	pai->ai_socktype = ANY;
    305 	pai->ai_protocol = ANY;
    306 	pai->ai_addrlen = 0;
    307 	pai->ai_canonname = NULL;
    308 	pai->ai_addr = NULL;
    309 	pai->ai_next = NULL;
    310 
    311 	if (hostname == NULL && servname == NULL)
    312 		return EAI_NONAME;
    313 	if (hints) {
    314 		/* error check for hints */
    315 		if (hints->ai_addrlen || hints->ai_canonname ||
    316 		    hints->ai_addr || hints->ai_next)
    317 			ERR(EAI_BADHINTS); /* xxx */
    318 		if (hints->ai_flags & ~AI_MASK)
    319 			ERR(EAI_BADFLAGS);
    320 		switch (hints->ai_family) {
    321 		case PF_UNSPEC:
    322 		case PF_INET:
    323 #ifdef INET6
    324 		case PF_INET6:
    325 #endif
    326 			break;
    327 		default:
    328 			ERR(EAI_FAMILY);
    329 		}
    330 		memcpy(pai, hints, sizeof(*pai));
    331 
    332 		/*
    333 		 * if both socktype/protocol are specified, check if they
    334 		 * are meaningful combination.
    335 		 */
    336 		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
    337 			for (ex = explore; ex->e_af >= 0; ex++) {
    338 				if (pai->ai_family != ex->e_af)
    339 					continue;
    340 				if (ex->e_socktype == ANY)
    341 					continue;
    342 				if (ex->e_protocol == ANY)
    343 					continue;
    344 				if (pai->ai_socktype == ex->e_socktype
    345 				 && pai->ai_protocol != ex->e_protocol) {
    346 					ERR(EAI_BADHINTS);
    347 				}
    348 			}
    349 		}
    350 	}
    351 
    352 	/*
    353 	 * check for special cases.  (1) numeric servname is disallowed if
    354 	 * socktype/protocol are left unspecified. (2) servname is disallowed
    355 	 * for raw and other inet{,6} sockets.
    356 	 */
    357 	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
    358 #ifdef PF_INET6
    359 	 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
    360 #endif
    361 	    ) {
    362 		ai0 = *pai;	/* backup *pai */
    363 
    364 		if (pai->ai_family == PF_UNSPEC) {
    365 #ifdef PF_INET6
    366 			pai->ai_family = PF_INET6;
    367 #else
    368 			pai->ai_family = PF_INET;
    369 #endif
    370 		}
    371 		error = get_portmatch(pai, servname);
    372 		if (error)
    373 			ERR(error);
    374 
    375 		*pai = ai0;
    376 	}
    377 
    378 	ai0 = *pai;
    379 
    380 	/* NULL hostname, or numeric hostname */
    381 	for (ex = explore; ex->e_af >= 0; ex++) {
    382 		*pai = ai0;
    383 
    384 		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
    385 			continue;
    386 		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
    387 			continue;
    388 		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
    389 			continue;
    390 
    391 		if (pai->ai_family == PF_UNSPEC)
    392 			pai->ai_family = ex->e_af;
    393 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
    394 			pai->ai_socktype = ex->e_socktype;
    395 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
    396 			pai->ai_protocol = ex->e_protocol;
    397 
    398 		if (hostname == NULL)
    399 			error = explore_null(pai, servname, &cur->ai_next);
    400 		else
    401 			error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
    402 
    403 		if (error)
    404 			goto free;
    405 
    406 		while (cur && cur->ai_next)
    407 			cur = cur->ai_next;
    408 	}
    409 
    410 	/*
    411 	 * XXX
    412 	 * If numreic representation of AF1 can be interpreted as FQDN
    413 	 * representation of AF2, we need to think again about the code below.
    414 	 */
    415 	if (sentinel.ai_next)
    416 		goto good;
    417 
    418 	if (pai->ai_flags & AI_NUMERICHOST)
    419 		ERR(EAI_NONAME);
    420 	if (hostname == NULL)
    421 		ERR(EAI_NONAME);
    422 
    423 	/*
    424 	 * hostname as alphabetical name.
    425 	 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
    426 	 * outer loop by AFs.
    427 	 */
    428 	for (afd = afdl; afd->a_af; afd++) {
    429 		*pai = ai0;
    430 
    431 		if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
    432 			continue;
    433 
    434 		for (ex = explore; ex->e_af >= 0; ex++) {
    435 			*pai = ai0;
    436 
    437 			if (pai->ai_family == PF_UNSPEC)
    438 				pai->ai_family = afd->a_af;
    439 
    440 			if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
    441 				continue;
    442 			if (!MATCH(pai->ai_socktype, ex->e_socktype,
    443 					WILD_SOCKTYPE(ex))) {
    444 				continue;
    445 			}
    446 			if (!MATCH(pai->ai_protocol, ex->e_protocol,
    447 					WILD_PROTOCOL(ex))) {
    448 				continue;
    449 			}
    450 
    451 			if (pai->ai_family == PF_UNSPEC)
    452 				pai->ai_family = ex->e_af;
    453 			if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
    454 				pai->ai_socktype = ex->e_socktype;
    455 			if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
    456 				pai->ai_protocol = ex->e_protocol;
    457 
    458 			error = explore_fqdn(pai, hostname, servname,
    459 				&cur->ai_next);
    460 
    461 			while (cur && cur->ai_next)
    462 				cur = cur->ai_next;
    463 		}
    464 	}
    465 
    466 	/* XXX */
    467 	if (sentinel.ai_next)
    468 		error = 0;
    469 
    470 	if (error)
    471 		goto free;
    472 	if (error == 0) {
    473 		if (sentinel.ai_next) {
    474  good:
    475 			*res = sentinel.ai_next;
    476 			return SUCCESS;
    477 		} else
    478 			error = EAI_FAIL;
    479 	}
    480  free:
    481  bad:
    482 	if (sentinel.ai_next)
    483 		freeaddrinfo(sentinel.ai_next);
    484 	*res = NULL;
    485 	return error;
    486 }
    487 
    488 /*
    489  * FQDN hostname, DNS lookup
    490  */
    491 static int
    492 explore_fqdn(pai, hostname, servname, res)
    493 	const struct addrinfo *pai;
    494 	const char *hostname;
    495 	const char *servname;
    496 	struct addrinfo **res;
    497 {
    498 	struct hostent *hp;
    499 	int h_error;
    500 	int af;
    501 	char **aplist = NULL, *apbuf = NULL;
    502 	char *ap;
    503 	struct addrinfo sentinel, *cur;
    504 	int i;
    505 	int naddrs;
    506 	const struct afd *afd;
    507 	int error = 0;
    508 
    509 	*res = NULL;
    510 	sentinel.ai_next = NULL;
    511 	cur = &sentinel;
    512 
    513 	/*
    514 	 * If AI_ADDRCONFIG is specified, check if we are expected to
    515 	 * return the address family or not.
    516 	 */
    517 	if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(pai))
    518 		return 0;
    519 
    520 	/*
    521 	 * if the servname does not match socktype/protocol, ignore it.
    522 	 */
    523 	if (get_portmatch(pai, servname) != 0)
    524 		return 0;
    525 
    526 	afd = find_afd(pai->ai_family);
    527 
    528 	hp = gethostbyname2(hostname, pai->ai_family);
    529 	h_error = h_errno;
    530 
    531 	if (hp == NULL) {
    532 		switch (h_error) {
    533 		case HOST_NOT_FOUND:
    534 		case NO_DATA:
    535 			error = EAI_NODATA;
    536 			break;
    537 		case TRY_AGAIN:
    538 			error = EAI_AGAIN;
    539 			break;
    540 		case NO_RECOVERY:
    541 		case NETDB_INTERNAL:
    542 		default:
    543 			error = EAI_FAIL;
    544 			break;
    545 		}
    546 	} else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
    547 			|| (hp->h_addr_list[0] == NULL)) {
    548 		hp = NULL;
    549 		error = EAI_FAIL;
    550 	}
    551 
    552 	if (hp == NULL)
    553 		goto free;
    554 
    555 	/*
    556 	 * hp will be overwritten if we use gethostbyname2().
    557 	 * always deep copy for simplification.
    558 	 */
    559 	for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++)
    560 		;
    561 	naddrs++;
    562 	aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
    563 	apbuf = (char *)malloc((size_t)hp->h_length * naddrs);
    564 	if (aplist == NULL || apbuf == NULL) {
    565 		error = EAI_MEMORY;
    566 		goto free;
    567 	}
    568 	memset(aplist, 0, sizeof(aplist[0]) * naddrs);
    569 	for (i = 0; i < naddrs; i++) {
    570 		if (hp->h_addr_list[i] == NULL) {
    571 			aplist[i] = NULL;
    572 			continue;
    573 		}
    574 		memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
    575 			(size_t)hp->h_length);
    576 		aplist[i] = &apbuf[i * hp->h_length];
    577 	}
    578 
    579 	for (i = 0; aplist[i] != NULL; i++) {
    580 		af = hp->h_addrtype;
    581 		ap = aplist[i];
    582 #ifdef AF_INET6
    583 		if (af == AF_INET6
    584 		 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
    585 			af = AF_INET;
    586 			ap = ap + sizeof(struct in6_addr)
    587 				- sizeof(struct in_addr);
    588 		}
    589 #endif
    590 
    591 		if (af != pai->ai_family)
    592 			continue;
    593 
    594 		GET_AI(cur->ai_next, afd, ap);
    595 		GET_PORT(cur->ai_next, servname);
    596 		if ((pai->ai_flags & AI_CANONNAME) != 0) {
    597 			/*
    598 			 * RFC2553 says that ai_canonname will be set only for
    599 			 * the first element.  we do it for all the elements,
    600 			 * just for convenience.
    601 			 */
    602 			GET_CANONNAME(cur->ai_next, hp->h_name);
    603 		}
    604 
    605 		while (cur && cur->ai_next)
    606 			cur = cur->ai_next;
    607 	}
    608 
    609 	*res = sentinel.ai_next;
    610 	return 0;
    611 
    612 free:
    613 	if (aplist)
    614 		free(aplist);
    615 	if (apbuf)
    616 		free(apbuf);
    617 	if (sentinel.ai_next)
    618 		freeaddrinfo(sentinel.ai_next);
    619 	return error;
    620 }
    621 
    622 /*
    623  * hostname == NULL.
    624  * passive socket -> anyaddr (0.0.0.0 or ::)
    625  * non-passive socket -> localhost (127.0.0.1 or ::1)
    626  */
    627 static int
    628 explore_null(pai, servname, res)
    629 	const struct addrinfo *pai;
    630 	const char *servname;
    631 	struct addrinfo **res;
    632 {
    633 	int s;
    634 	const struct afd *afd;
    635 	struct addrinfo *cur;
    636 	struct addrinfo sentinel;
    637 	int error;
    638 
    639 	*res = NULL;
    640 	sentinel.ai_next = NULL;
    641 	cur = &sentinel;
    642 
    643 	/*
    644 	 * filter out AFs that are not supported by the kernel
    645 	 * XXX errno?
    646 	 */
    647 	s = socket(pai->ai_family, SOCK_DGRAM, 0);
    648 	if (s < 0) {
    649 		if (errno != EMFILE)
    650 			return 0;
    651 	} else
    652 		close(s);
    653 
    654 	/*
    655 	 * if the servname does not match socktype/protocol, ignore it.
    656 	 */
    657 	if (get_portmatch(pai, servname) != 0)
    658 		return 0;
    659 
    660 	afd = find_afd(pai->ai_family);
    661 
    662 	if (pai->ai_flags & AI_PASSIVE) {
    663 		GET_AI(cur->ai_next, afd, afd->a_addrany);
    664 		/* xxx meaningless?
    665 		 * GET_CANONNAME(cur->ai_next, "anyaddr");
    666 		 */
    667 		GET_PORT(cur->ai_next, servname);
    668 	} else {
    669 		GET_AI(cur->ai_next, afd, afd->a_loopback);
    670 		/* xxx meaningless?
    671 		 * GET_CANONNAME(cur->ai_next, "localhost");
    672 		 */
    673 		GET_PORT(cur->ai_next, servname);
    674 	}
    675 	cur = cur->ai_next;
    676 
    677 	*res = sentinel.ai_next;
    678 	return 0;
    679 
    680 free:
    681 	if (sentinel.ai_next)
    682 		freeaddrinfo(sentinel.ai_next);
    683 	return error;
    684 }
    685 
    686 /*
    687  * numeric hostname
    688  */
    689 static int
    690 explore_numeric(pai, hostname, servname, res)
    691 	const struct addrinfo *pai;
    692 	const char *hostname;
    693 	const char *servname;
    694 	struct addrinfo **res;
    695 {
    696 	const struct afd *afd;
    697 	struct addrinfo *cur;
    698 	struct addrinfo sentinel;
    699 	int error;
    700 	char pton[PTON_MAX];
    701 	int flags;
    702 
    703 	*res = NULL;
    704 	sentinel.ai_next = NULL;
    705 	cur = &sentinel;
    706 
    707 	/*
    708 	 * if the servname does not match socktype/protocol, ignore it.
    709 	 */
    710 	if (get_portmatch(pai, servname) != 0)
    711 		return 0;
    712 
    713 	afd = find_afd(pai->ai_family);
    714 	flags = pai->ai_flags;
    715 
    716 	switch (afd->a_af) {
    717 #if 0 /*X/Open spec*/
    718 	case AF_INET:
    719 		if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
    720 			if (pai->ai_family == afd->a_af ||
    721 			    pai->ai_family == PF_UNSPEC /*?*/) {
    722 				GET_AI(cur->ai_next, afd, pton);
    723 				GET_PORT(cur->ai_next, servname);
    724 				while (cur && cur->ai_next)
    725 					cur = cur->ai_next;
    726 			} else
    727 				ERR(EAI_FAMILY);	/*xxx*/
    728 		}
    729 		break;
    730 #endif
    731 	default:
    732 		if (inet_pton(afd->a_af, hostname, pton) == 1) {
    733 			if (pai->ai_family == afd->a_af ||
    734 			    pai->ai_family == PF_UNSPEC /*?*/) {
    735 				GET_AI(cur->ai_next, afd, pton);
    736 				GET_PORT(cur->ai_next, servname);
    737 				while (cur && cur->ai_next)
    738 					cur = cur->ai_next;
    739 			} else
    740 				ERR(EAI_FAMILY);	/*xxx*/
    741 		}
    742 		break;
    743 	}
    744 
    745 	*res = sentinel.ai_next;
    746 	return 0;
    747 
    748 free:
    749 bad:
    750 	if (sentinel.ai_next)
    751 		freeaddrinfo(sentinel.ai_next);
    752 	return error;
    753 }
    754 
    755 /*
    756  * numeric hostname with scope
    757  */
    758 static int
    759 explore_numeric_scope(pai, hostname, servname, res)
    760 	const struct addrinfo *pai;
    761 	const char *hostname;
    762 	const char *servname;
    763 	struct addrinfo **res;
    764 {
    765 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
    766 	return explore_numeric(pai, hostname, servname, res);
    767 #else
    768 	const struct afd *afd;
    769 	struct addrinfo *cur;
    770 	int error;
    771 	char *cp, *hostname2 = NULL, *scope, *addr;
    772 	struct sockaddr_in6 *sin6;
    773 
    774 	/*
    775 	 * if the servname does not match socktype/protocol, ignore it.
    776 	 */
    777 	if (get_portmatch(pai, servname) != 0)
    778 		return 0;
    779 
    780 	afd = find_afd(pai->ai_family);
    781 	if (!afd->a_scoped)
    782 		return explore_numeric(pai, hostname, servname, res);
    783 
    784 	cp = strchr(hostname, SCOPE_DELIMITER);
    785 	if (cp == NULL)
    786 		return explore_numeric(pai, hostname, servname, res);
    787 
    788 #if 0
    789 	/*
    790 	 * Handle special case of <scope id><delimiter><scoped_address>
    791 	 */
    792 	hostname2 = strdup(hostname);
    793 	if (hostname2 == NULL)
    794 		return EAI_MEMORY;
    795 	/* terminate at the delimiter */
    796 	hostname2[cp - hostname] = '\0';
    797 	scope = hostname2;
    798 	addr = cp + 1;
    799 #else
    800 	/*
    801 	 * Handle special case of <scoped_address><delimiter><scope id>
    802 	 */
    803 	hostname2 = strdup(hostname);
    804 	if (hostname2 == NULL)
    805 		return EAI_MEMORY;
    806 	/* terminate at the delimiter */
    807 	hostname2[cp - hostname] = '\0';
    808 	addr = hostname2;
    809 	scope = cp + 1;
    810 #endif
    811 
    812 	error = explore_numeric(pai, addr, servname, res);
    813 	if (error == 0) {
    814 		int scopeid;
    815 
    816 		for (cur = *res; cur; cur = cur->ai_next) {
    817 			if (cur->ai_family != AF_INET6)
    818 				continue;
    819 			sin6 = (struct sockaddr_in6 *)cur->ai_addr;
    820 			if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) {
    821 				free(hostname2);
    822 				return(EAI_NONAME); /* XXX: is return OK? */
    823 			}
    824 			sin6->sin6_scope_id = scopeid;
    825 		}
    826 	}
    827 
    828 	free(hostname2);
    829 
    830 	return error;
    831 #endif
    832 }
    833 
    834 static int
    835 get_canonname(pai, ai, str)
    836 	const struct addrinfo *pai;
    837 	struct addrinfo *ai;
    838 	const char *str;
    839 {
    840 	if ((pai->ai_flags & AI_CANONNAME) != 0) {
    841 		ai->ai_canonname = (char *)malloc(strlen(str) + 1);
    842 		if (ai->ai_canonname == NULL)
    843 			return EAI_MEMORY;
    844 		strcpy(ai->ai_canonname, str);
    845 	}
    846 	return 0;
    847 }
    848 
    849 static struct addrinfo *
    850 get_ai(pai, afd, addr)
    851 	const struct addrinfo *pai;
    852 	const struct afd *afd;
    853 	const char *addr;
    854 {
    855 	char *p;
    856 	struct addrinfo *ai;
    857 
    858 	ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
    859 		+ (afd->a_socklen));
    860 	if (ai == NULL)
    861 		return NULL;
    862 
    863 	memcpy(ai, pai, sizeof(struct addrinfo));
    864 	ai->ai_addr = (struct sockaddr *)(ai + 1);
    865 	memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
    866 	ai->ai_addr->sa_len = afd->a_socklen;
    867 	ai->ai_addrlen = afd->a_socklen;
    868 	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
    869 	p = (char *)(ai->ai_addr);
    870 	memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
    871 	return ai;
    872 }
    873 
    874 static int
    875 get_portmatch(ai, servname)
    876 	const struct addrinfo *ai;
    877 	const char *servname;
    878 {
    879 
    880 	/* get_port does not touch first argument. when matchonly == 1. */
    881 	return get_port((struct addrinfo *)ai, servname, 1);
    882 }
    883 
    884 static int
    885 get_port(ai, servname, matchonly)
    886 	struct addrinfo *ai;
    887 	const char *servname;
    888 	int matchonly;
    889 {
    890 	const char *proto;
    891 	struct servent *sp;
    892 	int port;
    893 	int allownumeric;
    894 
    895 	if (servname == NULL)
    896 		return 0;
    897 	switch (ai->ai_family) {
    898 	case AF_INET:
    899 #ifdef AF_INET6
    900 	case AF_INET6:
    901 #endif
    902 		break;
    903 	default:
    904 		return 0;
    905 	}
    906 
    907 	switch (ai->ai_socktype) {
    908 	case SOCK_RAW:
    909 		return EAI_SERVICE;
    910 	case SOCK_DGRAM:
    911 	case SOCK_STREAM:
    912 		allownumeric = 1;
    913 		break;
    914 	case ANY:
    915 		allownumeric = 0;
    916 		break;
    917 	default:
    918 		return EAI_SOCKTYPE;
    919 	}
    920 
    921 	if (str_isnumber(servname)) {
    922 		if (!allownumeric)
    923 			return EAI_SERVICE;
    924 		port = htons(atoi(servname));
    925 		if (port < 0 || port > 65535)
    926 			return EAI_SERVICE;
    927 	} else {
    928 		switch (ai->ai_socktype) {
    929 		case SOCK_DGRAM:
    930 			proto = "udp";
    931 			break;
    932 		case SOCK_STREAM:
    933 			proto = "tcp";
    934 			break;
    935 		default:
    936 			proto = NULL;
    937 			break;
    938 		}
    939 
    940 		if ((sp = getservbyname(servname, proto)) == NULL)
    941 			return EAI_SERVICE;
    942 		port = sp->s_port;
    943 	}
    944 
    945 	if (!matchonly) {
    946 		switch (ai->ai_family) {
    947 		case AF_INET:
    948 			((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
    949 			break;
    950 #ifdef INET6
    951 		case AF_INET6:
    952 			((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
    953 			break;
    954 #endif
    955 		}
    956 	}
    957 
    958 	return 0;
    959 }
    960 
    961 static const struct afd *
    962 find_afd(af)
    963 	int af;
    964 {
    965 	const struct afd *afd;
    966 
    967 	if (af == PF_UNSPEC)
    968 		return NULL;
    969 	for (afd = afdl; afd->a_af; afd++) {
    970 		if (afd->a_af == af)
    971 			return afd;
    972 	}
    973 	return NULL;
    974 }
    975 
    976 /*
    977  * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
    978  * will take care of it.
    979  * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
    980  * if the code is right or not.
    981  */
    982 static int
    983 addrconfig(pai)
    984 	const struct addrinfo *pai;
    985 {
    986 	int s;
    987 
    988 	/* XXX errno */
    989 	s = socket(pai->ai_family, SOCK_DGRAM, 0);
    990 	if (s < 0)
    991 		return 0;
    992 	close(s);
    993 	return 1;
    994 }
    995 
    996 #ifdef INET6
    997 /* convert a string to a scope identifier. XXX: IPv6 specific */
    998 static int
    999 ip6_str2scopeid(scope, sin6)
   1000 	char *scope;
   1001 	struct sockaddr_in6 *sin6;
   1002 {
   1003 	int scopeid;
   1004 	struct in6_addr *a6 = &sin6->sin6_addr;
   1005 	char *ep;
   1006 
   1007 	if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
   1008 		/*
   1009 		 * We currently assume a one-to-one mapping between links
   1010 		 * and interfaces, so we simply use interface indices for
   1011 		 * like-local scopes.
   1012 		 */
   1013 		scopeid = if_nametoindex(scope);
   1014 		if (scopeid == 0)
   1015 			goto trynumeric;
   1016 		return(scopeid);
   1017 	}
   1018 
   1019 	/* still unclear about literal, allow numeric only - placeholder */
   1020 	if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
   1021 		goto trynumeric;
   1022 	if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
   1023 		goto trynumeric;
   1024 	else
   1025 		goto trynumeric;	/* global */
   1026 
   1027 	/* try to convert to a numeric id as a last resort */
   1028   trynumeric:
   1029 	scopeid = (int)strtoul(scope, &ep, 10);
   1030 	if (*ep == '\0')
   1031 		return scopeid;
   1032 	else
   1033 		return -1;
   1034 }
   1035 #endif
   1036