xref: /netbsd-src/external/bsd/libbind/dist/irs/getaddrinfo.c (revision b5677b36047b601b9addaaa494a58ceae82c2a6c)
1 /*	$NetBSD: getaddrinfo.c,v 1.1.1.1 2009/04/12 15:33:44 christos Exp $	*/
2 
3 /*	$KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $	*/
4 
5 /*
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*! \file
35  * Issues to be discussed:
36  *\li  Thread safe-ness must be checked.
37  *\li  Return values.  There are nonstandard return values defined and used
38  *   in the source code.  This is because RFC2553 is silent about which error
39  *   code must be returned for which situation.
40  *\li  IPv4 classful (shortened) form.  RFC2553 is silent about it.  XNET 5.2
41  *   says to use inet_aton() to convert IPv4 numeric to binary (allows
42  *   classful form as a result).
43  *   current code - disallow classful form for IPv4 (due to use of inet_pton).
44  *\li  freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
45  *   invalid.
46  *   current code - SEGV on freeaddrinfo(NULL)
47  * Note:
48  *\li  We use getipnodebyname() just for thread-safeness.  There's no intent
49  *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
50  *   getipnodebyname().
51  *\li  The code filters out AFs that are not supported by the kernel,
52  *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
53  *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
54  *   in ai_flags?
55  *\li  (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
56  *   (1) what should we do against numeric hostname (2) what should we do
57  *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
58  *   non-loopback address configured?  global address configured?
59  * \par Additional Issue:
60  *  To avoid search order issue, we have a big amount of code duplicate
61  *   from gethnamaddr.c and some other places.  The issues that there's no
62  *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
63  *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
64  *   follows:
65  *	\li The code makes use of following calls when asked to resolver with
66  *	  ai_family  = PF_UNSPEC:
67  *\code		getipnodebyname(host, AF_INET6);
68  *		getipnodebyname(host, AF_INET);
69  *\endcode
70  *	\li  This will result in the following queries if the node is configure to
71  *	  prefer /etc/hosts than DNS:
72  *\code
73  *		lookup /etc/hosts for IPv6 address
74  *		lookup DNS for IPv6 address
75  *		lookup /etc/hosts for IPv4 address
76  *		lookup DNS for IPv4 address
77  *\endcode
78  *	  which may not meet people's requirement.
79  *	 \li The right thing to happen is to have underlying layer which does
80  *	  PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
81  *	  This would result in a bit of code duplicate with _dns_ghbyname() and
82  *	  friends.
83  */
84 
85 #include "port_before.h"
86 
87 #include <sys/types.h>
88 #include <sys/param.h>
89 #include <sys/socket.h>
90 
91 #include <net/if.h>
92 #include <netinet/in.h>
93 
94 #include <arpa/inet.h>
95 #include <arpa/nameser.h>
96 
97 #include <netdb.h>
98 #include <resolv.h>
99 #include <string.h>
100 #include <stdlib.h>
101 #include <stddef.h>
102 #include <ctype.h>
103 #include <unistd.h>
104 #include <stdio.h>
105 #include <errno.h>
106 
107 #include <stdarg.h>
108 
109 #include <irs.h>
110 #include <isc/assertions.h>
111 
112 #include "port_after.h"
113 
114 #include "irs_data.h"
115 
116 #define SUCCESS 0
117 #define ANY 0
118 #define YES 1
119 #define NO  0
120 
121 static const char in_addrany[] = { 0, 0, 0, 0 };
122 static const char in6_addrany[] = {
123 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
124 };
125 static const char in_loopback[] = { 127, 0, 0, 1 };
126 static const char in6_loopback[] = {
127 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
128 };
129 
130 static const struct afd {
131 	int a_af;
132 	int a_addrlen;
133 	int a_socklen;
134 	int a_off;
135 	const char *a_addrany;
136 	const char *a_loopback;
137 	int a_scoped;
138 } afdl [] = {
139 	{PF_INET6, sizeof(struct in6_addr),
140 	 sizeof(struct sockaddr_in6),
141 	 offsetof(struct sockaddr_in6, sin6_addr),
142 	 in6_addrany, in6_loopback, 1},
143 	{PF_INET, sizeof(struct in_addr),
144 	 sizeof(struct sockaddr_in),
145 	 offsetof(struct sockaddr_in, sin_addr),
146 	 in_addrany, in_loopback, 0},
147 	{0, 0, 0, 0, NULL, NULL, 0},
148 };
149 
150 struct explore {
151 	int e_af;
152 	int e_socktype;
153 	int e_protocol;
154 	const char *e_protostr;
155 	int e_wild;
156 #define WILD_AF(ex)		((ex)->e_wild & 0x01)
157 #define WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
158 #define WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
159 };
160 
161 static const struct explore explore[] = {
162 #if 0
163 	{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
164 #endif
165 	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
166 	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
167 	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
168 	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
169 	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
170 	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
171 	{ -1, 0, 0, NULL, 0 },
172 };
173 
174 #define PTON_MAX	16
175 
176 static int str_isnumber __P((const char *));
177 static int explore_fqdn __P((const struct addrinfo *, const char *,
178 	const char *, struct addrinfo **));
179 static int explore_copy __P((const struct addrinfo *, const struct addrinfo *,
180 	struct addrinfo **));
181 static int explore_null __P((const struct addrinfo *,
182 	const char *, struct addrinfo **));
183 static int explore_numeric __P((const struct addrinfo *, const char *,
184 	const char *, struct addrinfo **));
185 static int explore_numeric_scope __P((const struct addrinfo *, const char *,
186 	const char *, struct addrinfo **));
187 static int get_canonname __P((const struct addrinfo *,
188 	struct addrinfo *, const char *));
189 static struct addrinfo *get_ai __P((const struct addrinfo *,
190 	const struct afd *, const char *));
191 static struct addrinfo *copy_ai __P((const struct addrinfo *));
192 static int get_portmatch __P((const struct addrinfo *, const char *));
193 static int get_port __P((const struct addrinfo *, const char *, int));
194 static const struct afd *find_afd __P((int));
195 static int addrconfig __P((int));
196 static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *,
197 				u_int32_t *scopeidp));
198 static struct net_data *init __P((void));
199 
200 struct addrinfo *hostent2addrinfo __P((struct hostent *,
201 				       const struct addrinfo *));
202 struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
203 				    const char *));
204 
205 #if 0
206 static const char *ai_errlist[] = {
207 	"Success",
208 	"Address family for hostname not supported",	/*%< EAI_ADDRFAMILY */
209 	"Temporary failure in name resolution",		/*%< EAI_AGAIN */
210 	"Invalid value for ai_flags",		       	/*%< EAI_BADFLAGS */
211 	"Non-recoverable failure in name resolution", 	/*%< EAI_FAIL */
212 	"ai_family not supported",			/*%< EAI_FAMILY */
213 	"Memory allocation failure", 			/*%< EAI_MEMORY */
214 	"No address associated with hostname", 		/*%< EAI_NODATA */
215 	"hostname nor servname provided, or not known",	/*%< EAI_NONAME */
216 	"servname not supported for ai_socktype",	/*%< EAI_SERVICE */
217 	"ai_socktype not supported", 			/*%< EAI_SOCKTYPE */
218 	"System error returned in errno", 		/*%< EAI_SYSTEM */
219 	"Invalid value for hints",			/*%< EAI_BADHINTS */
220 	"Resolved protocol is unknown",			/*%< EAI_PROTOCOL */
221 	"Unknown error", 				/*%< EAI_MAX */
222 };
223 #endif
224 
225 /* XXX macros that make external reference is BAD. */
226 
227 #define GET_AI(ai, afd, addr) \
228 do { \
229 	/* external reference: pai, error, and label free */ \
230 	(ai) = get_ai(pai, (afd), (addr)); \
231 	if ((ai) == NULL) { \
232 		error = EAI_MEMORY; \
233 		goto free; \
234 	} \
235 } while (/*CONSTCOND*/0)
236 
237 #define GET_PORT(ai, serv) \
238 do { \
239 	/* external reference: error and label free */ \
240 	error = get_port((ai), (serv), 0); \
241 	if (error != 0) \
242 		goto free; \
243 } while (/*CONSTCOND*/0)
244 
245 #define GET_CANONNAME(ai, str) \
246 do { \
247 	/* external reference: pai, error and label free */ \
248 	error = get_canonname(pai, (ai), (str)); \
249 	if (error != 0) \
250 		goto free; \
251 } while (/*CONSTCOND*/0)
252 
253 #ifndef SOLARIS2
254 #define SETERROR(err) \
255 do { \
256 	/* external reference: error, and label bad */ \
257 	error = (err); \
258 	goto bad; \
259 	/*NOTREACHED*/ \
260 } while (/*CONSTCOND*/0)
261 #else
262 #define SETERROR(err) \
263 do { \
264 	/* external reference: error, and label bad */ \
265 	error = (err); \
266 	if (error == error) \
267 		goto bad; \
268 } while (/*CONSTCOND*/0)
269 #endif
270 
271 
272 #define MATCH_FAMILY(x, y, w) \
273 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
274 #define MATCH(x, y, w) \
275 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
276 
277 #if 0				/*%< bind8 has its own version */
278 char *
279 gai_strerror(ecode)
280 	int ecode;
281 {
282 	if (ecode < 0 || ecode > EAI_MAX)
283 		ecode = EAI_MAX;
284 	return ai_errlist[ecode];
285 }
286 #endif
287 
288 void
freeaddrinfo(ai)289 freeaddrinfo(ai)
290 	struct addrinfo *ai;
291 {
292 	struct addrinfo *next;
293 
294 	do {
295 		next = ai->ai_next;
296 		if (ai->ai_canonname)
297 			free(ai->ai_canonname);
298 		/* no need to free(ai->ai_addr) */
299 		free(ai);
300 		ai = next;
301 	} while (ai);
302 }
303 
304 static int
str_isnumber(p)305 str_isnumber(p)
306 	const char *p;
307 {
308 	char *ep;
309 
310 	if (*p == '\0')
311 		return NO;
312 	ep = NULL;
313 	errno = 0;
314 	(void)strtoul(p, &ep, 10);
315 	if (errno == 0 && ep && *ep == '\0')
316 		return YES;
317 	else
318 		return NO;
319 }
320 
321 int
getaddrinfo(hostname,servname,hints,res)322 getaddrinfo(hostname, servname, hints, res)
323 	const char *hostname, *servname;
324 	const struct addrinfo *hints;
325 	struct addrinfo **res;
326 {
327 	struct addrinfo sentinel;
328 	struct addrinfo *cur;
329 	int error = 0;
330 	struct addrinfo ai, ai0, *afai = NULL;
331 	struct addrinfo *pai;
332 	const struct explore *ex;
333 
334 	memset(&sentinel, 0, sizeof(sentinel));
335 	cur = &sentinel;
336 	pai = &ai;
337 	pai->ai_flags = 0;
338 	pai->ai_family = PF_UNSPEC;
339 	pai->ai_socktype = ANY;
340 	pai->ai_protocol = ANY;
341 #if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
342 	/*
343 	 * clear _ai_pad to preserve binary
344 	 * compatibility with previously compiled 64-bit
345 	 * applications in a pre-SUSv3 environment by
346 	 * guaranteeing the upper 32-bits are empty.
347 	 */
348 	pai->_ai_pad = 0;
349 #endif
350 	pai->ai_addrlen = 0;
351 	pai->ai_canonname = NULL;
352 	pai->ai_addr = NULL;
353 	pai->ai_next = NULL;
354 
355 	if (hostname == NULL && servname == NULL)
356 		return EAI_NONAME;
357 	if (hints) {
358 		/* error check for hints */
359 		if (hints->ai_addrlen || hints->ai_canonname ||
360 		    hints->ai_addr || hints->ai_next)
361 			SETERROR(EAI_BADHINTS); /*%< xxx */
362 		if (hints->ai_flags & ~AI_MASK)
363 			SETERROR(EAI_BADFLAGS);
364 		switch (hints->ai_family) {
365 		case PF_UNSPEC:
366 		case PF_INET:
367 		case PF_INET6:
368 			break;
369 		default:
370 			SETERROR(EAI_FAMILY);
371 		}
372 		memcpy(pai, hints, sizeof(*pai));
373 
374 #if defined(sun) && defined(_SOCKLEN_T) && defined(__sparcv9)
375 		/*
376 		 * We need to clear _ai_pad to preserve binary
377 		 * compatibility.  See prior comment.
378 		 */
379 		pai->_ai_pad = 0;
380 #endif
381 		/*
382 		 * if both socktype/protocol are specified, check if they
383 		 * are meaningful combination.
384 		 */
385 		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
386 			for (ex = explore; ex->e_af >= 0; ex++) {
387 				if (pai->ai_family != ex->e_af)
388 					continue;
389 				if (ex->e_socktype == ANY)
390 					continue;
391 				if (ex->e_protocol == ANY)
392 					continue;
393 				if (pai->ai_socktype == ex->e_socktype &&
394 				    pai->ai_protocol != ex->e_protocol) {
395 					SETERROR(EAI_BADHINTS);
396 				}
397 			}
398 		}
399 	}
400 
401 	/*
402 	 * post-2553: AI_ALL and AI_V4MAPPED are effective only against
403 	 * AF_INET6 query.  They needs to be ignored if specified in other
404 	 * occassions.
405 	 */
406 	switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
407 	case AI_V4MAPPED:
408 	case AI_ALL | AI_V4MAPPED:
409 		if (pai->ai_family != AF_INET6)
410 			pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
411 		break;
412 	case AI_ALL:
413 #if 1
414 		/* illegal */
415 		SETERROR(EAI_BADFLAGS);
416 #else
417 		pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
418 		break;
419 #endif
420 	}
421 
422 	/*
423 	 * check for special cases.  (1) numeric servname is disallowed if
424 	 * socktype/protocol are left unspecified. (2) servname is disallowed
425 	 * for raw and other inet{,6} sockets.
426 	 */
427 	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
428 #ifdef PF_INET6
429 	 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
430 #endif
431 	    ) {
432 		ai0 = *pai;	/* backup *pai */
433 
434 		if (pai->ai_family == PF_UNSPEC) {
435 #ifdef PF_INET6
436 			pai->ai_family = PF_INET6;
437 #else
438 			pai->ai_family = PF_INET;
439 #endif
440 		}
441 		error = get_portmatch(pai, servname);
442 		if (error)
443 			SETERROR(error);
444 
445 		*pai = ai0;
446 	}
447 
448 	ai0 = *pai;
449 
450 	/* NULL hostname, or numeric hostname */
451 	for (ex = explore; ex->e_af >= 0; ex++) {
452 		*pai = ai0;
453 
454 		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
455 			continue;
456 		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
457 			continue;
458 		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
459 			continue;
460 
461 		if (pai->ai_family == PF_UNSPEC)
462 			pai->ai_family = ex->e_af;
463 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
464 			pai->ai_socktype = ex->e_socktype;
465 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
466 			pai->ai_protocol = ex->e_protocol;
467 
468 		/*
469 		 * if the servname does not match socktype/protocol, ignore it.
470 		 */
471 		if (get_portmatch(pai, servname) != 0)
472 			continue;
473 
474 		if (hostname == NULL) {
475 			/*
476 			 * filter out AFs that are not supported by the kernel
477 			 * XXX errno?
478 			 */
479 			if (!addrconfig(pai->ai_family))
480 				continue;
481 			error = explore_null(pai, servname, &cur->ai_next);
482 		} else
483 			error = explore_numeric_scope(pai, hostname, servname,
484 			    &cur->ai_next);
485 
486 		if (error)
487 			goto free;
488 
489 		while (cur && cur->ai_next)
490 			cur = cur->ai_next;
491 	}
492 
493 	/*
494 	 * XXX
495 	 * If numreic representation of AF1 can be interpreted as FQDN
496 	 * representation of AF2, we need to think again about the code below.
497 	 */
498 	if (sentinel.ai_next)
499 		goto good;
500 
501 	if (pai->ai_flags & AI_NUMERICHOST)
502 		SETERROR(EAI_NONAME);
503 	if (hostname == NULL)
504 		SETERROR(EAI_NONAME);
505 
506 	/*
507 	 * hostname as alphabetical name.
508 	 * We'll make sure that
509 	 * - if returning addrinfo list is empty, return non-zero error
510 	 *   value (already known one or EAI_NONAME).
511 	 * - otherwise,
512 	 *   + if we haven't had any errors, return 0 (i.e. success).
513 	 *   + if we've had an error, free the list and return the error.
514 	 * without any assumption on the behavior of explore_fqdn().
515 	 */
516 
517 	/* first, try to query DNS for all possible address families. */
518 	*pai = ai0;
519 	error = explore_fqdn(pai, hostname, servname, &afai);
520 	if (error) {
521 		if (afai != NULL)
522 			freeaddrinfo(afai);
523 		goto free;
524 	}
525 	if (afai == NULL) {
526 		error = EAI_NONAME; /*%< we've had no errors. */
527 		goto free;
528 	}
529 
530 	/*
531 	 * we would like to prefer AF_INET6 than AF_INET, so we'll make an
532 	 * outer loop by AFs.
533 	 */
534 	for (ex = explore; ex->e_af >= 0; ex++) {
535 		*pai = ai0;
536 
537 		if (pai->ai_family == PF_UNSPEC)
538 			pai->ai_family = ex->e_af;
539 
540 		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
541 			continue;
542 		if (!MATCH(pai->ai_socktype, ex->e_socktype,
543 			   WILD_SOCKTYPE(ex))) {
544 			continue;
545 		}
546 		if (!MATCH(pai->ai_protocol, ex->e_protocol,
547 			   WILD_PROTOCOL(ex))) {
548 			continue;
549 		}
550 
551 #ifdef AI_ADDRCONFIG
552 		/*
553 		 * If AI_ADDRCONFIG is specified, check if we are
554 		 * expected to return the address family or not.
555 		 */
556 		if ((pai->ai_flags & AI_ADDRCONFIG) != 0 &&
557 		    !addrconfig(pai->ai_family))
558 			continue;
559 #endif
560 
561 		if (pai->ai_family == PF_UNSPEC)
562 			pai->ai_family = ex->e_af;
563 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
564 			pai->ai_socktype = ex->e_socktype;
565 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
566 			pai->ai_protocol = ex->e_protocol;
567 
568 		/*
569 		 * if the servname does not match socktype/protocol, ignore it.
570 		 */
571 		if (get_portmatch(pai, servname) != 0)
572 			continue;
573 
574 		if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) {
575 			freeaddrinfo(afai);
576 			goto free;
577 		}
578 
579 		while (cur && cur->ai_next)
580 			cur = cur->ai_next;
581 	}
582 
583 	freeaddrinfo(afai);	/*%< afai must not be NULL at this point. */
584 
585 	if (sentinel.ai_next) {
586 good:
587 		*res = sentinel.ai_next;
588 		return(SUCCESS);
589 	} else {
590 		/*
591 		 * All the process succeeded, but we've had an empty list.
592 		 * This can happen if the given hints do not match our
593 		 * candidates.
594 		 */
595 		error = EAI_NONAME;
596 	}
597 
598 free:
599 bad:
600 	if (sentinel.ai_next)
601 		freeaddrinfo(sentinel.ai_next);
602 	*res = NULL;
603 	return(error);
604 }
605 
606 /*%
607  * FQDN hostname, DNS lookup
608  */
609 static int
explore_fqdn(pai,hostname,servname,res)610 explore_fqdn(pai, hostname, servname, res)
611 	const struct addrinfo *pai;
612 	const char *hostname;
613 	const char *servname;
614 	struct addrinfo **res;
615 {
616 	struct addrinfo *result;
617 	struct addrinfo *cur;
618 	struct net_data *net_data = init();
619 	struct irs_ho *ho;
620 	int error = 0;
621 	char tmp[NS_MAXDNAME];
622 	const char *cp;
623 
624 	INSIST(res != NULL && *res == NULL);
625 
626 	/*
627 	 * if the servname does not match socktype/protocol, ignore it.
628 	 */
629 	if (get_portmatch(pai, servname) != 0)
630 		return(0);
631 
632 	if (!net_data || !(ho = net_data->ho))
633 		return(0);
634 #if 0				/*%< XXX (notyet) */
635 	if (net_data->ho_stayopen && net_data->ho_last &&
636 	    net_data->ho_last->h_addrtype == af) {
637 		if (ns_samename(name, net_data->ho_last->h_name) == 1)
638 			return (net_data->ho_last);
639 		for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
640 			if (ns_samename(name, *hap) == 1)
641 				return (net_data->ho_last);
642 	}
643 #endif
644 	if (!strchr(hostname, '.') &&
645 	    (cp = res_hostalias(net_data->res, hostname,
646 				tmp, sizeof(tmp))))
647 		hostname = cp;
648 	result = (*ho->addrinfo)(ho, hostname, pai);
649 	if (!net_data->ho_stayopen) {
650 		(*ho->minimize)(ho);
651 	}
652 	if (result == NULL) {
653 		int e = h_errno;
654 
655 		switch(e) {
656 		case NETDB_INTERNAL:
657 			error = EAI_SYSTEM;
658 			break;
659 		case TRY_AGAIN:
660 			error = EAI_AGAIN;
661 			break;
662 		case NO_RECOVERY:
663 			error = EAI_FAIL;
664 			break;
665 		case HOST_NOT_FOUND:
666 		case NO_DATA:
667 			error = EAI_NONAME;
668 			break;
669 		default:
670 		case NETDB_SUCCESS: /*%< should be impossible... */
671 			error = EAI_NONAME;
672 			break;
673 		}
674 		goto free;
675 	}
676 
677 	for (cur = result; cur; cur = cur->ai_next) {
678 		GET_PORT(cur, servname); /*%< XXX: redundant lookups... */
679 		/* canonname should already be filled. */
680 	}
681 
682 	*res = result;
683 
684 	return(0);
685 
686 free:
687 	if (result)
688 		freeaddrinfo(result);
689 	return error;
690 }
691 
692 static int
explore_copy(pai,src0,res)693 explore_copy(pai, src0, res)
694 	const struct addrinfo *pai;	/*%< seed */
695 	const struct addrinfo *src0;	/*%< source */
696 	struct addrinfo **res;
697 {
698 	int error;
699 	struct addrinfo sentinel, *cur;
700 	const struct addrinfo *src;
701 
702 	error = 0;
703 	sentinel.ai_next = NULL;
704 	cur = &sentinel;
705 
706 	for (src = src0; src != NULL; src = src->ai_next) {
707 		if (src->ai_family != pai->ai_family)
708 			continue;
709 
710 		cur->ai_next = copy_ai(src);
711 		if (!cur->ai_next) {
712 			error = EAI_MEMORY;
713 			goto fail;
714 		}
715 
716 		cur->ai_next->ai_socktype = pai->ai_socktype;
717 		cur->ai_next->ai_protocol = pai->ai_protocol;
718 		cur = cur->ai_next;
719 	}
720 
721 	*res = sentinel.ai_next;
722 	return 0;
723 
724 fail:
725 	freeaddrinfo(sentinel.ai_next);
726 	return error;
727 }
728 
729 /*%
730  * hostname == NULL.
731  * passive socket -> anyaddr (0.0.0.0 or ::)
732  * non-passive socket -> localhost (127.0.0.1 or ::1)
733  */
734 static int
explore_null(pai,servname,res)735 explore_null(pai, servname, res)
736 	const struct addrinfo *pai;
737 	const char *servname;
738 	struct addrinfo **res;
739 {
740 	const struct afd *afd;
741 	struct addrinfo *cur;
742 	struct addrinfo sentinel;
743 	int error;
744 
745 	*res = NULL;
746 	sentinel.ai_next = NULL;
747 	cur = &sentinel;
748 
749 	afd = find_afd(pai->ai_family);
750 	if (afd == NULL)
751 		return 0;
752 
753 	if (pai->ai_flags & AI_PASSIVE) {
754 		GET_AI(cur->ai_next, afd, afd->a_addrany);
755 		/* xxx meaningless?
756 		 * GET_CANONNAME(cur->ai_next, "anyaddr");
757 		 */
758 		GET_PORT(cur->ai_next, servname);
759 	} else {
760 		GET_AI(cur->ai_next, afd, afd->a_loopback);
761 		/* xxx meaningless?
762 		 * GET_CANONNAME(cur->ai_next, "localhost");
763 		 */
764 		GET_PORT(cur->ai_next, servname);
765 	}
766 	cur = cur->ai_next;
767 
768 	*res = sentinel.ai_next;
769 	return 0;
770 
771 free:
772 	if (sentinel.ai_next)
773 		freeaddrinfo(sentinel.ai_next);
774 	return error;
775 }
776 
777 /*%
778  * numeric hostname
779  */
780 static int
explore_numeric(pai,hostname,servname,res)781 explore_numeric(pai, hostname, servname, res)
782 	const struct addrinfo *pai;
783 	const char *hostname;
784 	const char *servname;
785 	struct addrinfo **res;
786 {
787 	const struct afd *afd;
788 	struct addrinfo *cur;
789 	struct addrinfo sentinel;
790 	int error;
791 	char pton[PTON_MAX];
792 
793 	*res = NULL;
794 	sentinel.ai_next = NULL;
795 	cur = &sentinel;
796 
797 	afd = find_afd(pai->ai_family);
798 	if (afd == NULL)
799 		return 0;
800 
801 	switch (afd->a_af) {
802 #if 0 /*X/Open spec*/
803 	case AF_INET:
804 		if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
805 			if (pai->ai_family == afd->a_af ||
806 			    pai->ai_family == PF_UNSPEC /*?*/) {
807 				GET_AI(cur->ai_next, afd, pton);
808 				GET_PORT(cur->ai_next, servname);
809 				while (cur->ai_next)
810 					cur = cur->ai_next;
811 			} else
812 				SETERROR(EAI_FAMILY);	/*xxx*/
813 		}
814 		break;
815 #endif
816 	default:
817 		if (inet_pton(afd->a_af, hostname, pton) == 1) {
818 			if (pai->ai_family == afd->a_af ||
819 			    pai->ai_family == PF_UNSPEC /*?*/) {
820 				GET_AI(cur->ai_next, afd, pton);
821 				GET_PORT(cur->ai_next, servname);
822 				while (cur->ai_next)
823 					cur = cur->ai_next;
824 			} else
825 				SETERROR(EAI_FAMILY);	/*xxx*/
826 		}
827 		break;
828 	}
829 
830 	*res = sentinel.ai_next;
831 	return 0;
832 
833 free:
834 bad:
835 	if (sentinel.ai_next)
836 		freeaddrinfo(sentinel.ai_next);
837 	return error;
838 }
839 
840 /*%
841  * numeric hostname with scope
842  */
843 static int
explore_numeric_scope(pai,hostname,servname,res)844 explore_numeric_scope(pai, hostname, servname, res)
845 	const struct addrinfo *pai;
846 	const char *hostname;
847 	const char *servname;
848 	struct addrinfo **res;
849 {
850 #ifndef SCOPE_DELIMITER
851 	return explore_numeric(pai, hostname, servname, res);
852 #else
853 	const struct afd *afd;
854 	struct addrinfo *cur;
855 	int error;
856 	char *cp, *hostname2 = NULL, *scope, *addr;
857 	struct sockaddr_in6 *sin6;
858 
859 	afd = find_afd(pai->ai_family);
860 	if (afd == NULL)
861 		return 0;
862 
863 	if (!afd->a_scoped)
864 		return explore_numeric(pai, hostname, servname, res);
865 
866 	cp = strchr(hostname, SCOPE_DELIMITER);
867 	if (cp == NULL)
868 		return explore_numeric(pai, hostname, servname, res);
869 
870 	/*
871 	 * Handle special case of <scoped_address><delimiter><scope id>
872 	 */
873 	hostname2 = strdup(hostname);
874 	if (hostname2 == NULL)
875 		return EAI_MEMORY;
876 	/* terminate at the delimiter */
877 	hostname2[cp - hostname] = '\0';
878 	addr = hostname2;
879 	scope = cp + 1;
880 
881 	error = explore_numeric(pai, addr, servname, res);
882 	if (error == 0) {
883 		u_int32_t scopeid = 0;
884 
885 		for (cur = *res; cur; cur = cur->ai_next) {
886 			if (cur->ai_family != AF_INET6)
887 				continue;
888 			sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
889 			if (!ip6_str2scopeid(scope, sin6, &scopeid)) {
890 				free(hostname2);
891 				return(EAI_NONAME); /*%< XXX: is return OK? */
892 			}
893 #ifdef HAVE_SIN6_SCOPE_ID
894 			sin6->sin6_scope_id = scopeid;
895 #endif
896 		}
897 	}
898 
899 	free(hostname2);
900 
901 	return error;
902 #endif
903 }
904 
905 static int
get_canonname(pai,ai,str)906 get_canonname(pai, ai, str)
907 	const struct addrinfo *pai;
908 	struct addrinfo *ai;
909 	const char *str;
910 {
911 	if ((pai->ai_flags & AI_CANONNAME) != 0) {
912 		ai->ai_canonname = (char *)malloc(strlen(str) + 1);
913 		if (ai->ai_canonname == NULL)
914 			return EAI_MEMORY;
915 		strcpy(ai->ai_canonname, str);
916 	}
917 	return 0;
918 }
919 
920 static struct addrinfo *
get_ai(pai,afd,addr)921 get_ai(pai, afd, addr)
922 	const struct addrinfo *pai;
923 	const struct afd *afd;
924 	const char *addr;
925 {
926 	char *p;
927 	struct addrinfo *ai;
928 
929 	ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
930 		+ (afd->a_socklen));
931 	if (ai == NULL)
932 		return NULL;
933 
934 	memcpy(ai, pai, sizeof(struct addrinfo));
935 	ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
936 	memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
937 #ifdef HAVE_SA_LEN
938 	ai->ai_addr->sa_len = afd->a_socklen;
939 #endif
940 	ai->ai_addrlen = afd->a_socklen;
941 	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
942 	p = (char *)(void *)(ai->ai_addr);
943 	memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
944 	return ai;
945 }
946 
947 /* XXX need to malloc() the same way we do from other functions! */
948 static struct addrinfo *
copy_ai(pai)949 copy_ai(pai)
950 	const struct addrinfo *pai;
951 {
952 	struct addrinfo *ai;
953 	size_t l;
954 
955 	l = sizeof(*ai) + pai->ai_addrlen;
956 	if ((ai = (struct addrinfo *)malloc(l)) == NULL)
957 		return NULL;
958 	memset(ai, 0, l);
959 	memcpy(ai, pai, sizeof(*ai));
960 	ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
961 	memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
962 
963 	if (pai->ai_canonname) {
964 		l = strlen(pai->ai_canonname) + 1;
965 		if ((ai->ai_canonname = malloc(l)) == NULL) {
966 			free(ai);
967 			return NULL;
968 		}
969 		strcpy(ai->ai_canonname, pai->ai_canonname);	/* (checked) */
970 	} else {
971 		/* just to make sure */
972 		ai->ai_canonname = NULL;
973 	}
974 
975 	ai->ai_next = NULL;
976 
977 	return ai;
978 }
979 
980 static int
get_portmatch(const struct addrinfo * ai,const char * servname)981 get_portmatch(const struct addrinfo *ai, const char *servname) {
982 
983 	/* get_port does not touch first argument. when matchonly == 1. */
984 	/* LINTED const cast */
985 	return get_port((const struct addrinfo *)ai, servname, 1);
986 }
987 
988 static int
get_port(const struct addrinfo * ai,const char * servname,int matchonly)989 get_port(const struct addrinfo *ai, const char *servname, int matchonly) {
990 	const char *proto;
991 	struct servent *sp;
992 	int port;
993 	int allownumeric;
994 
995 	if (servname == NULL)
996 		return 0;
997 	switch (ai->ai_family) {
998 	case AF_INET:
999 #ifdef AF_INET6
1000 	case AF_INET6:
1001 #endif
1002 		break;
1003 	default:
1004 		return 0;
1005 	}
1006 
1007 	switch (ai->ai_socktype) {
1008 	case SOCK_RAW:
1009 		return EAI_SERVICE;
1010 	case SOCK_DGRAM:
1011 	case SOCK_STREAM:
1012 		allownumeric = 1;
1013 		break;
1014 	case ANY:
1015 		switch (ai->ai_family) {
1016 		case AF_INET:
1017 #ifdef AF_INET6
1018 		case AF_INET6:
1019 #endif
1020 			allownumeric = 1;
1021 			break;
1022 		default:
1023 			allownumeric = 0;
1024 			break;
1025 		}
1026 		break;
1027 	default:
1028 		return EAI_SOCKTYPE;
1029 	}
1030 
1031 	if (str_isnumber(servname)) {
1032 		if (!allownumeric)
1033 			return EAI_SERVICE;
1034 		port = atoi(servname);
1035 		if (port < 0 || port > 65535)
1036 			return EAI_SERVICE;
1037 		port = htons(port);
1038 	} else {
1039 		switch (ai->ai_socktype) {
1040 		case SOCK_DGRAM:
1041 			proto = "udp";
1042 			break;
1043 		case SOCK_STREAM:
1044 			proto = "tcp";
1045 			break;
1046 		default:
1047 			proto = NULL;
1048 			break;
1049 		}
1050 
1051 		if ((sp = getservbyname(servname, proto)) == NULL)
1052 			return EAI_SERVICE;
1053 		port = sp->s_port;
1054 	}
1055 
1056 	if (!matchonly) {
1057 		switch (ai->ai_family) {
1058 		case AF_INET:
1059 			((struct sockaddr_in *)(void *)
1060 			    ai->ai_addr)->sin_port = port;
1061 			break;
1062 		case AF_INET6:
1063 			((struct sockaddr_in6 *)(void *)
1064 			    ai->ai_addr)->sin6_port = port;
1065 			break;
1066 		}
1067 	}
1068 
1069 	return 0;
1070 }
1071 
1072 static const struct afd *
find_afd(af)1073 find_afd(af)
1074 	int af;
1075 {
1076 	const struct afd *afd;
1077 
1078 	if (af == PF_UNSPEC)
1079 		return NULL;
1080 	for (afd = afdl; afd->a_af; afd++) {
1081 		if (afd->a_af == af)
1082 			return afd;
1083 	}
1084 	return NULL;
1085 }
1086 
1087 /*%
1088  * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
1089  * will take care of it.
1090  * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
1091  * if the code is right or not.
1092  */
1093 static int
addrconfig(af)1094 addrconfig(af)
1095 	int af;
1096 {
1097 	int s;
1098 
1099 	/* XXX errno */
1100 	s = socket(af, SOCK_DGRAM, 0);
1101 	if (s < 0) {
1102 		if (errno != EMFILE)
1103 			return 0;
1104 	} else
1105 		close(s);
1106 	return 1;
1107 }
1108 
1109 /* convert a string to a scope identifier. XXX: IPv6 specific */
1110 static int
ip6_str2scopeid(char * scope,struct sockaddr_in6 * sin6,u_int32_t * scopeidp)1111 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6,
1112 		u_int32_t *scopeidp)
1113 {
1114 	u_int32_t scopeid;
1115 	u_long lscopeid;
1116 	struct in6_addr *a6 = &sin6->sin6_addr;
1117 	char *ep;
1118 
1119 	/* empty scopeid portion is invalid */
1120 	if (*scope == '\0')
1121 		return (0);
1122 
1123 #ifdef USE_IFNAMELINKID
1124 	if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
1125 	    IN6_IS_ADDR_MC_NODELOCAL(a6)) {
1126 		/*
1127 		 * Using interface names as link indices can be allowed
1128 		 * only when we can assume a one-to-one mappings between
1129 		 * links and interfaces.  See comments in getnameinfo.c.
1130 		 */
1131 		scopeid = if_nametoindex(scope);
1132 		if (scopeid == 0)
1133 			goto trynumeric;
1134 		*scopeidp = scopeid;
1135 		return (1);
1136 	}
1137 #endif
1138 
1139 	/* still unclear about literal, allow numeric only - placeholder */
1140 	if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1141 		goto trynumeric;
1142 	if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1143 		goto trynumeric;
1144 	else
1145 		goto trynumeric;	/*%< global */
1146 	/* try to convert to a numeric id as a last resort */
1147 trynumeric:
1148 	errno = 0;
1149 	lscopeid = strtoul(scope, &ep, 10);
1150 	scopeid = lscopeid & 0xffffffff;
1151 	if (errno == 0 && ep && *ep == '\0' && scopeid == lscopeid) {
1152 		*scopeidp = scopeid;
1153 		return (1);
1154 	} else
1155 		return (0);
1156 }
1157 
1158 struct addrinfo *
hostent2addrinfo(hp,pai)1159 hostent2addrinfo(hp, pai)
1160 	struct hostent *hp;
1161 	const struct addrinfo *pai;
1162 {
1163 	int i, af, error = 0;
1164 	char **aplist = NULL, *ap;
1165 	struct addrinfo sentinel, *cur;
1166 	const struct afd *afd;
1167 
1168 	af = hp->h_addrtype;
1169 	if (pai->ai_family != AF_UNSPEC && af != pai->ai_family)
1170 		return(NULL);
1171 
1172 	afd = find_afd(af);
1173 	if (afd == NULL)
1174 		return(NULL);
1175 
1176 	aplist = hp->h_addr_list;
1177 
1178 	memset(&sentinel, 0, sizeof(sentinel));
1179 	cur = &sentinel;
1180 
1181 	for (i = 0; (ap = aplist[i]) != NULL; i++) {
1182 #if 0				/*%< the trick seems too much */
1183 		af = hp->h_addr_list;
1184 		if (af == AF_INET6 &&
1185 		    IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
1186 			af = AF_INET;
1187 			ap = ap + sizeof(struct in6_addr)
1188 				- sizeof(struct in_addr);
1189 		}
1190 		afd = find_afd(af);
1191 		if (afd == NULL)
1192 			continue;
1193 #endif /* 0 */
1194 
1195 		GET_AI(cur->ai_next, afd, ap);
1196 
1197 		/* GET_PORT(cur->ai_next, servname); */
1198 		if ((pai->ai_flags & AI_CANONNAME) != 0) {
1199 			/*
1200 			 * RFC2553 says that ai_canonname will be set only for
1201 			 * the first element.  we do it for all the elements,
1202 			 * just for convenience.
1203 			 */
1204 			GET_CANONNAME(cur->ai_next, hp->h_name);
1205 		}
1206 		while (cur->ai_next) /*%< no need to loop, actually. */
1207 			cur = cur->ai_next;
1208 		continue;
1209 
1210 	free:
1211 		if (cur->ai_next)
1212 			freeaddrinfo(cur->ai_next);
1213 		cur->ai_next = NULL;
1214 		/* continue, without tht pointer CUR advanced. */
1215 	}
1216 
1217 	return(sentinel.ai_next);
1218 }
1219 
1220 struct addrinfo *
addr2addrinfo(pai,cp)1221 addr2addrinfo(pai, cp)
1222 	const struct addrinfo *pai;
1223 	const char *cp;
1224 {
1225 	const struct afd *afd;
1226 
1227 	afd = find_afd(pai->ai_family);
1228 	if (afd == NULL)
1229 		return(NULL);
1230 
1231 	return(get_ai(pai, afd, cp));
1232 }
1233 
1234 static struct net_data *
init()1235 init()
1236 {
1237 	struct net_data *net_data;
1238 
1239 	if (!(net_data = net_data_init(NULL)))
1240 		goto error;
1241 	if (!net_data->ho) {
1242 		net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
1243 		if (!net_data->ho || !net_data->res) {
1244 error:
1245 			errno = EIO;
1246 			if (net_data && net_data->res)
1247 				RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
1248 			return (NULL);
1249 		}
1250 
1251 		(*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
1252 	}
1253 
1254 	return (net_data);
1255 }
1256