xref: /freebsd/lib/libc/net/getaddrinfo.c (revision 33dee819339974eaf7dbf69068001771cbdcd548)
1bf838688SHajimu UMEMOTO /*	$KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $	*/
2b826397aSJun-ichiro itojun Hagino 
37d56d374SYoshinobu Inoue /*
47d56d374SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
57d56d374SYoshinobu Inoue  * All rights reserved.
67d56d374SYoshinobu Inoue  *
77d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
87d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
97d56d374SYoshinobu Inoue  * are met:
107d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
117d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
127d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
137d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
147d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
157d56d374SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
167d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
177d56d374SYoshinobu Inoue  *    without specific prior written permission.
187d56d374SYoshinobu Inoue  *
197d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
207d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
217d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
227d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
237d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
247d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
257d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
267d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
277d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
287d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
297d56d374SYoshinobu Inoue  * SUCH DAMAGE.
307d56d374SYoshinobu Inoue  */
317d56d374SYoshinobu Inoue 
327d56d374SYoshinobu Inoue /*
337d56d374SYoshinobu Inoue  * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
347d56d374SYoshinobu Inoue  *
357d56d374SYoshinobu Inoue  * Issues to be discussed:
367d56d374SYoshinobu Inoue  * - Thread safe-ness must be checked.
377d56d374SYoshinobu Inoue  * - Return values.  There are nonstandard return values defined and used
387d56d374SYoshinobu Inoue  *   in the source code.  This is because RFC2553 is silent about which error
397d56d374SYoshinobu Inoue  *   code must be returned for which situation.
40a42af91cSHajimu UMEMOTO  * - freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
41dd521ef1SHajimu UMEMOTO  *   invalid.  current code - SEGV on freeaddrinfo(NULL)
42dd521ef1SHajimu UMEMOTO  *
4300a8a579SYoshinobu Inoue  * Note:
4400a8a579SYoshinobu Inoue  * - The code filters out AFs that are not supported by the kernel,
4500a8a579SYoshinobu Inoue  *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
4600a8a579SYoshinobu Inoue  *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
4700a8a579SYoshinobu Inoue  *   in ai_flags?
48a42af91cSHajimu UMEMOTO  * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
49a42af91cSHajimu UMEMOTO  *   (1) what should we do against numeric hostname (2) what should we do
50a42af91cSHajimu UMEMOTO  *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
51a42af91cSHajimu UMEMOTO  *   non-loopback address configured?  global address configured?
52dd521ef1SHajimu UMEMOTO  *
53dd521ef1SHajimu UMEMOTO  * OS specific notes for netbsd/openbsd/freebsd4/bsdi4:
54a42af91cSHajimu UMEMOTO  * - To avoid search order issue, we have a big amount of code duplicate
55a42af91cSHajimu UMEMOTO  *   from gethnamaddr.c and some other places.  The issues that there's no
56a42af91cSHajimu UMEMOTO  *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
57a42af91cSHajimu UMEMOTO  *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
58dd521ef1SHajimu UMEMOTO  *   presented above.
59dd521ef1SHajimu UMEMOTO  *
60dd521ef1SHajimu UMEMOTO  * OS specific notes for freebsd4:
61dd521ef1SHajimu UMEMOTO  * - FreeBSD supported $GAI.  The code does not.
62dd521ef1SHajimu UMEMOTO  * - FreeBSD allowed classful IPv4 numeric (127.1), the code does not.
637d56d374SYoshinobu Inoue  */
647d56d374SYoshinobu Inoue 
65333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
66333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
67333fc21eSDavid E. O'Brien 
68d201fe46SDaniel Eischen #include "namespace.h"
697d56d374SYoshinobu Inoue #include <sys/types.h>
707d56d374SYoshinobu Inoue #include <sys/param.h>
717d56d374SYoshinobu Inoue #include <sys/socket.h>
727d56d374SYoshinobu Inoue #include <net/if.h>
737d56d374SYoshinobu Inoue #include <netinet/in.h>
744c6867a8SHajimu UMEMOTO #include <sys/queue.h>
754c6867a8SHajimu UMEMOTO #ifdef INET6
764c6867a8SHajimu UMEMOTO #include <net/if_var.h>
774c6867a8SHajimu UMEMOTO #include <sys/sysctl.h>
784c6867a8SHajimu UMEMOTO #include <netinet6/in6_var.h>	/* XXX */
794c6867a8SHajimu UMEMOTO #endif
807d56d374SYoshinobu Inoue #include <arpa/inet.h>
817d56d374SYoshinobu Inoue #include <arpa/nameser.h>
82bf838688SHajimu UMEMOTO #include <rpc/rpc.h>
83bf838688SHajimu UMEMOTO #include <rpcsvc/yp_prot.h>
84bf838688SHajimu UMEMOTO #include <rpcsvc/ypclnt.h>
857d56d374SYoshinobu Inoue #include <netdb.h>
86e8baaa70SDaniel Eischen #include <pthread.h>
877d56d374SYoshinobu Inoue #include <resolv.h>
887d56d374SYoshinobu Inoue #include <string.h>
897d56d374SYoshinobu Inoue #include <stdlib.h>
907d56d374SYoshinobu Inoue #include <stddef.h>
917d56d374SYoshinobu Inoue #include <ctype.h>
927d56d374SYoshinobu Inoue #include <unistd.h>
937d56d374SYoshinobu Inoue #include <stdio.h>
94a42af91cSHajimu UMEMOTO #include <errno.h>
9569b0a4b6SJim Pirzyk 
9669b0a4b6SJim Pirzyk #include "res_config.h"
9769b0a4b6SJim Pirzyk 
98ce6282dbSHajimu UMEMOTO #ifdef DEBUG
99ce6282dbSHajimu UMEMOTO #include <syslog.h>
100ce6282dbSHajimu UMEMOTO #endif
1017d56d374SYoshinobu Inoue 
102248aee62SJacques Vidrine #include <stdarg.h>
103248aee62SJacques Vidrine #include <nsswitch.h>
104d201fe46SDaniel Eischen #include "un-namespace.h"
1052bbd7cf8SJacques Vidrine #include "libc_private.h"
106248aee62SJacques Vidrine 
1077d56d374SYoshinobu Inoue #if defined(__KAME__) && defined(INET6)
1087d56d374SYoshinobu Inoue # define FAITH
1097d56d374SYoshinobu Inoue #endif
1107d56d374SYoshinobu Inoue 
1117d56d374SYoshinobu Inoue #define SUCCESS 0
1127d56d374SYoshinobu Inoue #define ANY 0
1137d56d374SYoshinobu Inoue #define YES 1
1147d56d374SYoshinobu Inoue #define NO  0
1157d56d374SYoshinobu Inoue 
1167d56d374SYoshinobu Inoue static const char in_addrany[] = { 0, 0, 0, 0 };
117dd521ef1SHajimu UMEMOTO static const char in_loopback[] = { 127, 0, 0, 1 };
118dd521ef1SHajimu UMEMOTO #ifdef INET6
1197d56d374SYoshinobu Inoue static const char in6_addrany[] = {
1207d56d374SYoshinobu Inoue 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1217d56d374SYoshinobu Inoue };
1227d56d374SYoshinobu Inoue static const char in6_loopback[] = {
1237d56d374SYoshinobu Inoue 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
1247d56d374SYoshinobu Inoue };
125dd521ef1SHajimu UMEMOTO #endif
1267d56d374SYoshinobu Inoue 
1274c6867a8SHajimu UMEMOTO struct policyqueue {
1284c6867a8SHajimu UMEMOTO 	TAILQ_ENTRY(policyqueue) pc_entry;
1294c6867a8SHajimu UMEMOTO #ifdef INET6
1304c6867a8SHajimu UMEMOTO 	struct in6_addrpolicy pc_policy;
1314c6867a8SHajimu UMEMOTO #endif
1324c6867a8SHajimu UMEMOTO };
1334c6867a8SHajimu UMEMOTO TAILQ_HEAD(policyhead, policyqueue);
1344c6867a8SHajimu UMEMOTO 
1357d56d374SYoshinobu Inoue static const struct afd {
1367d56d374SYoshinobu Inoue 	int a_af;
1377d56d374SYoshinobu Inoue 	int a_addrlen;
1387d56d374SYoshinobu Inoue 	int a_socklen;
1397d56d374SYoshinobu Inoue 	int a_off;
1407d56d374SYoshinobu Inoue 	const char *a_addrany;
1417d56d374SYoshinobu Inoue 	const char *a_loopback;
1427d56d374SYoshinobu Inoue 	int a_scoped;
1437d56d374SYoshinobu Inoue } afdl [] = {
1447d56d374SYoshinobu Inoue #ifdef INET6
1457d56d374SYoshinobu Inoue #define	N_INET6 0
1467d56d374SYoshinobu Inoue 	{PF_INET6, sizeof(struct in6_addr),
1477d56d374SYoshinobu Inoue 	 sizeof(struct sockaddr_in6),
1487d56d374SYoshinobu Inoue 	 offsetof(struct sockaddr_in6, sin6_addr),
1497d56d374SYoshinobu Inoue 	 in6_addrany, in6_loopback, 1},
1507d56d374SYoshinobu Inoue #define	N_INET 1
1517d56d374SYoshinobu Inoue #else
1527d56d374SYoshinobu Inoue #define	N_INET 0
1537d56d374SYoshinobu Inoue #endif
1547d56d374SYoshinobu Inoue 	{PF_INET, sizeof(struct in_addr),
1557d56d374SYoshinobu Inoue 	 sizeof(struct sockaddr_in),
1567d56d374SYoshinobu Inoue 	 offsetof(struct sockaddr_in, sin_addr),
1577d56d374SYoshinobu Inoue 	 in_addrany, in_loopback, 0},
1587d56d374SYoshinobu Inoue 	{0, 0, 0, 0, NULL, NULL, 0},
1597d56d374SYoshinobu Inoue };
1607d56d374SYoshinobu Inoue 
1617d56d374SYoshinobu Inoue struct explore {
162a42af91cSHajimu UMEMOTO 	int e_af;
1637d56d374SYoshinobu Inoue 	int e_socktype;
1647d56d374SYoshinobu Inoue 	int e_protocol;
1657d56d374SYoshinobu Inoue 	const char *e_protostr;
1667d56d374SYoshinobu Inoue 	int e_wild;
1677d56d374SYoshinobu Inoue #define WILD_AF(ex)		((ex)->e_wild & 0x01)
1687d56d374SYoshinobu Inoue #define WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
1697d56d374SYoshinobu Inoue #define WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
1707d56d374SYoshinobu Inoue };
1717d56d374SYoshinobu Inoue 
1727d56d374SYoshinobu Inoue static const struct explore explore[] = {
173a42af91cSHajimu UMEMOTO #if 0
174bf838688SHajimu UMEMOTO 	{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
175a42af91cSHajimu UMEMOTO #endif
176a42af91cSHajimu UMEMOTO #ifdef INET6
177bf838688SHajimu UMEMOTO 	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
178bf838688SHajimu UMEMOTO 	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
179bf838688SHajimu UMEMOTO 	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
180a42af91cSHajimu UMEMOTO #endif
181bf838688SHajimu UMEMOTO 	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
182bf838688SHajimu UMEMOTO 	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
183bf838688SHajimu UMEMOTO 	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
184bf838688SHajimu UMEMOTO 	{ PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
185bf838688SHajimu UMEMOTO 	{ PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
186bf838688SHajimu UMEMOTO 	{ PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
187a42af91cSHajimu UMEMOTO 	{ -1, 0, 0, NULL, 0 },
1887d56d374SYoshinobu Inoue };
1897d56d374SYoshinobu Inoue 
1907d56d374SYoshinobu Inoue #ifdef INET6
1917d56d374SYoshinobu Inoue #define PTON_MAX	16
1927d56d374SYoshinobu Inoue #else
1937d56d374SYoshinobu Inoue #define PTON_MAX	4
1947d56d374SYoshinobu Inoue #endif
1957d56d374SYoshinobu Inoue 
1964c6867a8SHajimu UMEMOTO #define AIO_SRCFLAG_DEPRECATED	0x1
1974c6867a8SHajimu UMEMOTO 
1984c6867a8SHajimu UMEMOTO struct ai_order {
1994c6867a8SHajimu UMEMOTO 	union {
2004c6867a8SHajimu UMEMOTO 		struct sockaddr_storage aiou_ss;
2014c6867a8SHajimu UMEMOTO 		struct sockaddr aiou_sa;
2024c6867a8SHajimu UMEMOTO 	} aio_src_un;
2034c6867a8SHajimu UMEMOTO #define aio_srcsa aio_src_un.aiou_sa
2044c6867a8SHajimu UMEMOTO 	u_int32_t aio_srcflag;
2054c6867a8SHajimu UMEMOTO 	int aio_srcscope;
2064c6867a8SHajimu UMEMOTO 	int aio_dstscope;
2074c6867a8SHajimu UMEMOTO 	struct policyqueue *aio_srcpolicy;
2084c6867a8SHajimu UMEMOTO 	struct policyqueue *aio_dstpolicy;
2094c6867a8SHajimu UMEMOTO 	struct addrinfo *aio_ai;
2104c6867a8SHajimu UMEMOTO 	int aio_matchlen;
2114c6867a8SHajimu UMEMOTO };
2124c6867a8SHajimu UMEMOTO 
213248aee62SJacques Vidrine static const ns_src default_dns_files[] = {
214248aee62SJacques Vidrine 	{ NSSRC_FILES, 	NS_SUCCESS },
215248aee62SJacques Vidrine 	{ NSSRC_DNS, 	NS_SUCCESS },
216248aee62SJacques Vidrine 	{ 0 }
217248aee62SJacques Vidrine };
218248aee62SJacques Vidrine 
219a42af91cSHajimu UMEMOTO struct res_target {
220a42af91cSHajimu UMEMOTO 	struct res_target *next;
221a42af91cSHajimu UMEMOTO 	const char *name;	/* domain name */
222b826397aSJun-ichiro itojun Hagino 	int qclass, qtype;	/* class and type of query */
223a42af91cSHajimu UMEMOTO 	u_char *answer;		/* buffer to put answer */
224a42af91cSHajimu UMEMOTO 	int anslen;		/* size of answer buffer */
225a42af91cSHajimu UMEMOTO 	int n;			/* result length */
226a42af91cSHajimu UMEMOTO };
227a42af91cSHajimu UMEMOTO 
228688a5c3eSHajimu UMEMOTO #define MAXPACKET	(64*1024)
229688a5c3eSHajimu UMEMOTO 
230688a5c3eSHajimu UMEMOTO typedef union {
231688a5c3eSHajimu UMEMOTO 	HEADER hdr;
232688a5c3eSHajimu UMEMOTO 	u_char buf[MAXPACKET];
233688a5c3eSHajimu UMEMOTO } querybuf;
234688a5c3eSHajimu UMEMOTO 
235c05ac53bSDavid E. O'Brien static int str_isnumber(const char *);
2361372519bSDavid E. O'Brien static int explore_null(const struct addrinfo *,
2371372519bSDavid E. O'Brien 	const char *, struct addrinfo **);
2381372519bSDavid E. O'Brien static int explore_numeric(const struct addrinfo *, const char *,
239bf838688SHajimu UMEMOTO 	const char *, struct addrinfo **);
2401372519bSDavid E. O'Brien static int explore_numeric_scope(const struct addrinfo *, const char *,
2411372519bSDavid E. O'Brien 	const char *, struct addrinfo **);
2421372519bSDavid E. O'Brien static int get_canonname(const struct addrinfo *,
2431372519bSDavid E. O'Brien 	struct addrinfo *, const char *);
2441372519bSDavid E. O'Brien static struct addrinfo *get_ai(const struct addrinfo *,
2451372519bSDavid E. O'Brien 	const struct afd *, const char *);
246c05ac53bSDavid E. O'Brien static int get_portmatch(const struct addrinfo *, const char *);
247c05ac53bSDavid E. O'Brien static int get_port(struct addrinfo *, const char *, int);
248c05ac53bSDavid E. O'Brien static const struct afd *find_afd(int);
249bf838688SHajimu UMEMOTO static int addrconfig(struct addrinfo *);
2504c6867a8SHajimu UMEMOTO static int comp_dst(const void *, const void *);
251a42af91cSHajimu UMEMOTO #ifdef INET6
252a89c1d30SHajimu UMEMOTO static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
253a42af91cSHajimu UMEMOTO #endif
2544c6867a8SHajimu UMEMOTO static int gai_addr2scopetype(struct sockaddr *);
255a42af91cSHajimu UMEMOTO 
256688a5c3eSHajimu UMEMOTO static int explore_fqdn(const struct addrinfo *, const char *,
257688a5c3eSHajimu UMEMOTO 	const char *, struct addrinfo **);
258688a5c3eSHajimu UMEMOTO 
2594c6867a8SHajimu UMEMOTO static int reorder(struct addrinfo *);
2604c6867a8SHajimu UMEMOTO static int get_addrselectpolicy(struct policyhead *);
2614c6867a8SHajimu UMEMOTO static void free_addrselectpolicy(struct policyhead *);
2624c6867a8SHajimu UMEMOTO static struct policyqueue *match_addrselectpolicy(struct sockaddr *,
2634c6867a8SHajimu UMEMOTO 	struct policyhead *);
2644c6867a8SHajimu UMEMOTO 
2651372519bSDavid E. O'Brien static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
2661372519bSDavid E. O'Brien 	const struct addrinfo *);
267688a5c3eSHajimu UMEMOTO #if defined(RESOLVSORT)
268688a5c3eSHajimu UMEMOTO static int addr4sort(struct addrinfo *);
269688a5c3eSHajimu UMEMOTO #endif
270a89c1d30SHajimu UMEMOTO static int _dns_getaddrinfo(void *, void *, va_list);
271c05ac53bSDavid E. O'Brien static void _sethtent(void);
272c05ac53bSDavid E. O'Brien static void _endhtent(void);
273c05ac53bSDavid E. O'Brien static struct addrinfo *_gethtent(const char *, const struct addrinfo *);
274c05ac53bSDavid E. O'Brien static int _files_getaddrinfo(void *, void *, va_list);
275a42af91cSHajimu UMEMOTO #ifdef YP
276c05ac53bSDavid E. O'Brien static struct addrinfo *_yphostent(char *, const struct addrinfo *);
277c05ac53bSDavid E. O'Brien static int _yp_getaddrinfo(void *, void *, va_list);
278a42af91cSHajimu UMEMOTO #endif
279a42af91cSHajimu UMEMOTO 
280c05ac53bSDavid E. O'Brien static int res_queryN(const char *, struct res_target *);
281c05ac53bSDavid E. O'Brien static int res_searchN(const char *, struct res_target *);
2821372519bSDavid E. O'Brien static int res_querydomainN(const char *, const char *,
2831372519bSDavid E. O'Brien 	struct res_target *);
284a42af91cSHajimu UMEMOTO 
285b29ec00bSHajimu UMEMOTO static struct ai_errlist {
286b29ec00bSHajimu UMEMOTO 	const char *str;
287b29ec00bSHajimu UMEMOTO 	int code;
288b29ec00bSHajimu UMEMOTO } ai_errlist[] = {
289b29ec00bSHajimu UMEMOTO 	{ "Success",					0, },
290b29ec00bSHajimu UMEMOTO 	{ "Temporary failure in name resolution",	EAI_AGAIN, },
291b29ec00bSHajimu UMEMOTO 	{ "Invalid value for ai_flags",		       	EAI_BADFLAGS, },
292b29ec00bSHajimu UMEMOTO 	{ "Non-recoverable failure in name resolution", EAI_FAIL, },
293b29ec00bSHajimu UMEMOTO 	{ "ai_family not supported",			EAI_FAMILY, },
294b29ec00bSHajimu UMEMOTO 	{ "Memory allocation failure", 			EAI_MEMORY, },
295b29ec00bSHajimu UMEMOTO 	{ "hostname nor servname provided, or not known", EAI_NONAME, },
296b29ec00bSHajimu UMEMOTO 	{ "servname not supported for ai_socktype",	EAI_SERVICE, },
297b29ec00bSHajimu UMEMOTO 	{ "ai_socktype not supported", 			EAI_SOCKTYPE, },
298b29ec00bSHajimu UMEMOTO 	{ "System error returned in errno", 		EAI_SYSTEM, },
299b29ec00bSHajimu UMEMOTO 	{ "Invalid value for hints",			EAI_BADHINTS, },
300b29ec00bSHajimu UMEMOTO 	{ "Resolved protocol is unknown",		EAI_PROTOCOL, },
301b29ec00bSHajimu UMEMOTO 	/* backward compatibility with userland code prior to 2553bis-02 */
302b29ec00bSHajimu UMEMOTO 	{ "Address family for hostname not supported",	1, },
303b29ec00bSHajimu UMEMOTO 	{ "No address associated with hostname", 	7, },
304b29ec00bSHajimu UMEMOTO 	{ NULL,						-1, },
3057d56d374SYoshinobu Inoue };
3067d56d374SYoshinobu Inoue 
30771918af6SHajimu UMEMOTO /*
30833dee819SBrian Feldman  * XXX: Many dependencies are not thread-safe.  So, we share lock between
30971918af6SHajimu UMEMOTO  * getaddrinfo() and getipnodeby*().  Still, we cannot use
31071918af6SHajimu UMEMOTO  * getaddrinfo() and getipnodeby*() in conjunction with other
31133dee819SBrian Feldman  * functions which call them.
31271918af6SHajimu UMEMOTO  */
313e8baaa70SDaniel Eischen pthread_mutex_t __getaddrinfo_thread_lock = PTHREAD_MUTEX_INITIALIZER;
31471918af6SHajimu UMEMOTO #define THREAD_LOCK() \
315e8baaa70SDaniel Eischen 	if (__isthreaded) _pthread_mutex_lock(&__getaddrinfo_thread_lock);
31671918af6SHajimu UMEMOTO #define THREAD_UNLOCK() \
317e8baaa70SDaniel Eischen 	if (__isthreaded) _pthread_mutex_unlock(&__getaddrinfo_thread_lock);
31871918af6SHajimu UMEMOTO 
3197d56d374SYoshinobu Inoue /* XXX macros that make external reference is BAD. */
3207d56d374SYoshinobu Inoue 
3217d56d374SYoshinobu Inoue #define GET_AI(ai, afd, addr) \
3227d56d374SYoshinobu Inoue do { \
3237d56d374SYoshinobu Inoue 	/* external reference: pai, error, and label free */ \
3247d56d374SYoshinobu Inoue 	(ai) = get_ai(pai, (afd), (addr)); \
3257d56d374SYoshinobu Inoue 	if ((ai) == NULL) { \
3267d56d374SYoshinobu Inoue 		error = EAI_MEMORY; \
3277d56d374SYoshinobu Inoue 		goto free; \
3287d56d374SYoshinobu Inoue 	} \
329a42af91cSHajimu UMEMOTO } while (/*CONSTCOND*/0)
3307d56d374SYoshinobu Inoue 
3317d56d374SYoshinobu Inoue #define GET_PORT(ai, serv) \
3327d56d374SYoshinobu Inoue do { \
3337d56d374SYoshinobu Inoue 	/* external reference: error and label free */ \
3347d56d374SYoshinobu Inoue 	error = get_port((ai), (serv), 0); \
3357d56d374SYoshinobu Inoue 	if (error != 0) \
3367d56d374SYoshinobu Inoue 		goto free; \
337a42af91cSHajimu UMEMOTO } while (/*CONSTCOND*/0)
3387d56d374SYoshinobu Inoue 
3397d56d374SYoshinobu Inoue #define GET_CANONNAME(ai, str) \
3407d56d374SYoshinobu Inoue do { \
3417d56d374SYoshinobu Inoue 	/* external reference: pai, error and label free */ \
3427d56d374SYoshinobu Inoue 	error = get_canonname(pai, (ai), (str)); \
3437d56d374SYoshinobu Inoue 	if (error != 0) \
3447d56d374SYoshinobu Inoue 		goto free; \
345a42af91cSHajimu UMEMOTO } while (/*CONSTCOND*/0)
3467d56d374SYoshinobu Inoue 
3477d56d374SYoshinobu Inoue #define ERR(err) \
3487d56d374SYoshinobu Inoue do { \
3497d56d374SYoshinobu Inoue 	/* external reference: error, and label bad */ \
3507d56d374SYoshinobu Inoue 	error = (err); \
3517d56d374SYoshinobu Inoue 	goto bad; \
352a42af91cSHajimu UMEMOTO 	/*NOTREACHED*/ \
353a42af91cSHajimu UMEMOTO } while (/*CONSTCOND*/0)
3547d56d374SYoshinobu Inoue 
3557d56d374SYoshinobu Inoue #define MATCH_FAMILY(x, y, w) \
356a42af91cSHajimu UMEMOTO 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
3577d56d374SYoshinobu Inoue #define MATCH(x, y, w) \
358a42af91cSHajimu UMEMOTO 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
3597d56d374SYoshinobu Inoue 
3607d56d374SYoshinobu Inoue char *
3617d56d374SYoshinobu Inoue gai_strerror(ecode)
3627d56d374SYoshinobu Inoue 	int ecode;
3637d56d374SYoshinobu Inoue {
364b29ec00bSHajimu UMEMOTO 	struct ai_errlist *p;
365b29ec00bSHajimu UMEMOTO 
366b29ec00bSHajimu UMEMOTO 	for (p = ai_errlist; p->str; p++) {
367b29ec00bSHajimu UMEMOTO 		if (p->code == ecode)
368b29ec00bSHajimu UMEMOTO 			return (char *)p->str;
369b29ec00bSHajimu UMEMOTO 	}
3703b1a7797SHajimu UMEMOTO 	return "Unknown error";
3717d56d374SYoshinobu Inoue }
3727d56d374SYoshinobu Inoue 
3737d56d374SYoshinobu Inoue void
3747d56d374SYoshinobu Inoue freeaddrinfo(ai)
3757d56d374SYoshinobu Inoue 	struct addrinfo *ai;
3767d56d374SYoshinobu Inoue {
3777d56d374SYoshinobu Inoue 	struct addrinfo *next;
3787d56d374SYoshinobu Inoue 
3797d56d374SYoshinobu Inoue 	do {
3807d56d374SYoshinobu Inoue 		next = ai->ai_next;
3817d56d374SYoshinobu Inoue 		if (ai->ai_canonname)
3827d56d374SYoshinobu Inoue 			free(ai->ai_canonname);
3837d56d374SYoshinobu Inoue 		/* no need to free(ai->ai_addr) */
3847d56d374SYoshinobu Inoue 		free(ai);
385a42af91cSHajimu UMEMOTO 		ai = next;
386a42af91cSHajimu UMEMOTO 	} while (ai);
3877d56d374SYoshinobu Inoue }
3887d56d374SYoshinobu Inoue 
3897d56d374SYoshinobu Inoue static int
3907d56d374SYoshinobu Inoue str_isnumber(p)
3917d56d374SYoshinobu Inoue 	const char *p;
3927d56d374SYoshinobu Inoue {
393ec20fe00SJun-ichiro itojun Hagino 	char *ep;
394ec20fe00SJun-ichiro itojun Hagino 
395ec20fe00SJun-ichiro itojun Hagino 	if (*p == '\0')
3967d56d374SYoshinobu Inoue 		return NO;
397ec20fe00SJun-ichiro itojun Hagino 	ep = NULL;
398a89c1d30SHajimu UMEMOTO 	errno = 0;
399ec20fe00SJun-ichiro itojun Hagino 	(void)strtoul(p, &ep, 10);
400a89c1d30SHajimu UMEMOTO 	if (errno == 0 && ep && *ep == '\0')
4017d56d374SYoshinobu Inoue 		return YES;
402ec20fe00SJun-ichiro itojun Hagino 	else
403ec20fe00SJun-ichiro itojun Hagino 		return NO;
4047d56d374SYoshinobu Inoue }
4057d56d374SYoshinobu Inoue 
4067d56d374SYoshinobu Inoue int
4077d56d374SYoshinobu Inoue getaddrinfo(hostname, servname, hints, res)
4087d56d374SYoshinobu Inoue 	const char *hostname, *servname;
4097d56d374SYoshinobu Inoue 	const struct addrinfo *hints;
4107d56d374SYoshinobu Inoue 	struct addrinfo **res;
4117d56d374SYoshinobu Inoue {
4127d56d374SYoshinobu Inoue 	struct addrinfo sentinel;
4137d56d374SYoshinobu Inoue 	struct addrinfo *cur;
4147d56d374SYoshinobu Inoue 	int error = 0;
415bf838688SHajimu UMEMOTO 	struct addrinfo ai;
416bf838688SHajimu UMEMOTO 	struct addrinfo ai0;
4177d56d374SYoshinobu Inoue 	struct addrinfo *pai;
4187d56d374SYoshinobu Inoue 	const struct explore *ex;
4194c6867a8SHajimu UMEMOTO 	int numeric = 0;
4207d56d374SYoshinobu Inoue 
421a42af91cSHajimu UMEMOTO 	memset(&sentinel, 0, sizeof(sentinel));
4227d56d374SYoshinobu Inoue 	cur = &sentinel;
4237d56d374SYoshinobu Inoue 	pai = &ai;
4247d56d374SYoshinobu Inoue 	pai->ai_flags = 0;
4257d56d374SYoshinobu Inoue 	pai->ai_family = PF_UNSPEC;
4267d56d374SYoshinobu Inoue 	pai->ai_socktype = ANY;
4277d56d374SYoshinobu Inoue 	pai->ai_protocol = ANY;
4287d56d374SYoshinobu Inoue 	pai->ai_addrlen = 0;
4297d56d374SYoshinobu Inoue 	pai->ai_canonname = NULL;
4307d56d374SYoshinobu Inoue 	pai->ai_addr = NULL;
4317d56d374SYoshinobu Inoue 	pai->ai_next = NULL;
4327d56d374SYoshinobu Inoue 
4337d56d374SYoshinobu Inoue 	if (hostname == NULL && servname == NULL)
4347d56d374SYoshinobu Inoue 		return EAI_NONAME;
4357d56d374SYoshinobu Inoue 	if (hints) {
4367d56d374SYoshinobu Inoue 		/* error check for hints */
4377d56d374SYoshinobu Inoue 		if (hints->ai_addrlen || hints->ai_canonname ||
4387d56d374SYoshinobu Inoue 		    hints->ai_addr || hints->ai_next)
4397d56d374SYoshinobu Inoue 			ERR(EAI_BADHINTS); /* xxx */
4407d56d374SYoshinobu Inoue 		if (hints->ai_flags & ~AI_MASK)
4417d56d374SYoshinobu Inoue 			ERR(EAI_BADFLAGS);
4427d56d374SYoshinobu Inoue 		switch (hints->ai_family) {
4437d56d374SYoshinobu Inoue 		case PF_UNSPEC:
4447d56d374SYoshinobu Inoue 		case PF_INET:
4457d56d374SYoshinobu Inoue #ifdef INET6
4467d56d374SYoshinobu Inoue 		case PF_INET6:
4477d56d374SYoshinobu Inoue #endif
4487d56d374SYoshinobu Inoue 			break;
4497d56d374SYoshinobu Inoue 		default:
4507d56d374SYoshinobu Inoue 			ERR(EAI_FAMILY);
4517d56d374SYoshinobu Inoue 		}
4527d56d374SYoshinobu Inoue 		memcpy(pai, hints, sizeof(*pai));
4537d56d374SYoshinobu Inoue 
4547d56d374SYoshinobu Inoue 		/*
4557d56d374SYoshinobu Inoue 		 * if both socktype/protocol are specified, check if they
4567d56d374SYoshinobu Inoue 		 * are meaningful combination.
4577d56d374SYoshinobu Inoue 		 */
4587d56d374SYoshinobu Inoue 		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
459a42af91cSHajimu UMEMOTO 			for (ex = explore; ex->e_af >= 0; ex++) {
460bf838688SHajimu UMEMOTO 				if (pai->ai_family != ex->e_af)
461a42af91cSHajimu UMEMOTO 					continue;
462bf838688SHajimu UMEMOTO 				if (ex->e_socktype == ANY)
4637d56d374SYoshinobu Inoue 					continue;
464bf838688SHajimu UMEMOTO 				if (ex->e_protocol == ANY)
4657d56d374SYoshinobu Inoue 					continue;
466bf838688SHajimu UMEMOTO 				if (pai->ai_socktype == ex->e_socktype &&
467bf838688SHajimu UMEMOTO 				    pai->ai_protocol != ex->e_protocol) {
4687d56d374SYoshinobu Inoue 					ERR(EAI_BADHINTS);
4697d56d374SYoshinobu Inoue 				}
4707d56d374SYoshinobu Inoue 			}
4717d56d374SYoshinobu Inoue 		}
472bf838688SHajimu UMEMOTO 	}
4737d56d374SYoshinobu Inoue 
4747d56d374SYoshinobu Inoue 	/*
475a42af91cSHajimu UMEMOTO 	 * post-2553: AI_ALL and AI_V4MAPPED are effective only against
476dd521ef1SHajimu UMEMOTO 	 * AF_INET6 query.  They need to be ignored if specified in other
477a42af91cSHajimu UMEMOTO 	 * occassions.
478a42af91cSHajimu UMEMOTO 	 */
479a42af91cSHajimu UMEMOTO 	switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
480a42af91cSHajimu UMEMOTO 	case AI_V4MAPPED:
481a42af91cSHajimu UMEMOTO 	case AI_ALL | AI_V4MAPPED:
482a42af91cSHajimu UMEMOTO 		if (pai->ai_family != AF_INET6)
483a42af91cSHajimu UMEMOTO 			pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
484a42af91cSHajimu UMEMOTO 		break;
485a42af91cSHajimu UMEMOTO 	case AI_ALL:
486a42af91cSHajimu UMEMOTO #if 1
487a42af91cSHajimu UMEMOTO 		/* illegal */
488a42af91cSHajimu UMEMOTO 		ERR(EAI_BADFLAGS);
489a42af91cSHajimu UMEMOTO #else
490a42af91cSHajimu UMEMOTO 		pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
491a42af91cSHajimu UMEMOTO #endif
492a42af91cSHajimu UMEMOTO 		break;
493a42af91cSHajimu UMEMOTO 	}
494a42af91cSHajimu UMEMOTO 
495a42af91cSHajimu UMEMOTO 	/*
496a42af91cSHajimu UMEMOTO 	 * check for special cases.  (1) numeric servname is disallowed if
497a42af91cSHajimu UMEMOTO 	 * socktype/protocol are left unspecified. (2) servname is disallowed
498a42af91cSHajimu UMEMOTO 	 * for raw and other inet{,6} sockets.
4997d56d374SYoshinobu Inoue 	 */
5007d56d374SYoshinobu Inoue 	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
501a42af91cSHajimu UMEMOTO #ifdef PF_INET6
5027d56d374SYoshinobu Inoue 	    || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
5037d56d374SYoshinobu Inoue #endif
5047d56d374SYoshinobu Inoue 	    ) {
505a42af91cSHajimu UMEMOTO 		ai0 = *pai;	/* backup *pai */
5067d56d374SYoshinobu Inoue 
507a42af91cSHajimu UMEMOTO 		if (pai->ai_family == PF_UNSPEC) {
508a42af91cSHajimu UMEMOTO #ifdef PF_INET6
5097d56d374SYoshinobu Inoue 			pai->ai_family = PF_INET6;
5107d56d374SYoshinobu Inoue #else
5117d56d374SYoshinobu Inoue 			pai->ai_family = PF_INET;
5127d56d374SYoshinobu Inoue #endif
513a42af91cSHajimu UMEMOTO 		}
5147d56d374SYoshinobu Inoue 		error = get_portmatch(pai, servname);
5157d56d374SYoshinobu Inoue 		if (error)
5167d56d374SYoshinobu Inoue 			ERR(error);
517a42af91cSHajimu UMEMOTO 
518a42af91cSHajimu UMEMOTO 		*pai = ai0;
5197d56d374SYoshinobu Inoue 	}
5207d56d374SYoshinobu Inoue 
521a42af91cSHajimu UMEMOTO 	ai0 = *pai;
522a42af91cSHajimu UMEMOTO 
523bf838688SHajimu UMEMOTO 	/* NULL hostname, or numeric hostname */
524a42af91cSHajimu UMEMOTO 	for (ex = explore; ex->e_af >= 0; ex++) {
5257d56d374SYoshinobu Inoue 		*pai = ai0;
5267d56d374SYoshinobu Inoue 
527bf838688SHajimu UMEMOTO 		/* PF_UNSPEC entries are prepared for DNS queries only */
528bf838688SHajimu UMEMOTO 		if (ex->e_af == PF_UNSPEC)
529bf838688SHajimu UMEMOTO 			continue;
530a42af91cSHajimu UMEMOTO 
531a42af91cSHajimu UMEMOTO 		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
5327d56d374SYoshinobu Inoue 			continue;
533248aee62SJacques Vidrine 		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
534a42af91cSHajimu UMEMOTO 			continue;
535248aee62SJacques Vidrine 		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
5367d56d374SYoshinobu Inoue 			continue;
5377d56d374SYoshinobu Inoue 
5387d56d374SYoshinobu Inoue 		if (pai->ai_family == PF_UNSPEC)
539a42af91cSHajimu UMEMOTO 			pai->ai_family = ex->e_af;
5407d56d374SYoshinobu Inoue 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
5417d56d374SYoshinobu Inoue 			pai->ai_socktype = ex->e_socktype;
5427d56d374SYoshinobu Inoue 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
5437d56d374SYoshinobu Inoue 			pai->ai_protocol = ex->e_protocol;
5447d56d374SYoshinobu Inoue 
545bf838688SHajimu UMEMOTO 		if (hostname == NULL)
546bf838688SHajimu UMEMOTO 			error = explore_null(pai, servname, &cur->ai_next);
547bf838688SHajimu UMEMOTO 		else
548bf838688SHajimu UMEMOTO 			error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
5497d56d374SYoshinobu Inoue 
550bf838688SHajimu UMEMOTO 		if (error)
551bf838688SHajimu UMEMOTO 			goto free;
5527d56d374SYoshinobu Inoue 
5537d56d374SYoshinobu Inoue 		while (cur && cur->ai_next)
5547d56d374SYoshinobu Inoue 			cur = cur->ai_next;
5557d56d374SYoshinobu Inoue 	}
5567d56d374SYoshinobu Inoue 
557bf838688SHajimu UMEMOTO 	/*
558bf838688SHajimu UMEMOTO 	 * XXX
559bf838688SHajimu UMEMOTO 	 * If numreic representation of AF1 can be interpreted as FQDN
560bf838688SHajimu UMEMOTO 	 * representation of AF2, we need to think again about the code below.
561bf838688SHajimu UMEMOTO 	 */
5624c6867a8SHajimu UMEMOTO 	if (sentinel.ai_next) {
5634c6867a8SHajimu UMEMOTO 		numeric = 1;
564bf838688SHajimu UMEMOTO 		goto good;
5654c6867a8SHajimu UMEMOTO 	}
566bf838688SHajimu UMEMOTO 
567bf838688SHajimu UMEMOTO 	if (hostname == NULL)
568bf838688SHajimu UMEMOTO 		ERR(EAI_NONAME);	/* used to be EAI_NODATA */
569bf838688SHajimu UMEMOTO 	if (pai->ai_flags & AI_NUMERICHOST)
570bf838688SHajimu UMEMOTO 		ERR(EAI_NONAME);
571bf838688SHajimu UMEMOTO 
572bf838688SHajimu UMEMOTO 	if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
573bf838688SHajimu UMEMOTO 		ERR(EAI_FAIL);
574a42af91cSHajimu UMEMOTO 
575f95d4633SHajimu UMEMOTO 	/*
576bf838688SHajimu UMEMOTO 	 * hostname as alphabetical name.
577bf838688SHajimu UMEMOTO 	 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
578bf838688SHajimu UMEMOTO 	 * outer loop by AFs.
579f95d4633SHajimu UMEMOTO 	 */
580bf838688SHajimu UMEMOTO 	for (ex = explore; ex->e_af >= 0; ex++) {
581bf838688SHajimu UMEMOTO 		*pai = ai0;
582f95d4633SHajimu UMEMOTO 
583bf838688SHajimu UMEMOTO 		/* require exact match for family field */
584bf838688SHajimu UMEMOTO 		if (pai->ai_family != ex->e_af)
585f95d4633SHajimu UMEMOTO 			continue;
586f95d4633SHajimu UMEMOTO 
587bf838688SHajimu UMEMOTO 		if (!MATCH(pai->ai_socktype, ex->e_socktype,
588bf838688SHajimu UMEMOTO 				WILD_SOCKTYPE(ex))) {
589bf838688SHajimu UMEMOTO 			continue;
590bf838688SHajimu UMEMOTO 		}
591bf838688SHajimu UMEMOTO 		if (!MATCH(pai->ai_protocol, ex->e_protocol,
592bf838688SHajimu UMEMOTO 				WILD_PROTOCOL(ex))) {
593bf838688SHajimu UMEMOTO 			continue;
594f95d4633SHajimu UMEMOTO 		}
595f95d4633SHajimu UMEMOTO 
596bf838688SHajimu UMEMOTO 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
597bf838688SHajimu UMEMOTO 			pai->ai_socktype = ex->e_socktype;
598bf838688SHajimu UMEMOTO 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
599bf838688SHajimu UMEMOTO 			pai->ai_protocol = ex->e_protocol;
600bf838688SHajimu UMEMOTO 
601bf838688SHajimu UMEMOTO 		error = explore_fqdn(pai, hostname, servname,
602bf838688SHajimu UMEMOTO 			&cur->ai_next);
603bf838688SHajimu UMEMOTO 
604bf838688SHajimu UMEMOTO 		while (cur && cur->ai_next)
605f95d4633SHajimu UMEMOTO 			cur = cur->ai_next;
606f95d4633SHajimu UMEMOTO 	}
607f95d4633SHajimu UMEMOTO 
6084c6867a8SHajimu UMEMOTO 	/* XXX inhibit errors if we have the result */
609bf838688SHajimu UMEMOTO 	if (sentinel.ai_next)
610bf838688SHajimu UMEMOTO 		error = 0;
611f95d4633SHajimu UMEMOTO 
6124c6867a8SHajimu UMEMOTO good:
6134c6867a8SHajimu UMEMOTO 	/*
6144c6867a8SHajimu UMEMOTO 	 * ensure we return either:
6154c6867a8SHajimu UMEMOTO 	 * - error == 0, non-NULL *res
6164c6867a8SHajimu UMEMOTO 	 * - error != 0, NULL *res
6174c6867a8SHajimu UMEMOTO 	 */
618bf838688SHajimu UMEMOTO 	if (error == 0) {
619bf838688SHajimu UMEMOTO 		if (sentinel.ai_next) {
6204c6867a8SHajimu UMEMOTO 			/*
6214c6867a8SHajimu UMEMOTO 			 * If the returned entry is for an active connection,
6224c6867a8SHajimu UMEMOTO 			 * and the given name is not numeric, reorder the
6234c6867a8SHajimu UMEMOTO 			 * list, so that the application would try the list
6244c6867a8SHajimu UMEMOTO 			 * in the most efficient order.
6254c6867a8SHajimu UMEMOTO 			 */
6264c6867a8SHajimu UMEMOTO 			if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) {
6274c6867a8SHajimu UMEMOTO 				if (!numeric)
6284c6867a8SHajimu UMEMOTO 					(void)reorder(&sentinel);
6294c6867a8SHajimu UMEMOTO 			}
630bf838688SHajimu UMEMOTO 			*res = sentinel.ai_next;
631bf838688SHajimu UMEMOTO 			return SUCCESS;
632bf838688SHajimu UMEMOTO 		} else
633bf838688SHajimu UMEMOTO 			error = EAI_FAIL;
634bf838688SHajimu UMEMOTO 	}
635bf838688SHajimu UMEMOTO free:
636bf838688SHajimu UMEMOTO bad:
637bf838688SHajimu UMEMOTO 	if (sentinel.ai_next)
638f95d4633SHajimu UMEMOTO 		freeaddrinfo(sentinel.ai_next);
639bf838688SHajimu UMEMOTO 	*res = NULL;
6407d56d374SYoshinobu Inoue 	return error;
6417d56d374SYoshinobu Inoue }
6427d56d374SYoshinobu Inoue 
6434c6867a8SHajimu UMEMOTO static int
6444c6867a8SHajimu UMEMOTO reorder(sentinel)
6454c6867a8SHajimu UMEMOTO 	struct addrinfo *sentinel;
6464c6867a8SHajimu UMEMOTO {
6474c6867a8SHajimu UMEMOTO 	struct addrinfo *ai, **aip;
6484c6867a8SHajimu UMEMOTO 	struct ai_order *aio;
6494c6867a8SHajimu UMEMOTO 	int i, n;
6504c6867a8SHajimu UMEMOTO 	struct policyhead policyhead;
6514c6867a8SHajimu UMEMOTO 
6524c6867a8SHajimu UMEMOTO 	/* count the number of addrinfo elements for sorting. */
6534c6867a8SHajimu UMEMOTO 	for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++)
6544c6867a8SHajimu UMEMOTO 		;
6554c6867a8SHajimu UMEMOTO 
6564c6867a8SHajimu UMEMOTO 	/*
6574c6867a8SHajimu UMEMOTO 	 * If the number is small enough, we can skip the reordering process.
6584c6867a8SHajimu UMEMOTO 	 */
6594c6867a8SHajimu UMEMOTO 	if (n <= 1)
6604c6867a8SHajimu UMEMOTO 		return(n);
6614c6867a8SHajimu UMEMOTO 
6624c6867a8SHajimu UMEMOTO 	/* allocate a temporary array for sort and initialization of it. */
6634c6867a8SHajimu UMEMOTO 	if ((aio = malloc(sizeof(*aio) * n)) == NULL)
6644c6867a8SHajimu UMEMOTO 		return(n);	/* give up reordering */
6654c6867a8SHajimu UMEMOTO 	memset(aio, 0, sizeof(*aio) * n);
6664c6867a8SHajimu UMEMOTO 
6674c6867a8SHajimu UMEMOTO 	/* retrieve address selection policy from the kernel */
6684c6867a8SHajimu UMEMOTO 	TAILQ_INIT(&policyhead);
6694c6867a8SHajimu UMEMOTO 	if (!get_addrselectpolicy(&policyhead)) {
6704c6867a8SHajimu UMEMOTO 		/* no policy is installed into kernel, we don't sort. */
6714c6867a8SHajimu UMEMOTO 		free(aio);
6724c6867a8SHajimu UMEMOTO 		return (n);
6734c6867a8SHajimu UMEMOTO 	}
6744c6867a8SHajimu UMEMOTO 
6754c6867a8SHajimu UMEMOTO 	for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) {
6764c6867a8SHajimu UMEMOTO 		aio[i].aio_ai = ai;
6774c6867a8SHajimu UMEMOTO 		aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr);
6784c6867a8SHajimu UMEMOTO 		aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr,
6794c6867a8SHajimu UMEMOTO 							      &policyhead);
6804c6867a8SHajimu UMEMOTO 	}
6814c6867a8SHajimu UMEMOTO 
6824c6867a8SHajimu UMEMOTO 	/* perform sorting. */
6834c6867a8SHajimu UMEMOTO 	qsort(aio, n, sizeof(*aio), comp_dst);
6844c6867a8SHajimu UMEMOTO 
6854c6867a8SHajimu UMEMOTO 	/* reorder the addrinfo chain. */
6864c6867a8SHajimu UMEMOTO 	for (i = 0, aip = &sentinel->ai_next; i < n; i++) {
6874c6867a8SHajimu UMEMOTO 		*aip = aio[i].aio_ai;
6884c6867a8SHajimu UMEMOTO 		aip = &aio[i].aio_ai->ai_next;
6894c6867a8SHajimu UMEMOTO 	}
6904c6867a8SHajimu UMEMOTO 	*aip = NULL;
6914c6867a8SHajimu UMEMOTO 
6924c6867a8SHajimu UMEMOTO 	/* cleanup and return */
6934c6867a8SHajimu UMEMOTO 	free(aio);
6944c6867a8SHajimu UMEMOTO 	free_addrselectpolicy(&policyhead);
6954c6867a8SHajimu UMEMOTO 	return(n);
6964c6867a8SHajimu UMEMOTO }
6974c6867a8SHajimu UMEMOTO 
6984c6867a8SHajimu UMEMOTO static int
6994c6867a8SHajimu UMEMOTO get_addrselectpolicy(head)
7004c6867a8SHajimu UMEMOTO 	struct policyhead *head;
7014c6867a8SHajimu UMEMOTO {
7024c6867a8SHajimu UMEMOTO #ifdef INET6
7034c6867a8SHajimu UMEMOTO 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
7044c6867a8SHajimu UMEMOTO 	size_t l;
7054c6867a8SHajimu UMEMOTO 	char *buf;
7064c6867a8SHajimu UMEMOTO 	struct in6_addrpolicy *pol, *ep;
7074c6867a8SHajimu UMEMOTO 
7084c6867a8SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
7094c6867a8SHajimu UMEMOTO 		return (0);
7104c6867a8SHajimu UMEMOTO 	if ((buf = malloc(l)) == NULL)
7114c6867a8SHajimu UMEMOTO 		return (0);
7124c6867a8SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
7134c6867a8SHajimu UMEMOTO 		free(buf);
7144c6867a8SHajimu UMEMOTO 		return (0);
7154c6867a8SHajimu UMEMOTO 	}
7164c6867a8SHajimu UMEMOTO 
7174c6867a8SHajimu UMEMOTO 	ep = (struct in6_addrpolicy *)(buf + l);
7184c6867a8SHajimu UMEMOTO 	for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
7194c6867a8SHajimu UMEMOTO 		struct policyqueue *new;
7204c6867a8SHajimu UMEMOTO 
7214c6867a8SHajimu UMEMOTO 		if ((new = malloc(sizeof(*new))) == NULL) {
7224c6867a8SHajimu UMEMOTO 			free_addrselectpolicy(head); /* make the list empty */
7234c6867a8SHajimu UMEMOTO 			break;
7244c6867a8SHajimu UMEMOTO 		}
7254c6867a8SHajimu UMEMOTO 		new->pc_policy = *pol;
7264c6867a8SHajimu UMEMOTO 		TAILQ_INSERT_TAIL(head, new, pc_entry);
7274c6867a8SHajimu UMEMOTO 	}
7284c6867a8SHajimu UMEMOTO 
7294c6867a8SHajimu UMEMOTO 	free(buf);
7304c6867a8SHajimu UMEMOTO 	return (1);
7314c6867a8SHajimu UMEMOTO #else
7324c6867a8SHajimu UMEMOTO 	return (0);
7334c6867a8SHajimu UMEMOTO #endif
7344c6867a8SHajimu UMEMOTO }
7354c6867a8SHajimu UMEMOTO 
7364c6867a8SHajimu UMEMOTO static void
7374c6867a8SHajimu UMEMOTO free_addrselectpolicy(head)
7384c6867a8SHajimu UMEMOTO 	struct policyhead *head;
7394c6867a8SHajimu UMEMOTO {
7404c6867a8SHajimu UMEMOTO 	struct policyqueue *ent, *nent;
7414c6867a8SHajimu UMEMOTO 
7424c6867a8SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = nent) {
7434c6867a8SHajimu UMEMOTO 		nent = TAILQ_NEXT(ent, pc_entry);
7444c6867a8SHajimu UMEMOTO 		TAILQ_REMOVE(head, ent, pc_entry);
7454c6867a8SHajimu UMEMOTO 		free(ent);
7464c6867a8SHajimu UMEMOTO 	}
7474c6867a8SHajimu UMEMOTO }
7484c6867a8SHajimu UMEMOTO 
7494c6867a8SHajimu UMEMOTO static struct policyqueue *
7504c6867a8SHajimu UMEMOTO match_addrselectpolicy(addr, head)
7514c6867a8SHajimu UMEMOTO 	struct sockaddr *addr;
7524c6867a8SHajimu UMEMOTO 	struct policyhead *head;
7534c6867a8SHajimu UMEMOTO {
7544c6867a8SHajimu UMEMOTO #ifdef INET6
7554c6867a8SHajimu UMEMOTO 	struct policyqueue *ent, *bestent = NULL;
7564c6867a8SHajimu UMEMOTO 	struct in6_addrpolicy *pol;
7574c6867a8SHajimu UMEMOTO 	int matchlen, bestmatchlen = -1;
7584c6867a8SHajimu UMEMOTO 	u_char *mp, *ep, *k, *p, m;
7594c6867a8SHajimu UMEMOTO 	struct sockaddr_in6 key;
7604c6867a8SHajimu UMEMOTO 
7614c6867a8SHajimu UMEMOTO 	switch(addr->sa_family) {
7624c6867a8SHajimu UMEMOTO 	case AF_INET6:
7634c6867a8SHajimu UMEMOTO 		key = *(struct sockaddr_in6 *)addr;
7644c6867a8SHajimu UMEMOTO 		break;
7654c6867a8SHajimu UMEMOTO 	case AF_INET:
7664c6867a8SHajimu UMEMOTO 		/* convert the address into IPv4-mapped IPv6 address. */
7674c6867a8SHajimu UMEMOTO 		memset(&key, 0, sizeof(key));
7684c6867a8SHajimu UMEMOTO 		key.sin6_family = AF_INET6;
7694c6867a8SHajimu UMEMOTO 		key.sin6_len = sizeof(key);
7704c6867a8SHajimu UMEMOTO 		key.sin6_addr.s6_addr[10] = 0xff;
7714c6867a8SHajimu UMEMOTO 		key.sin6_addr.s6_addr[11] = 0xff;
7724c6867a8SHajimu UMEMOTO 		memcpy(&key.sin6_addr.s6_addr[12],
7734c6867a8SHajimu UMEMOTO 		       &((struct sockaddr_in *)addr)->sin_addr, 4);
7744c6867a8SHajimu UMEMOTO 		break;
7754c6867a8SHajimu UMEMOTO 	default:
7764c6867a8SHajimu UMEMOTO 		return(NULL);
7774c6867a8SHajimu UMEMOTO 	}
7784c6867a8SHajimu UMEMOTO 
7794c6867a8SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
7804c6867a8SHajimu UMEMOTO 		pol = &ent->pc_policy;
7814c6867a8SHajimu UMEMOTO 		matchlen = 0;
7824c6867a8SHajimu UMEMOTO 
7834c6867a8SHajimu UMEMOTO 		mp = (u_char *)&pol->addrmask.sin6_addr;
7844c6867a8SHajimu UMEMOTO 		ep = mp + 16;	/* XXX: scope field? */
7854c6867a8SHajimu UMEMOTO 		k = (u_char *)&key.sin6_addr;
7864c6867a8SHajimu UMEMOTO 		p = (u_char *)&pol->addr.sin6_addr;
7874c6867a8SHajimu UMEMOTO 		for (; mp < ep && *mp; mp++, k++, p++) {
7884c6867a8SHajimu UMEMOTO 			m = *mp;
7894c6867a8SHajimu UMEMOTO 			if ((*k & m) != *p)
7904c6867a8SHajimu UMEMOTO 				goto next; /* not match */
7914c6867a8SHajimu UMEMOTO 			if (m == 0xff) /* short cut for a typical case */
7924c6867a8SHajimu UMEMOTO 				matchlen += 8;
7934c6867a8SHajimu UMEMOTO 			else {
7944c6867a8SHajimu UMEMOTO 				while (m >= 0x80) {
7954c6867a8SHajimu UMEMOTO 					matchlen++;
7964c6867a8SHajimu UMEMOTO 					m <<= 1;
7974c6867a8SHajimu UMEMOTO 				}
7984c6867a8SHajimu UMEMOTO 			}
7994c6867a8SHajimu UMEMOTO 		}
8004c6867a8SHajimu UMEMOTO 
8014c6867a8SHajimu UMEMOTO 		/* matched.  check if this is better than the current best. */
8024c6867a8SHajimu UMEMOTO 		if (matchlen > bestmatchlen) {
8034c6867a8SHajimu UMEMOTO 			bestent = ent;
8044c6867a8SHajimu UMEMOTO 			bestmatchlen = matchlen;
8054c6867a8SHajimu UMEMOTO 		}
8064c6867a8SHajimu UMEMOTO 
8074c6867a8SHajimu UMEMOTO 	  next:
8084c6867a8SHajimu UMEMOTO 		continue;
8094c6867a8SHajimu UMEMOTO 	}
8104c6867a8SHajimu UMEMOTO 
8114c6867a8SHajimu UMEMOTO 	return(bestent);
8124c6867a8SHajimu UMEMOTO #else
8134c6867a8SHajimu UMEMOTO 	return(NULL);
8144c6867a8SHajimu UMEMOTO #endif
8154c6867a8SHajimu UMEMOTO 
8164c6867a8SHajimu UMEMOTO }
8174c6867a8SHajimu UMEMOTO 
8184c6867a8SHajimu UMEMOTO static int
8194c6867a8SHajimu UMEMOTO comp_dst(arg1, arg2)
8204c6867a8SHajimu UMEMOTO 	const void *arg1, *arg2;
8214c6867a8SHajimu UMEMOTO {
8224c6867a8SHajimu UMEMOTO 	const struct ai_order *dst1 = arg1, *dst2 = arg2;
8234c6867a8SHajimu UMEMOTO 
8244c6867a8SHajimu UMEMOTO 	/*
8254c6867a8SHajimu UMEMOTO 	 * Rule 1: Avoid unusable destinations.
8264c6867a8SHajimu UMEMOTO 	 * XXX: we currently do not consider if an appropriate route exists.
8274c6867a8SHajimu UMEMOTO 	 */
8284c6867a8SHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
8294c6867a8SHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family == AF_UNSPEC) {
8304c6867a8SHajimu UMEMOTO 		return(-1);
8314c6867a8SHajimu UMEMOTO 	}
8324c6867a8SHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
8334c6867a8SHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
8344c6867a8SHajimu UMEMOTO 		return(1);
8354c6867a8SHajimu UMEMOTO 	}
8364c6867a8SHajimu UMEMOTO 
8374c6867a8SHajimu UMEMOTO 	/* Rule 2: Prefer matching scope. */
8384c6867a8SHajimu UMEMOTO 	if (dst1->aio_dstscope == dst1->aio_srcscope &&
8394c6867a8SHajimu UMEMOTO 	    dst2->aio_dstscope != dst2->aio_srcscope) {
8404c6867a8SHajimu UMEMOTO 		return(-1);
8414c6867a8SHajimu UMEMOTO 	}
8424c6867a8SHajimu UMEMOTO 	if (dst1->aio_dstscope != dst1->aio_srcscope &&
8434c6867a8SHajimu UMEMOTO 	    dst2->aio_dstscope == dst2->aio_srcscope) {
8444c6867a8SHajimu UMEMOTO 		return(1);
8454c6867a8SHajimu UMEMOTO 	}
8464c6867a8SHajimu UMEMOTO 
8474c6867a8SHajimu UMEMOTO 	/* Rule 3: Avoid deprecated addresses. */
8484c6867a8SHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
8494c6867a8SHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
8504c6867a8SHajimu UMEMOTO 		if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
8514c6867a8SHajimu UMEMOTO 		    (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
8524c6867a8SHajimu UMEMOTO 			return(-1);
8534c6867a8SHajimu UMEMOTO 		}
8544c6867a8SHajimu UMEMOTO 		if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
8554c6867a8SHajimu UMEMOTO 		    !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
8564c6867a8SHajimu UMEMOTO 			return(1);
8574c6867a8SHajimu UMEMOTO 		}
8584c6867a8SHajimu UMEMOTO 	}
8594c6867a8SHajimu UMEMOTO 
8604c6867a8SHajimu UMEMOTO 	/* Rule 4: Prefer home addresses. */
8614c6867a8SHajimu UMEMOTO 	/* XXX: not implemented yet */
8624c6867a8SHajimu UMEMOTO 
8634c6867a8SHajimu UMEMOTO 	/* Rule 5: Prefer matching label. */
8644c6867a8SHajimu UMEMOTO #ifdef INET6
8654c6867a8SHajimu UMEMOTO 	if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
8664c6867a8SHajimu UMEMOTO 	    dst1->aio_srcpolicy->pc_policy.label ==
8674c6867a8SHajimu UMEMOTO 	    dst1->aio_dstpolicy->pc_policy.label &&
8684c6867a8SHajimu UMEMOTO 	    (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
8694c6867a8SHajimu UMEMOTO 	     dst2->aio_srcpolicy->pc_policy.label !=
8704c6867a8SHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.label)) {
8714c6867a8SHajimu UMEMOTO 		return(-1);
8724c6867a8SHajimu UMEMOTO 	}
8734c6867a8SHajimu UMEMOTO 	if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
8744c6867a8SHajimu UMEMOTO 	    dst2->aio_srcpolicy->pc_policy.label ==
8754c6867a8SHajimu UMEMOTO 	    dst2->aio_dstpolicy->pc_policy.label &&
8764c6867a8SHajimu UMEMOTO 	    (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
8774c6867a8SHajimu UMEMOTO 	     dst1->aio_srcpolicy->pc_policy.label !=
8784c6867a8SHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.label)) {
8794c6867a8SHajimu UMEMOTO 		return(1);
8804c6867a8SHajimu UMEMOTO 	}
8814c6867a8SHajimu UMEMOTO #endif
8824c6867a8SHajimu UMEMOTO 
8834c6867a8SHajimu UMEMOTO 	/* Rule 6: Prefer higher precedence. */
8844c6867a8SHajimu UMEMOTO #ifdef INET6
8854c6867a8SHajimu UMEMOTO 	if (dst1->aio_dstpolicy &&
8864c6867a8SHajimu UMEMOTO 	    (dst2->aio_dstpolicy == NULL ||
8874c6867a8SHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced >
8884c6867a8SHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced)) {
8894c6867a8SHajimu UMEMOTO 		return(-1);
8904c6867a8SHajimu UMEMOTO 	}
8914c6867a8SHajimu UMEMOTO 	if (dst2->aio_dstpolicy &&
8924c6867a8SHajimu UMEMOTO 	    (dst1->aio_dstpolicy == NULL ||
8934c6867a8SHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced >
8944c6867a8SHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced)) {
8954c6867a8SHajimu UMEMOTO 		return(1);
8964c6867a8SHajimu UMEMOTO 	}
8974c6867a8SHajimu UMEMOTO #endif
8984c6867a8SHajimu UMEMOTO 
8994c6867a8SHajimu UMEMOTO 	/* Rule 7: Prefer native transport. */
9004c6867a8SHajimu UMEMOTO 	/* XXX: not implemented yet */
9014c6867a8SHajimu UMEMOTO 
9024c6867a8SHajimu UMEMOTO 	/* Rule 8: Prefer smaller scope. */
9034c6867a8SHajimu UMEMOTO 	if (dst1->aio_dstscope >= 0 &&
9044c6867a8SHajimu UMEMOTO 	    dst1->aio_dstscope < dst2->aio_dstscope) {
9054c6867a8SHajimu UMEMOTO 		return(-1);
9064c6867a8SHajimu UMEMOTO 	}
9074c6867a8SHajimu UMEMOTO 	if (dst2->aio_dstscope >= 0 &&
9084c6867a8SHajimu UMEMOTO 	    dst2->aio_dstscope < dst1->aio_dstscope) {
9094c6867a8SHajimu UMEMOTO 		return(1);
9104c6867a8SHajimu UMEMOTO 	}
9114c6867a8SHajimu UMEMOTO 
9124c6867a8SHajimu UMEMOTO 	/*
9134c6867a8SHajimu UMEMOTO 	 * Rule 9: Use longest matching prefix.
9144c6867a8SHajimu UMEMOTO 	 * We compare the match length in a same AF only.
9154c6867a8SHajimu UMEMOTO 	 */
9164c6867a8SHajimu UMEMOTO 	if (dst1->aio_ai->ai_addr->sa_family ==
9174c6867a8SHajimu UMEMOTO 	    dst2->aio_ai->ai_addr->sa_family) {
9184c6867a8SHajimu UMEMOTO 		if (dst1->aio_matchlen > dst2->aio_matchlen) {
9194c6867a8SHajimu UMEMOTO 			return(-1);
9204c6867a8SHajimu UMEMOTO 		}
9214c6867a8SHajimu UMEMOTO 		if (dst1->aio_matchlen < dst2->aio_matchlen) {
9224c6867a8SHajimu UMEMOTO 			return(1);
9234c6867a8SHajimu UMEMOTO 		}
9244c6867a8SHajimu UMEMOTO 	}
9254c6867a8SHajimu UMEMOTO 
9264c6867a8SHajimu UMEMOTO 	/* Rule 10: Otherwise, leave the order unchanged. */
9274c6867a8SHajimu UMEMOTO 	return(-1);
9284c6867a8SHajimu UMEMOTO }
9294c6867a8SHajimu UMEMOTO 
9304c6867a8SHajimu UMEMOTO /*
9314c6867a8SHajimu UMEMOTO  * Copy from scope.c.
9324c6867a8SHajimu UMEMOTO  * XXX: we should standardize the functions and link them as standard
9334c6867a8SHajimu UMEMOTO  * library.
9344c6867a8SHajimu UMEMOTO  */
9354c6867a8SHajimu UMEMOTO static int
9364c6867a8SHajimu UMEMOTO gai_addr2scopetype(sa)
9374c6867a8SHajimu UMEMOTO 	struct sockaddr *sa;
9384c6867a8SHajimu UMEMOTO {
9394c6867a8SHajimu UMEMOTO #ifdef INET6
9404c6867a8SHajimu UMEMOTO 	struct sockaddr_in6 *sa6;
9414c6867a8SHajimu UMEMOTO #endif
9424c6867a8SHajimu UMEMOTO 	struct sockaddr_in *sa4;
9434c6867a8SHajimu UMEMOTO 
9444c6867a8SHajimu UMEMOTO 	switch(sa->sa_family) {
9454c6867a8SHajimu UMEMOTO #ifdef INET6
9464c6867a8SHajimu UMEMOTO 	case AF_INET6:
9474c6867a8SHajimu UMEMOTO 		sa6 = (struct sockaddr_in6 *)sa;
9484c6867a8SHajimu UMEMOTO 		if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
9494c6867a8SHajimu UMEMOTO 			/* just use the scope field of the multicast address */
9504c6867a8SHajimu UMEMOTO 			return(sa6->sin6_addr.s6_addr[2] & 0x0f);
9514c6867a8SHajimu UMEMOTO 		}
9524c6867a8SHajimu UMEMOTO 		/*
9534c6867a8SHajimu UMEMOTO 		 * Unicast addresses: map scope type to corresponding scope
9544c6867a8SHajimu UMEMOTO 		 * value defined for multcast addresses.
9554c6867a8SHajimu UMEMOTO 		 * XXX: hardcoded scope type values are bad...
9564c6867a8SHajimu UMEMOTO 		 */
9574c6867a8SHajimu UMEMOTO 		if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
9584c6867a8SHajimu UMEMOTO 			return(1); /* node local scope */
9594c6867a8SHajimu UMEMOTO 		if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
9604c6867a8SHajimu UMEMOTO 			return(2); /* link-local scope */
9614c6867a8SHajimu UMEMOTO 		if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
9624c6867a8SHajimu UMEMOTO 			return(5); /* site-local scope */
9634c6867a8SHajimu UMEMOTO 		return(14);	/* global scope */
9644c6867a8SHajimu UMEMOTO 		break;
9654c6867a8SHajimu UMEMOTO #endif
9664c6867a8SHajimu UMEMOTO 	case AF_INET:
9674c6867a8SHajimu UMEMOTO 		/*
9684c6867a8SHajimu UMEMOTO 		 * IPv4 pseudo scoping according to RFC 3484.
9694c6867a8SHajimu UMEMOTO 		 */
9704c6867a8SHajimu UMEMOTO 		sa4 = (struct sockaddr_in *)sa;
9714c6867a8SHajimu UMEMOTO 		/* IPv4 autoconfiguration addresses have link-local scope. */
9724c6867a8SHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 169 &&
9734c6867a8SHajimu UMEMOTO 		    ((u_char *)&sa4->sin_addr)[1] == 254)
9744c6867a8SHajimu UMEMOTO 			return(2);
9754c6867a8SHajimu UMEMOTO 		/* Private addresses have site-local scope. */
9764c6867a8SHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 10 ||
9774c6867a8SHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 172 &&
9784c6867a8SHajimu UMEMOTO 		     (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
9794c6867a8SHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 192 &&
9804c6867a8SHajimu UMEMOTO 		     ((u_char *)&sa4->sin_addr)[1] == 168))
9814c6867a8SHajimu UMEMOTO 			return(5);
9824c6867a8SHajimu UMEMOTO 		/* Loopback addresses have link-local scope. */
9834c6867a8SHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 127)
9844c6867a8SHajimu UMEMOTO 			return(2);
9854c6867a8SHajimu UMEMOTO 		return(14);
9864c6867a8SHajimu UMEMOTO 		break;
9874c6867a8SHajimu UMEMOTO 	default:
9884c6867a8SHajimu UMEMOTO 		errno = EAFNOSUPPORT; /* is this a good error? */
9894c6867a8SHajimu UMEMOTO 		return(-1);
9904c6867a8SHajimu UMEMOTO 	}
9914c6867a8SHajimu UMEMOTO }
9924c6867a8SHajimu UMEMOTO 
9937d56d374SYoshinobu Inoue /*
9947d56d374SYoshinobu Inoue  * hostname == NULL.
9957d56d374SYoshinobu Inoue  * passive socket -> anyaddr (0.0.0.0 or ::)
9967d56d374SYoshinobu Inoue  * non-passive socket -> localhost (127.0.0.1 or ::1)
9977d56d374SYoshinobu Inoue  */
9987d56d374SYoshinobu Inoue static int
999a42af91cSHajimu UMEMOTO explore_null(pai, servname, res)
10007d56d374SYoshinobu Inoue 	const struct addrinfo *pai;
10017d56d374SYoshinobu Inoue 	const char *servname;
10027d56d374SYoshinobu Inoue 	struct addrinfo **res;
10037d56d374SYoshinobu Inoue {
1004bf838688SHajimu UMEMOTO 	int s;
10057d56d374SYoshinobu Inoue 	const struct afd *afd;
10067d56d374SYoshinobu Inoue 	struct addrinfo *cur;
10077d56d374SYoshinobu Inoue 	struct addrinfo sentinel;
10087d56d374SYoshinobu Inoue 	int error;
10097d56d374SYoshinobu Inoue 
10107d56d374SYoshinobu Inoue 	*res = NULL;
10117d56d374SYoshinobu Inoue 	sentinel.ai_next = NULL;
10127d56d374SYoshinobu Inoue 	cur = &sentinel;
10137d56d374SYoshinobu Inoue 
10147d56d374SYoshinobu Inoue 	/*
1015bf838688SHajimu UMEMOTO 	 * filter out AFs that are not supported by the kernel
1016bf838688SHajimu UMEMOTO 	 * XXX errno?
1017bf838688SHajimu UMEMOTO 	 */
1018bf838688SHajimu UMEMOTO 	s = _socket(pai->ai_family, SOCK_DGRAM, 0);
1019bf838688SHajimu UMEMOTO 	if (s < 0) {
1020bf838688SHajimu UMEMOTO 		if (errno != EMFILE)
1021bf838688SHajimu UMEMOTO 			return 0;
1022bf838688SHajimu UMEMOTO 	} else
1023bf838688SHajimu UMEMOTO 		_close(s);
1024bf838688SHajimu UMEMOTO 
1025bf838688SHajimu UMEMOTO 	/*
1026a42af91cSHajimu UMEMOTO 	 * if the servname does not match socktype/protocol, ignore it.
1027a42af91cSHajimu UMEMOTO 	 */
1028a42af91cSHajimu UMEMOTO 	if (get_portmatch(pai, servname) != 0)
1029a42af91cSHajimu UMEMOTO 		return 0;
1030a42af91cSHajimu UMEMOTO 
10317d56d374SYoshinobu Inoue 	afd = find_afd(pai->ai_family);
10327d56d374SYoshinobu Inoue 	if (afd == NULL)
10337d56d374SYoshinobu Inoue 		return 0;
10347d56d374SYoshinobu Inoue 
1035a42af91cSHajimu UMEMOTO 	if (pai->ai_flags & AI_PASSIVE) {
1036a42af91cSHajimu UMEMOTO 		GET_AI(cur->ai_next, afd, afd->a_addrany);
10377d56d374SYoshinobu Inoue 		/* xxx meaningless?
10387d56d374SYoshinobu Inoue 		 * GET_CANONNAME(cur->ai_next, "anyaddr");
1039a42af91cSHajimu UMEMOTO 		 */
1040a42af91cSHajimu UMEMOTO 		GET_PORT(cur->ai_next, servname);
1041a42af91cSHajimu UMEMOTO 	} else {
1042a42af91cSHajimu UMEMOTO 		GET_AI(cur->ai_next, afd, afd->a_loopback);
1043a42af91cSHajimu UMEMOTO 		/* xxx meaningless?
10447d56d374SYoshinobu Inoue 		 * GET_CANONNAME(cur->ai_next, "localhost");
10457d56d374SYoshinobu Inoue 		 */
10467d56d374SYoshinobu Inoue 		GET_PORT(cur->ai_next, servname);
1047a42af91cSHajimu UMEMOTO 	}
1048a42af91cSHajimu UMEMOTO 	cur = cur->ai_next;
10497d56d374SYoshinobu Inoue 
10507d56d374SYoshinobu Inoue 	*res = sentinel.ai_next;
10517d56d374SYoshinobu Inoue 	return 0;
10527d56d374SYoshinobu Inoue 
10537d56d374SYoshinobu Inoue free:
10547d56d374SYoshinobu Inoue 	if (sentinel.ai_next)
10557d56d374SYoshinobu Inoue 		freeaddrinfo(sentinel.ai_next);
10567d56d374SYoshinobu Inoue 	return error;
10577d56d374SYoshinobu Inoue }
10587d56d374SYoshinobu Inoue 
10597d56d374SYoshinobu Inoue /*
10607d56d374SYoshinobu Inoue  * numeric hostname
10617d56d374SYoshinobu Inoue  */
10627d56d374SYoshinobu Inoue static int
1063bf838688SHajimu UMEMOTO explore_numeric(pai, hostname, servname, res)
10647d56d374SYoshinobu Inoue 	const struct addrinfo *pai;
10657d56d374SYoshinobu Inoue 	const char *hostname;
10667d56d374SYoshinobu Inoue 	const char *servname;
10677d56d374SYoshinobu Inoue 	struct addrinfo **res;
10687d56d374SYoshinobu Inoue {
10697d56d374SYoshinobu Inoue 	const struct afd *afd;
10707d56d374SYoshinobu Inoue 	struct addrinfo *cur;
10717d56d374SYoshinobu Inoue 	struct addrinfo sentinel;
10727d56d374SYoshinobu Inoue 	int error;
10737d56d374SYoshinobu Inoue 	char pton[PTON_MAX];
10747d56d374SYoshinobu Inoue 
10757d56d374SYoshinobu Inoue 	*res = NULL;
10767d56d374SYoshinobu Inoue 	sentinel.ai_next = NULL;
10777d56d374SYoshinobu Inoue 	cur = &sentinel;
10787d56d374SYoshinobu Inoue 
1079bf838688SHajimu UMEMOTO 	/*
1080bf838688SHajimu UMEMOTO 	 * if the servname does not match socktype/protocol, ignore it.
1081bf838688SHajimu UMEMOTO 	 */
1082bf838688SHajimu UMEMOTO 	if (get_portmatch(pai, servname) != 0)
1083bf838688SHajimu UMEMOTO 		return 0;
1084bf838688SHajimu UMEMOTO 
10857d56d374SYoshinobu Inoue 	afd = find_afd(pai->ai_family);
10867d56d374SYoshinobu Inoue 	if (afd == NULL)
10877d56d374SYoshinobu Inoue 		return 0;
10887d56d374SYoshinobu Inoue 
1089b826397aSJun-ichiro itojun Hagino 	switch (afd->a_af) {
1090b826397aSJun-ichiro itojun Hagino #if 1 /*X/Open spec*/
1091b826397aSJun-ichiro itojun Hagino 	case AF_INET:
1092b826397aSJun-ichiro itojun Hagino 		if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
10937d56d374SYoshinobu Inoue 			if (pai->ai_family == afd->a_af ||
10947d56d374SYoshinobu Inoue 			    pai->ai_family == PF_UNSPEC /*?*/) {
10957d56d374SYoshinobu Inoue 				GET_AI(cur->ai_next, afd, pton);
10967d56d374SYoshinobu Inoue 				GET_PORT(cur->ai_next, servname);
10977d56d374SYoshinobu Inoue 				while (cur && cur->ai_next)
10987d56d374SYoshinobu Inoue 					cur = cur->ai_next;
10997d56d374SYoshinobu Inoue 			} else
11007d56d374SYoshinobu Inoue 				ERR(EAI_FAMILY);	/*xxx*/
11017d56d374SYoshinobu Inoue 		}
1102b826397aSJun-ichiro itojun Hagino 		break;
1103b826397aSJun-ichiro itojun Hagino #endif
1104b826397aSJun-ichiro itojun Hagino 	default:
1105b826397aSJun-ichiro itojun Hagino 		if (inet_pton(afd->a_af, hostname, pton) == 1) {
1106b826397aSJun-ichiro itojun Hagino 			if (pai->ai_family == afd->a_af ||
1107b826397aSJun-ichiro itojun Hagino 			    pai->ai_family == PF_UNSPEC /*?*/) {
1108b826397aSJun-ichiro itojun Hagino 				GET_AI(cur->ai_next, afd, pton);
1109b826397aSJun-ichiro itojun Hagino 				GET_PORT(cur->ai_next, servname);
1110b826397aSJun-ichiro itojun Hagino 				while (cur && cur->ai_next)
1111b826397aSJun-ichiro itojun Hagino 					cur = cur->ai_next;
1112b826397aSJun-ichiro itojun Hagino 			} else
1113dd521ef1SHajimu UMEMOTO 				ERR(EAI_FAMILY);	/* XXX */
1114b826397aSJun-ichiro itojun Hagino 		}
1115b826397aSJun-ichiro itojun Hagino 		break;
1116b826397aSJun-ichiro itojun Hagino 	}
11177d56d374SYoshinobu Inoue 
11187d56d374SYoshinobu Inoue 	*res = sentinel.ai_next;
11197d56d374SYoshinobu Inoue 	return 0;
11207d56d374SYoshinobu Inoue 
11217d56d374SYoshinobu Inoue free:
11227d56d374SYoshinobu Inoue bad:
11237d56d374SYoshinobu Inoue 	if (sentinel.ai_next)
11247d56d374SYoshinobu Inoue 		freeaddrinfo(sentinel.ai_next);
11257d56d374SYoshinobu Inoue 	return error;
11267d56d374SYoshinobu Inoue }
11277d56d374SYoshinobu Inoue 
11287d56d374SYoshinobu Inoue /*
11297d56d374SYoshinobu Inoue  * numeric hostname with scope
11307d56d374SYoshinobu Inoue  */
11317d56d374SYoshinobu Inoue static int
11327d56d374SYoshinobu Inoue explore_numeric_scope(pai, hostname, servname, res)
11337d56d374SYoshinobu Inoue 	const struct addrinfo *pai;
11347d56d374SYoshinobu Inoue 	const char *hostname;
11357d56d374SYoshinobu Inoue 	const char *servname;
11367d56d374SYoshinobu Inoue 	struct addrinfo **res;
11377d56d374SYoshinobu Inoue {
1138a42af91cSHajimu UMEMOTO #if !defined(SCOPE_DELIMITER) || !defined(INET6)
1139bf838688SHajimu UMEMOTO 	return explore_numeric(pai, hostname, servname, res);
11407d56d374SYoshinobu Inoue #else
11417d56d374SYoshinobu Inoue 	const struct afd *afd;
11427d56d374SYoshinobu Inoue 	struct addrinfo *cur;
11437d56d374SYoshinobu Inoue 	int error;
1144a42af91cSHajimu UMEMOTO 	char *cp, *hostname2 = NULL, *scope, *addr;
11457d56d374SYoshinobu Inoue 	struct sockaddr_in6 *sin6;
11467d56d374SYoshinobu Inoue 
1147bf838688SHajimu UMEMOTO 	/*
1148bf838688SHajimu UMEMOTO 	 * if the servname does not match socktype/protocol, ignore it.
1149bf838688SHajimu UMEMOTO 	 */
1150bf838688SHajimu UMEMOTO 	if (get_portmatch(pai, servname) != 0)
1151bf838688SHajimu UMEMOTO 		return 0;
1152bf838688SHajimu UMEMOTO 
11537d56d374SYoshinobu Inoue 	afd = find_afd(pai->ai_family);
11547d56d374SYoshinobu Inoue 	if (afd == NULL)
11557d56d374SYoshinobu Inoue 		return 0;
1156248aee62SJacques Vidrine 
11577d56d374SYoshinobu Inoue 	if (!afd->a_scoped)
1158bf838688SHajimu UMEMOTO 		return explore_numeric(pai, hostname, servname, res);
11597d56d374SYoshinobu Inoue 
11607d56d374SYoshinobu Inoue 	cp = strchr(hostname, SCOPE_DELIMITER);
11617d56d374SYoshinobu Inoue 	if (cp == NULL)
1162bf838688SHajimu UMEMOTO 		return explore_numeric(pai, hostname, servname, res);
11637d56d374SYoshinobu Inoue 
11647d56d374SYoshinobu Inoue 	/*
11657d56d374SYoshinobu Inoue 	 * Handle special case of <scoped_address><delimiter><scope id>
11667d56d374SYoshinobu Inoue 	 */
11677d56d374SYoshinobu Inoue 	hostname2 = strdup(hostname);
11687d56d374SYoshinobu Inoue 	if (hostname2 == NULL)
11697d56d374SYoshinobu Inoue 		return EAI_MEMORY;
11707d56d374SYoshinobu Inoue 	/* terminate at the delimiter */
11717d56d374SYoshinobu Inoue 	hostname2[cp - hostname] = '\0';
1172a42af91cSHajimu UMEMOTO 	addr = hostname2;
1173a42af91cSHajimu UMEMOTO 	scope = cp + 1;
11747d56d374SYoshinobu Inoue 
1175bf838688SHajimu UMEMOTO 	error = explore_numeric(pai, addr, servname, res);
11767d56d374SYoshinobu Inoue 	if (error == 0) {
1177a89c1d30SHajimu UMEMOTO 		u_int32_t scopeid;
1178a42af91cSHajimu UMEMOTO 
11797d56d374SYoshinobu Inoue 		for (cur = *res; cur; cur = cur->ai_next) {
11807d56d374SYoshinobu Inoue 			if (cur->ai_family != AF_INET6)
11817d56d374SYoshinobu Inoue 				continue;
1182a42af91cSHajimu UMEMOTO 			sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
1183a89c1d30SHajimu UMEMOTO 			if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
1184a42af91cSHajimu UMEMOTO 				free(hostname2);
118537b3e941SHajimu UMEMOTO 				return(EAI_NONAME); /* XXX: is return OK? */
1186a42af91cSHajimu UMEMOTO 			}
1187a42af91cSHajimu UMEMOTO 			sin6->sin6_scope_id = scopeid;
11887d56d374SYoshinobu Inoue 		}
11897d56d374SYoshinobu Inoue 	}
11907d56d374SYoshinobu Inoue 
11917d56d374SYoshinobu Inoue 	free(hostname2);
11927d56d374SYoshinobu Inoue 
11937d56d374SYoshinobu Inoue 	return error;
11947d56d374SYoshinobu Inoue #endif
11957d56d374SYoshinobu Inoue }
11967d56d374SYoshinobu Inoue 
11977d56d374SYoshinobu Inoue static int
11987d56d374SYoshinobu Inoue get_canonname(pai, ai, str)
11997d56d374SYoshinobu Inoue 	const struct addrinfo *pai;
12007d56d374SYoshinobu Inoue 	struct addrinfo *ai;
12017d56d374SYoshinobu Inoue 	const char *str;
12027d56d374SYoshinobu Inoue {
12037d56d374SYoshinobu Inoue 	if ((pai->ai_flags & AI_CANONNAME) != 0) {
1204bf838688SHajimu UMEMOTO 		ai->ai_canonname = (char *)malloc(strlen(str) + 1);
12057d56d374SYoshinobu Inoue 		if (ai->ai_canonname == NULL)
12067d56d374SYoshinobu Inoue 			return EAI_MEMORY;
1207bf838688SHajimu UMEMOTO 		strlcpy(ai->ai_canonname, str, strlen(str) + 1);
12087d56d374SYoshinobu Inoue 	}
12097d56d374SYoshinobu Inoue 	return 0;
12107d56d374SYoshinobu Inoue }
12117d56d374SYoshinobu Inoue 
12127d56d374SYoshinobu Inoue static struct addrinfo *
12137d56d374SYoshinobu Inoue get_ai(pai, afd, addr)
12147d56d374SYoshinobu Inoue 	const struct addrinfo *pai;
12157d56d374SYoshinobu Inoue 	const struct afd *afd;
12167d56d374SYoshinobu Inoue 	const char *addr;
12177d56d374SYoshinobu Inoue {
12187d56d374SYoshinobu Inoue 	char *p;
12197d56d374SYoshinobu Inoue 	struct addrinfo *ai;
12207d56d374SYoshinobu Inoue #ifdef FAITH
12217d56d374SYoshinobu Inoue 	struct in6_addr faith_prefix;
12227d56d374SYoshinobu Inoue 	char *fp_str;
12237d56d374SYoshinobu Inoue 	int translate = 0;
12247d56d374SYoshinobu Inoue #endif
12257d56d374SYoshinobu Inoue 
12267d56d374SYoshinobu Inoue #ifdef FAITH
12277d56d374SYoshinobu Inoue 	/*
12287d56d374SYoshinobu Inoue 	 * Transfrom an IPv4 addr into a special IPv6 addr format for
12297d56d374SYoshinobu Inoue 	 * IPv6->IPv4 translation gateway. (only TCP is supported now)
12307d56d374SYoshinobu Inoue 	 *
12317d56d374SYoshinobu Inoue 	 * +-----------------------------------+------------+
12327d56d374SYoshinobu Inoue 	 * | faith prefix part (12 bytes)      | embedded   |
12337d56d374SYoshinobu Inoue 	 * |                                   | IPv4 addr part (4 bytes)
12347d56d374SYoshinobu Inoue 	 * +-----------------------------------+------------+
12357d56d374SYoshinobu Inoue 	 *
12367d56d374SYoshinobu Inoue 	 * faith prefix part is specified as ascii IPv6 addr format
12377d56d374SYoshinobu Inoue 	 * in environmental variable GAI.
12387d56d374SYoshinobu Inoue 	 * For FAITH to work correctly, routing to faith prefix must be
12397d56d374SYoshinobu Inoue 	 * setup toward a machine where a FAITH daemon operates.
12407d56d374SYoshinobu Inoue 	 * Also, the machine must enable some mechanizm
12417d56d374SYoshinobu Inoue 	 * (e.g. faith interface hack) to divert those packet with
12427d56d374SYoshinobu Inoue 	 * faith prefixed destination addr to user-land FAITH daemon.
12437d56d374SYoshinobu Inoue 	 */
12447d56d374SYoshinobu Inoue 	fp_str = getenv("GAI");
12457d56d374SYoshinobu Inoue 	if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 &&
12467d56d374SYoshinobu Inoue 	    afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) {
12477d56d374SYoshinobu Inoue 		u_int32_t v4a;
12487d56d374SYoshinobu Inoue 		u_int8_t v4a_top;
12497d56d374SYoshinobu Inoue 
12507d56d374SYoshinobu Inoue 		memcpy(&v4a, addr, sizeof v4a);
12517d56d374SYoshinobu Inoue 		v4a_top = v4a >> IN_CLASSA_NSHIFT;
12527d56d374SYoshinobu Inoue 		if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) &&
12537d56d374SYoshinobu Inoue 		    v4a_top != 0 && v4a != IN_LOOPBACKNET) {
12547d56d374SYoshinobu Inoue 			afd = &afdl[N_INET6];
12557d56d374SYoshinobu Inoue 			memcpy(&faith_prefix.s6_addr[12], addr,
12567d56d374SYoshinobu Inoue 			       sizeof(struct in_addr));
12577d56d374SYoshinobu Inoue 			translate = 1;
12587d56d374SYoshinobu Inoue 		}
12597d56d374SYoshinobu Inoue 	}
12607d56d374SYoshinobu Inoue #endif
12617d56d374SYoshinobu Inoue 
12627d56d374SYoshinobu Inoue 	ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
12637d56d374SYoshinobu Inoue 		+ (afd->a_socklen));
12647d56d374SYoshinobu Inoue 	if (ai == NULL)
12657d56d374SYoshinobu Inoue 		return NULL;
12667d56d374SYoshinobu Inoue 
12677d56d374SYoshinobu Inoue 	memcpy(ai, pai, sizeof(struct addrinfo));
1268a42af91cSHajimu UMEMOTO 	ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
1269a42af91cSHajimu UMEMOTO 	memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
12707d56d374SYoshinobu Inoue 	ai->ai_addr->sa_len = afd->a_socklen;
12717d56d374SYoshinobu Inoue 	ai->ai_addrlen = afd->a_socklen;
12727d56d374SYoshinobu Inoue 	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
1273248aee62SJacques Vidrine 	p = (char *)(void *)(ai->ai_addr);
12747d56d374SYoshinobu Inoue #ifdef FAITH
12757d56d374SYoshinobu Inoue 	if (translate == 1)
1276248aee62SJacques Vidrine 		memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
12777d56d374SYoshinobu Inoue 	else
12787d56d374SYoshinobu Inoue #endif
1279248aee62SJacques Vidrine 	memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
12807d56d374SYoshinobu Inoue 	return ai;
12817d56d374SYoshinobu Inoue }
12827d56d374SYoshinobu Inoue 
12837d56d374SYoshinobu Inoue static int
12847d56d374SYoshinobu Inoue get_portmatch(ai, servname)
12857d56d374SYoshinobu Inoue 	const struct addrinfo *ai;
12867d56d374SYoshinobu Inoue 	const char *servname;
12877d56d374SYoshinobu Inoue {
1288a42af91cSHajimu UMEMOTO 
12897d56d374SYoshinobu Inoue 	/* get_port does not touch first argument. when matchonly == 1. */
1290a42af91cSHajimu UMEMOTO 	/* LINTED const cast */
12917d56d374SYoshinobu Inoue 	return get_port((struct addrinfo *)ai, servname, 1);
12927d56d374SYoshinobu Inoue }
12937d56d374SYoshinobu Inoue 
12947d56d374SYoshinobu Inoue static int
12957d56d374SYoshinobu Inoue get_port(ai, servname, matchonly)
12967d56d374SYoshinobu Inoue 	struct addrinfo *ai;
12977d56d374SYoshinobu Inoue 	const char *servname;
12987d56d374SYoshinobu Inoue 	int matchonly;
12997d56d374SYoshinobu Inoue {
13007d56d374SYoshinobu Inoue 	const char *proto;
13017d56d374SYoshinobu Inoue 	struct servent *sp;
13027d56d374SYoshinobu Inoue 	int port;
13037d56d374SYoshinobu Inoue 	int allownumeric;
13047d56d374SYoshinobu Inoue 
13057d56d374SYoshinobu Inoue 	if (servname == NULL)
13067d56d374SYoshinobu Inoue 		return 0;
1307a42af91cSHajimu UMEMOTO 	switch (ai->ai_family) {
1308a42af91cSHajimu UMEMOTO 	case AF_INET:
1309a42af91cSHajimu UMEMOTO #ifdef AF_INET6
1310a42af91cSHajimu UMEMOTO 	case AF_INET6:
13117d56d374SYoshinobu Inoue #endif
1312a42af91cSHajimu UMEMOTO 		break;
1313a42af91cSHajimu UMEMOTO 	default:
13147d56d374SYoshinobu Inoue 		return 0;
1315a42af91cSHajimu UMEMOTO 	}
13167d56d374SYoshinobu Inoue 
13177d56d374SYoshinobu Inoue 	switch (ai->ai_socktype) {
13187d56d374SYoshinobu Inoue 	case SOCK_RAW:
13197d56d374SYoshinobu Inoue 		return EAI_SERVICE;
13207d56d374SYoshinobu Inoue 	case SOCK_DGRAM:
13217d56d374SYoshinobu Inoue 	case SOCK_STREAM:
13227d56d374SYoshinobu Inoue 		allownumeric = 1;
13237d56d374SYoshinobu Inoue 		break;
13247d56d374SYoshinobu Inoue 	case ANY:
13257d56d374SYoshinobu Inoue 		allownumeric = 0;
13267d56d374SYoshinobu Inoue 		break;
13277d56d374SYoshinobu Inoue 	default:
13287d56d374SYoshinobu Inoue 		return EAI_SOCKTYPE;
13297d56d374SYoshinobu Inoue 	}
13307d56d374SYoshinobu Inoue 
13317d56d374SYoshinobu Inoue 	if (str_isnumber(servname)) {
13327d56d374SYoshinobu Inoue 		if (!allownumeric)
13337d56d374SYoshinobu Inoue 			return EAI_SERVICE;
1334dd521ef1SHajimu UMEMOTO 		port = atoi(servname);
13357d56d374SYoshinobu Inoue 		if (port < 0 || port > 65535)
13367d56d374SYoshinobu Inoue 			return EAI_SERVICE;
1337dd521ef1SHajimu UMEMOTO 		port = htons(port);
13387d56d374SYoshinobu Inoue 	} else {
1339bf838688SHajimu UMEMOTO 		switch (ai->ai_socktype) {
1340bf838688SHajimu UMEMOTO 		case SOCK_DGRAM:
13417d56d374SYoshinobu Inoue 			proto = "udp";
13427d56d374SYoshinobu Inoue 			break;
1343bf838688SHajimu UMEMOTO 		case SOCK_STREAM:
13447d56d374SYoshinobu Inoue 			proto = "tcp";
13457d56d374SYoshinobu Inoue 			break;
13467d56d374SYoshinobu Inoue 		default:
13477d56d374SYoshinobu Inoue 			proto = NULL;
13487d56d374SYoshinobu Inoue 			break;
13497d56d374SYoshinobu Inoue 		}
13507d56d374SYoshinobu Inoue 
135133dee819SBrian Feldman 		THREAD_LOCK();
135233dee819SBrian Feldman 		if ((sp = getservbyname(servname, proto)) == NULL) {
135333dee819SBrian Feldman 			THREAD_UNLOCK();
13547d56d374SYoshinobu Inoue 			return EAI_SERVICE;
135533dee819SBrian Feldman 		}
13567d56d374SYoshinobu Inoue 		port = sp->s_port;
135733dee819SBrian Feldman 		THREAD_UNLOCK();
13587d56d374SYoshinobu Inoue 	}
13597d56d374SYoshinobu Inoue 
13607d56d374SYoshinobu Inoue 	if (!matchonly) {
13617d56d374SYoshinobu Inoue 		switch (ai->ai_family) {
13627d56d374SYoshinobu Inoue 		case AF_INET:
1363a42af91cSHajimu UMEMOTO 			((struct sockaddr_in *)(void *)
1364a42af91cSHajimu UMEMOTO 			    ai->ai_addr)->sin_port = port;
13657d56d374SYoshinobu Inoue 			break;
13667d56d374SYoshinobu Inoue #ifdef INET6
13677d56d374SYoshinobu Inoue 		case AF_INET6:
1368a42af91cSHajimu UMEMOTO 			((struct sockaddr_in6 *)(void *)
1369a42af91cSHajimu UMEMOTO 			    ai->ai_addr)->sin6_port = port;
13707d56d374SYoshinobu Inoue 			break;
13717d56d374SYoshinobu Inoue #endif
13727d56d374SYoshinobu Inoue 		}
13737d56d374SYoshinobu Inoue 	}
13747d56d374SYoshinobu Inoue 
13757d56d374SYoshinobu Inoue 	return 0;
13767d56d374SYoshinobu Inoue }
13777d56d374SYoshinobu Inoue 
13787d56d374SYoshinobu Inoue static const struct afd *
13797d56d374SYoshinobu Inoue find_afd(af)
13807d56d374SYoshinobu Inoue 	int af;
13817d56d374SYoshinobu Inoue {
13827d56d374SYoshinobu Inoue 	const struct afd *afd;
13837d56d374SYoshinobu Inoue 
13847d56d374SYoshinobu Inoue 	if (af == PF_UNSPEC)
13857d56d374SYoshinobu Inoue 		return NULL;
13867d56d374SYoshinobu Inoue 	for (afd = afdl; afd->a_af; afd++) {
13877d56d374SYoshinobu Inoue 		if (afd->a_af == af)
13887d56d374SYoshinobu Inoue 			return afd;
13897d56d374SYoshinobu Inoue 	}
13907d56d374SYoshinobu Inoue 	return NULL;
13917d56d374SYoshinobu Inoue }
1392a42af91cSHajimu UMEMOTO 
1393a42af91cSHajimu UMEMOTO /*
1394a42af91cSHajimu UMEMOTO  * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
1395a42af91cSHajimu UMEMOTO  * will take care of it.
1396a42af91cSHajimu UMEMOTO  * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
1397a42af91cSHajimu UMEMOTO  * if the code is right or not.
1398bf838688SHajimu UMEMOTO  *
1399bf838688SHajimu UMEMOTO  * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
1400bf838688SHajimu UMEMOTO  * _dns_getaddrinfo.
1401a42af91cSHajimu UMEMOTO  */
1402a42af91cSHajimu UMEMOTO static int
1403bf838688SHajimu UMEMOTO addrconfig(pai)
1404bf838688SHajimu UMEMOTO 	struct addrinfo *pai;
1405a42af91cSHajimu UMEMOTO {
1406bf838688SHajimu UMEMOTO 	int s, af;
1407a42af91cSHajimu UMEMOTO 
1408bf838688SHajimu UMEMOTO 	/*
1409bf838688SHajimu UMEMOTO 	 * TODO:
1410bf838688SHajimu UMEMOTO 	 * Note that implementation dependent test for address
1411bf838688SHajimu UMEMOTO 	 * configuration should be done everytime called
1412bf838688SHajimu UMEMOTO 	 * (or apropriate interval),
1413bf838688SHajimu UMEMOTO 	 * because addresses will be dynamically assigned or deleted.
1414bf838688SHajimu UMEMOTO 	 */
1415bf838688SHajimu UMEMOTO 	af = pai->ai_family;
1416bf838688SHajimu UMEMOTO 	if (af == AF_UNSPEC) {
1417bf838688SHajimu UMEMOTO 		if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1418bf838688SHajimu UMEMOTO 			af = AF_INET;
1419bf838688SHajimu UMEMOTO 		else {
1420bf838688SHajimu UMEMOTO 			_close(s);
1421bf838688SHajimu UMEMOTO 			if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1422bf838688SHajimu UMEMOTO 				af = AF_INET6;
1423bf838688SHajimu UMEMOTO 			else
1424bf838688SHajimu UMEMOTO 				_close(s);
1425bf838688SHajimu UMEMOTO 		}
1426bf838688SHajimu UMEMOTO 	}
1427bf838688SHajimu UMEMOTO 	if (af != AF_UNSPEC) {
1428bf838688SHajimu UMEMOTO 		if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
1429a42af91cSHajimu UMEMOTO 			return 0;
1430bf838688SHajimu UMEMOTO 		_close(s);
1431bf838688SHajimu UMEMOTO 	}
1432bf838688SHajimu UMEMOTO 	pai->ai_family = af;
1433a42af91cSHajimu UMEMOTO 	return 1;
1434a42af91cSHajimu UMEMOTO }
1435a42af91cSHajimu UMEMOTO 
1436a42af91cSHajimu UMEMOTO #ifdef INET6
1437a42af91cSHajimu UMEMOTO /* convert a string to a scope identifier. XXX: IPv6 specific */
1438a42af91cSHajimu UMEMOTO static int
1439a89c1d30SHajimu UMEMOTO ip6_str2scopeid(scope, sin6, scopeid)
1440a42af91cSHajimu UMEMOTO 	char *scope;
1441a42af91cSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
1442a89c1d30SHajimu UMEMOTO 	u_int32_t *scopeid;
1443a42af91cSHajimu UMEMOTO {
1444a89c1d30SHajimu UMEMOTO 	u_long lscopeid;
1445bf838688SHajimu UMEMOTO 	struct in6_addr *a6;
1446a42af91cSHajimu UMEMOTO 	char *ep;
1447a42af91cSHajimu UMEMOTO 
1448bf838688SHajimu UMEMOTO 	a6 = &sin6->sin6_addr;
1449bf838688SHajimu UMEMOTO 
1450ec20fe00SJun-ichiro itojun Hagino 	/* empty scopeid portion is invalid */
1451ec20fe00SJun-ichiro itojun Hagino 	if (*scope == '\0')
1452ec20fe00SJun-ichiro itojun Hagino 		return -1;
1453ec20fe00SJun-ichiro itojun Hagino 
1454bf838688SHajimu UMEMOTO 	if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1455a42af91cSHajimu UMEMOTO 		/*
1456a42af91cSHajimu UMEMOTO 		 * We currently assume a one-to-one mapping between links
1457a42af91cSHajimu UMEMOTO 		 * and interfaces, so we simply use interface indices for
1458a42af91cSHajimu UMEMOTO 		 * like-local scopes.
1459a42af91cSHajimu UMEMOTO 		 */
1460a89c1d30SHajimu UMEMOTO 		*scopeid = if_nametoindex(scope);
1461a89c1d30SHajimu UMEMOTO 		if (*scopeid == 0)
1462a42af91cSHajimu UMEMOTO 			goto trynumeric;
1463a89c1d30SHajimu UMEMOTO 		return 0;
1464a42af91cSHajimu UMEMOTO 	}
1465a42af91cSHajimu UMEMOTO 
1466a42af91cSHajimu UMEMOTO 	/* still unclear about literal, allow numeric only - placeholder */
1467a42af91cSHajimu UMEMOTO 	if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1468a42af91cSHajimu UMEMOTO 		goto trynumeric;
1469a42af91cSHajimu UMEMOTO 	if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1470a42af91cSHajimu UMEMOTO 		goto trynumeric;
1471a42af91cSHajimu UMEMOTO 	else
1472a42af91cSHajimu UMEMOTO 		goto trynumeric;	/* global */
1473a42af91cSHajimu UMEMOTO 
1474a42af91cSHajimu UMEMOTO 	/* try to convert to a numeric id as a last resort */
1475a42af91cSHajimu UMEMOTO   trynumeric:
1476a89c1d30SHajimu UMEMOTO 	errno = 0;
1477a89c1d30SHajimu UMEMOTO 	lscopeid = strtoul(scope, &ep, 10);
1478a89c1d30SHajimu UMEMOTO 	*scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1479a89c1d30SHajimu UMEMOTO 	if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1480a89c1d30SHajimu UMEMOTO 		return 0;
1481a42af91cSHajimu UMEMOTO 	else
1482a42af91cSHajimu UMEMOTO 		return -1;
1483a42af91cSHajimu UMEMOTO }
1484a42af91cSHajimu UMEMOTO #endif
1485a42af91cSHajimu UMEMOTO 
1486688a5c3eSHajimu UMEMOTO /*
1487688a5c3eSHajimu UMEMOTO  * FQDN hostname, DNS lookup
1488688a5c3eSHajimu UMEMOTO  */
1489688a5c3eSHajimu UMEMOTO static int
1490688a5c3eSHajimu UMEMOTO explore_fqdn(pai, hostname, servname, res)
1491688a5c3eSHajimu UMEMOTO 	const struct addrinfo *pai;
1492688a5c3eSHajimu UMEMOTO 	const char *hostname;
1493688a5c3eSHajimu UMEMOTO 	const char *servname;
1494688a5c3eSHajimu UMEMOTO 	struct addrinfo **res;
1495688a5c3eSHajimu UMEMOTO {
1496688a5c3eSHajimu UMEMOTO 	struct addrinfo *result;
1497688a5c3eSHajimu UMEMOTO 	struct addrinfo *cur;
1498688a5c3eSHajimu UMEMOTO 	int error = 0;
1499688a5c3eSHajimu UMEMOTO 	static const ns_dtab dtab[] = {
1500688a5c3eSHajimu UMEMOTO 		NS_FILES_CB(_files_getaddrinfo, NULL)
1501688a5c3eSHajimu UMEMOTO 		{ NSSRC_DNS, _dns_getaddrinfo, NULL },	/* force -DHESIOD */
1502688a5c3eSHajimu UMEMOTO 		NS_NIS_CB(_yp_getaddrinfo, NULL)
1503688a5c3eSHajimu UMEMOTO 		{ 0 }
150469b0a4b6SJim Pirzyk 	};
150569b0a4b6SJim Pirzyk 
1506688a5c3eSHajimu UMEMOTO 	result = NULL;
150769b0a4b6SJim Pirzyk 
1508688a5c3eSHajimu UMEMOTO 	/*
1509688a5c3eSHajimu UMEMOTO 	 * if the servname does not match socktype/protocol, ignore it.
1510688a5c3eSHajimu UMEMOTO 	 */
151133dee819SBrian Feldman 	if (get_portmatch(pai, servname) != 0)
151269b0a4b6SJim Pirzyk 		return 0;
151369b0a4b6SJim Pirzyk 
1514688a5c3eSHajimu UMEMOTO 	switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
1515688a5c3eSHajimu UMEMOTO 			default_dns_files, hostname, pai)) {
1516688a5c3eSHajimu UMEMOTO 	case NS_TRYAGAIN:
1517688a5c3eSHajimu UMEMOTO 		error = EAI_AGAIN;
1518688a5c3eSHajimu UMEMOTO 		goto free;
1519688a5c3eSHajimu UMEMOTO 	case NS_UNAVAIL:
1520688a5c3eSHajimu UMEMOTO 		error = EAI_FAIL;
1521688a5c3eSHajimu UMEMOTO 		goto free;
1522688a5c3eSHajimu UMEMOTO 	case NS_NOTFOUND:
1523688a5c3eSHajimu UMEMOTO 		error = EAI_NONAME;
1524688a5c3eSHajimu UMEMOTO 		goto free;
1525688a5c3eSHajimu UMEMOTO 	case NS_SUCCESS:
1526688a5c3eSHajimu UMEMOTO 		error = 0;
1527688a5c3eSHajimu UMEMOTO 		for (cur = result; cur; cur = cur->ai_next) {
1528688a5c3eSHajimu UMEMOTO 			GET_PORT(cur, servname);
1529688a5c3eSHajimu UMEMOTO 			/* canonname should be filled already */
1530688a5c3eSHajimu UMEMOTO 		}
153169b0a4b6SJim Pirzyk 		break;
153269b0a4b6SJim Pirzyk 	}
153369b0a4b6SJim Pirzyk 
1534688a5c3eSHajimu UMEMOTO 	*res = result;
1535688a5c3eSHajimu UMEMOTO 
153669b0a4b6SJim Pirzyk 	return 0;
1537688a5c3eSHajimu UMEMOTO 
1538688a5c3eSHajimu UMEMOTO free:
1539688a5c3eSHajimu UMEMOTO 	if (result)
1540688a5c3eSHajimu UMEMOTO 		freeaddrinfo(result);
1541688a5c3eSHajimu UMEMOTO 	return error;
154269b0a4b6SJim Pirzyk }
154369b0a4b6SJim Pirzyk 
1544a42af91cSHajimu UMEMOTO #ifdef DEBUG
1545a42af91cSHajimu UMEMOTO static const char AskedForGot[] =
1546a42af91cSHajimu UMEMOTO 	"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1547a42af91cSHajimu UMEMOTO #endif
1548248aee62SJacques Vidrine static FILE *hostf = NULL;
1549a42af91cSHajimu UMEMOTO 
1550a42af91cSHajimu UMEMOTO static struct addrinfo *
1551a42af91cSHajimu UMEMOTO getanswer(answer, anslen, qname, qtype, pai)
1552a42af91cSHajimu UMEMOTO 	const querybuf *answer;
1553a42af91cSHajimu UMEMOTO 	int anslen;
1554a42af91cSHajimu UMEMOTO 	const char *qname;
1555a42af91cSHajimu UMEMOTO 	int qtype;
1556a42af91cSHajimu UMEMOTO 	const struct addrinfo *pai;
1557a42af91cSHajimu UMEMOTO {
1558a42af91cSHajimu UMEMOTO 	struct addrinfo sentinel, *cur;
1559a42af91cSHajimu UMEMOTO 	struct addrinfo ai;
1560a42af91cSHajimu UMEMOTO 	const struct afd *afd;
1561a42af91cSHajimu UMEMOTO 	char *canonname;
1562a42af91cSHajimu UMEMOTO 	const HEADER *hp;
1563a42af91cSHajimu UMEMOTO 	const u_char *cp;
1564a42af91cSHajimu UMEMOTO 	int n;
1565a42af91cSHajimu UMEMOTO 	const u_char *eom;
1566dd521ef1SHajimu UMEMOTO 	char *bp, *ep;
1567dd521ef1SHajimu UMEMOTO 	int type, class, ancount, qdcount;
1568a42af91cSHajimu UMEMOTO 	int haveanswer, had_error;
1569a42af91cSHajimu UMEMOTO 	char tbuf[MAXDNAME];
1570c05ac53bSDavid E. O'Brien 	int (*name_ok)(const char *);
1571a42af91cSHajimu UMEMOTO 	char hostbuf[8*1024];
1572a42af91cSHajimu UMEMOTO 
1573a42af91cSHajimu UMEMOTO 	memset(&sentinel, 0, sizeof(sentinel));
1574a42af91cSHajimu UMEMOTO 	cur = &sentinel;
1575a42af91cSHajimu UMEMOTO 
1576a42af91cSHajimu UMEMOTO 	canonname = NULL;
1577a42af91cSHajimu UMEMOTO 	eom = answer->buf + anslen;
1578a42af91cSHajimu UMEMOTO 	switch (qtype) {
1579a42af91cSHajimu UMEMOTO 	case T_A:
1580a42af91cSHajimu UMEMOTO 	case T_AAAA:
1581a42af91cSHajimu UMEMOTO 	case T_ANY:	/*use T_ANY only for T_A/T_AAAA lookup*/
1582a42af91cSHajimu UMEMOTO 		name_ok = res_hnok;
1583a42af91cSHajimu UMEMOTO 		break;
1584a42af91cSHajimu UMEMOTO 	default:
1585a42af91cSHajimu UMEMOTO 		return (NULL);	/* XXX should be abort(); */
1586a42af91cSHajimu UMEMOTO 	}
1587a42af91cSHajimu UMEMOTO 	/*
1588a42af91cSHajimu UMEMOTO 	 * find first satisfactory answer
1589a42af91cSHajimu UMEMOTO 	 */
1590a42af91cSHajimu UMEMOTO 	hp = &answer->hdr;
1591a42af91cSHajimu UMEMOTO 	ancount = ntohs(hp->ancount);
1592a42af91cSHajimu UMEMOTO 	qdcount = ntohs(hp->qdcount);
1593a42af91cSHajimu UMEMOTO 	bp = hostbuf;
1594dd521ef1SHajimu UMEMOTO 	ep = hostbuf + sizeof hostbuf;
1595a42af91cSHajimu UMEMOTO 	cp = answer->buf + HFIXEDSZ;
1596a42af91cSHajimu UMEMOTO 	if (qdcount != 1) {
1597a42af91cSHajimu UMEMOTO 		h_errno = NO_RECOVERY;
1598a42af91cSHajimu UMEMOTO 		return (NULL);
1599a42af91cSHajimu UMEMOTO 	}
1600dd521ef1SHajimu UMEMOTO 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1601a42af91cSHajimu UMEMOTO 	if ((n < 0) || !(*name_ok)(bp)) {
1602a42af91cSHajimu UMEMOTO 		h_errno = NO_RECOVERY;
1603a42af91cSHajimu UMEMOTO 		return (NULL);
1604a42af91cSHajimu UMEMOTO 	}
1605a42af91cSHajimu UMEMOTO 	cp += n + QFIXEDSZ;
1606a42af91cSHajimu UMEMOTO 	if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1607a42af91cSHajimu UMEMOTO 		/* res_send() has already verified that the query name is the
1608a42af91cSHajimu UMEMOTO 		 * same as the one we sent; this just gets the expanded name
1609a42af91cSHajimu UMEMOTO 		 * (i.e., with the succeeding search-domain tacked on).
1610a42af91cSHajimu UMEMOTO 		 */
1611a42af91cSHajimu UMEMOTO 		n = strlen(bp) + 1;		/* for the \0 */
1612a42af91cSHajimu UMEMOTO 		if (n >= MAXHOSTNAMELEN) {
1613a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
1614a42af91cSHajimu UMEMOTO 			return (NULL);
1615a42af91cSHajimu UMEMOTO 		}
1616a42af91cSHajimu UMEMOTO 		canonname = bp;
1617a42af91cSHajimu UMEMOTO 		bp += n;
1618a42af91cSHajimu UMEMOTO 		/* The qname can be abbreviated, but h_name is now absolute. */
1619a42af91cSHajimu UMEMOTO 		qname = canonname;
1620a42af91cSHajimu UMEMOTO 	}
1621a42af91cSHajimu UMEMOTO 	haveanswer = 0;
1622a42af91cSHajimu UMEMOTO 	had_error = 0;
1623a42af91cSHajimu UMEMOTO 	while (ancount-- > 0 && cp < eom && !had_error) {
1624dd521ef1SHajimu UMEMOTO 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1625a42af91cSHajimu UMEMOTO 		if ((n < 0) || !(*name_ok)(bp)) {
1626a42af91cSHajimu UMEMOTO 			had_error++;
1627a42af91cSHajimu UMEMOTO 			continue;
1628a42af91cSHajimu UMEMOTO 		}
1629a42af91cSHajimu UMEMOTO 		cp += n;			/* name */
1630a42af91cSHajimu UMEMOTO 		type = _getshort(cp);
1631a42af91cSHajimu UMEMOTO  		cp += INT16SZ;			/* type */
1632a42af91cSHajimu UMEMOTO 		class = _getshort(cp);
1633a42af91cSHajimu UMEMOTO  		cp += INT16SZ + INT32SZ;	/* class, TTL */
1634a42af91cSHajimu UMEMOTO 		n = _getshort(cp);
1635a42af91cSHajimu UMEMOTO 		cp += INT16SZ;			/* len */
1636a42af91cSHajimu UMEMOTO 		if (class != C_IN) {
1637a42af91cSHajimu UMEMOTO 			/* XXX - debug? syslog? */
1638a42af91cSHajimu UMEMOTO 			cp += n;
1639a42af91cSHajimu UMEMOTO 			continue;		/* XXX - had_error++ ? */
1640a42af91cSHajimu UMEMOTO 		}
1641a42af91cSHajimu UMEMOTO 		if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1642a42af91cSHajimu UMEMOTO 		    type == T_CNAME) {
1643a42af91cSHajimu UMEMOTO 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1644a42af91cSHajimu UMEMOTO 			if ((n < 0) || !(*name_ok)(tbuf)) {
1645a42af91cSHajimu UMEMOTO 				had_error++;
1646a42af91cSHajimu UMEMOTO 				continue;
1647a42af91cSHajimu UMEMOTO 			}
1648a42af91cSHajimu UMEMOTO 			cp += n;
1649a42af91cSHajimu UMEMOTO 			/* Get canonical name. */
1650a42af91cSHajimu UMEMOTO 			n = strlen(tbuf) + 1;	/* for the \0 */
1651dd521ef1SHajimu UMEMOTO 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1652a42af91cSHajimu UMEMOTO 				had_error++;
1653a42af91cSHajimu UMEMOTO 				continue;
1654a42af91cSHajimu UMEMOTO 			}
1655d0509082SJacques Vidrine 			strlcpy(bp, tbuf, ep - bp);
1656a42af91cSHajimu UMEMOTO 			canonname = bp;
1657a42af91cSHajimu UMEMOTO 			bp += n;
1658a42af91cSHajimu UMEMOTO 			continue;
1659a42af91cSHajimu UMEMOTO 		}
1660a42af91cSHajimu UMEMOTO 		if (qtype == T_ANY) {
1661a42af91cSHajimu UMEMOTO 			if (!(type == T_A || type == T_AAAA)) {
1662a42af91cSHajimu UMEMOTO 				cp += n;
1663a42af91cSHajimu UMEMOTO 				continue;
1664a42af91cSHajimu UMEMOTO 			}
1665a42af91cSHajimu UMEMOTO 		} else if (type != qtype) {
1666a42af91cSHajimu UMEMOTO #ifdef DEBUG
1667a42af91cSHajimu UMEMOTO 			if (type != T_KEY && type != T_SIG)
1668a42af91cSHajimu UMEMOTO 				syslog(LOG_NOTICE|LOG_AUTH,
1669a42af91cSHajimu UMEMOTO 	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1670a42af91cSHajimu UMEMOTO 				       qname, p_class(C_IN), p_type(qtype),
1671a42af91cSHajimu UMEMOTO 				       p_type(type));
1672a42af91cSHajimu UMEMOTO #endif
1673a42af91cSHajimu UMEMOTO 			cp += n;
1674a42af91cSHajimu UMEMOTO 			continue;		/* XXX - had_error++ ? */
1675a42af91cSHajimu UMEMOTO 		}
1676a42af91cSHajimu UMEMOTO 		switch (type) {
1677a42af91cSHajimu UMEMOTO 		case T_A:
1678a42af91cSHajimu UMEMOTO 		case T_AAAA:
1679a42af91cSHajimu UMEMOTO 			if (strcasecmp(canonname, bp) != 0) {
1680a42af91cSHajimu UMEMOTO #ifdef DEBUG
1681a42af91cSHajimu UMEMOTO 				syslog(LOG_NOTICE|LOG_AUTH,
1682a42af91cSHajimu UMEMOTO 				       AskedForGot, canonname, bp);
1683a42af91cSHajimu UMEMOTO #endif
1684a42af91cSHajimu UMEMOTO 				cp += n;
1685a42af91cSHajimu UMEMOTO 				continue;	/* XXX - had_error++ ? */
1686a42af91cSHajimu UMEMOTO 			}
1687a42af91cSHajimu UMEMOTO 			if (type == T_A && n != INADDRSZ) {
1688a42af91cSHajimu UMEMOTO 				cp += n;
1689a42af91cSHajimu UMEMOTO 				continue;
1690a42af91cSHajimu UMEMOTO 			}
1691a42af91cSHajimu UMEMOTO 			if (type == T_AAAA && n != IN6ADDRSZ) {
1692a42af91cSHajimu UMEMOTO 				cp += n;
1693a42af91cSHajimu UMEMOTO 				continue;
1694a42af91cSHajimu UMEMOTO 			}
1695a42af91cSHajimu UMEMOTO #ifdef FILTER_V4MAPPED
1696a42af91cSHajimu UMEMOTO 			if (type == T_AAAA) {
1697a42af91cSHajimu UMEMOTO 				struct in6_addr in6;
1698a42af91cSHajimu UMEMOTO 				memcpy(&in6, cp, sizeof(in6));
1699a42af91cSHajimu UMEMOTO 				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1700a42af91cSHajimu UMEMOTO 					cp += n;
1701a42af91cSHajimu UMEMOTO 					continue;
1702a42af91cSHajimu UMEMOTO 				}
1703a42af91cSHajimu UMEMOTO 			}
1704a42af91cSHajimu UMEMOTO #endif
1705a42af91cSHajimu UMEMOTO 			if (!haveanswer) {
1706a42af91cSHajimu UMEMOTO 				int nn;
1707a42af91cSHajimu UMEMOTO 
1708a42af91cSHajimu UMEMOTO 				canonname = bp;
1709a42af91cSHajimu UMEMOTO 				nn = strlen(bp) + 1;	/* for the \0 */
1710a42af91cSHajimu UMEMOTO 				bp += nn;
1711a42af91cSHajimu UMEMOTO 			}
1712a42af91cSHajimu UMEMOTO 
1713a42af91cSHajimu UMEMOTO 			/* don't overwrite pai */
1714a42af91cSHajimu UMEMOTO 			ai = *pai;
1715a42af91cSHajimu UMEMOTO 			ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1716a42af91cSHajimu UMEMOTO 			afd = find_afd(ai.ai_family);
1717a42af91cSHajimu UMEMOTO 			if (afd == NULL) {
1718a42af91cSHajimu UMEMOTO 				cp += n;
1719a42af91cSHajimu UMEMOTO 				continue;
1720a42af91cSHajimu UMEMOTO 			}
1721a42af91cSHajimu UMEMOTO 			cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1722a42af91cSHajimu UMEMOTO 			if (cur->ai_next == NULL)
1723a42af91cSHajimu UMEMOTO 				had_error++;
1724a42af91cSHajimu UMEMOTO 			while (cur && cur->ai_next)
1725a42af91cSHajimu UMEMOTO 				cur = cur->ai_next;
1726a42af91cSHajimu UMEMOTO 			cp += n;
1727a42af91cSHajimu UMEMOTO 			break;
1728a42af91cSHajimu UMEMOTO 		default:
1729a42af91cSHajimu UMEMOTO 			abort();
1730a42af91cSHajimu UMEMOTO 		}
1731a42af91cSHajimu UMEMOTO 		if (!had_error)
1732a42af91cSHajimu UMEMOTO 			haveanswer++;
1733a42af91cSHajimu UMEMOTO 	}
1734a42af91cSHajimu UMEMOTO 	if (haveanswer) {
173569b0a4b6SJim Pirzyk #if defined(RESOLVSORT)
173669b0a4b6SJim Pirzyk 		/*
173769b0a4b6SJim Pirzyk 		 * We support only IPv4 address for backward
173869b0a4b6SJim Pirzyk 		 * compatibility against gethostbyname(3).
173969b0a4b6SJim Pirzyk 		 */
174069b0a4b6SJim Pirzyk 		if (_res.nsort && qtype == T_A) {
174169b0a4b6SJim Pirzyk 			if (addr4sort(&sentinel) < 0) {
174269b0a4b6SJim Pirzyk 				freeaddrinfo(sentinel.ai_next);
174369b0a4b6SJim Pirzyk 				h_errno = NO_RECOVERY;
174469b0a4b6SJim Pirzyk 				return NULL;
174569b0a4b6SJim Pirzyk 			}
174669b0a4b6SJim Pirzyk 		}
174769b0a4b6SJim Pirzyk #endif /*RESOLVSORT*/
1748a42af91cSHajimu UMEMOTO 		if (!canonname)
1749a42af91cSHajimu UMEMOTO 			(void)get_canonname(pai, sentinel.ai_next, qname);
1750a42af91cSHajimu UMEMOTO 		else
1751a42af91cSHajimu UMEMOTO 			(void)get_canonname(pai, sentinel.ai_next, canonname);
1752a42af91cSHajimu UMEMOTO 		h_errno = NETDB_SUCCESS;
1753a42af91cSHajimu UMEMOTO 		return sentinel.ai_next;
1754a42af91cSHajimu UMEMOTO 	}
1755a42af91cSHajimu UMEMOTO 
1756a42af91cSHajimu UMEMOTO 	h_errno = NO_RECOVERY;
1757a42af91cSHajimu UMEMOTO 	return NULL;
1758a42af91cSHajimu UMEMOTO }
1759a42af91cSHajimu UMEMOTO 
1760688a5c3eSHajimu UMEMOTO #ifdef RESOLVSORT
1761688a5c3eSHajimu UMEMOTO struct addr_ptr {
1762688a5c3eSHajimu UMEMOTO 	struct addrinfo *ai;
1763688a5c3eSHajimu UMEMOTO 	int aval;
1764688a5c3eSHajimu UMEMOTO };
1765688a5c3eSHajimu UMEMOTO 
1766688a5c3eSHajimu UMEMOTO static int
1767688a5c3eSHajimu UMEMOTO addr4sort(struct addrinfo *sentinel)
1768688a5c3eSHajimu UMEMOTO {
1769688a5c3eSHajimu UMEMOTO 	struct addrinfo *ai;
1770688a5c3eSHajimu UMEMOTO 	struct addr_ptr *addrs, addr;
1771688a5c3eSHajimu UMEMOTO 	struct sockaddr_in *sin;
1772688a5c3eSHajimu UMEMOTO 	int naddrs, i, j;
1773688a5c3eSHajimu UMEMOTO 	int needsort = 0;
1774688a5c3eSHajimu UMEMOTO 
1775688a5c3eSHajimu UMEMOTO 	if (!sentinel)
1776688a5c3eSHajimu UMEMOTO 		return -1;
1777688a5c3eSHajimu UMEMOTO 	naddrs = 0;
1778688a5c3eSHajimu UMEMOTO 	for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
1779688a5c3eSHajimu UMEMOTO 		naddrs++;
1780688a5c3eSHajimu UMEMOTO 	if (naddrs < 2)
1781688a5c3eSHajimu UMEMOTO 		return 0;		/* We don't need sorting. */
1782688a5c3eSHajimu UMEMOTO 	if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
1783688a5c3eSHajimu UMEMOTO 		return -1;
1784688a5c3eSHajimu UMEMOTO 	i = 0;
1785688a5c3eSHajimu UMEMOTO 	for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
1786688a5c3eSHajimu UMEMOTO 		sin = (struct sockaddr_in *)ai->ai_addr;
1787688a5c3eSHajimu UMEMOTO 		for (j = 0; (unsigned)j < _res.nsort; j++) {
1788688a5c3eSHajimu UMEMOTO 			if (_res.sort_list[j].addr.s_addr ==
1789688a5c3eSHajimu UMEMOTO 			    (sin->sin_addr.s_addr & _res.sort_list[j].mask))
1790688a5c3eSHajimu UMEMOTO 				break;
1791688a5c3eSHajimu UMEMOTO 		}
1792688a5c3eSHajimu UMEMOTO 		addrs[i].ai = ai;
1793688a5c3eSHajimu UMEMOTO 		addrs[i].aval = j;
1794688a5c3eSHajimu UMEMOTO 		if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
1795688a5c3eSHajimu UMEMOTO 			needsort = i;
1796688a5c3eSHajimu UMEMOTO 		i++;
1797688a5c3eSHajimu UMEMOTO 	}
1798688a5c3eSHajimu UMEMOTO 	if (!needsort) {
1799688a5c3eSHajimu UMEMOTO 		free(addrs);
1800688a5c3eSHajimu UMEMOTO 		return 0;
1801688a5c3eSHajimu UMEMOTO 	}
1802688a5c3eSHajimu UMEMOTO 
1803688a5c3eSHajimu UMEMOTO 	while (needsort < naddrs) {
1804688a5c3eSHajimu UMEMOTO 	    for (j = needsort - 1; j >= 0; j--) {
1805688a5c3eSHajimu UMEMOTO 		if (addrs[j].aval > addrs[j+1].aval) {
1806688a5c3eSHajimu UMEMOTO 		    addr = addrs[j];
1807688a5c3eSHajimu UMEMOTO 		    addrs[j] = addrs[j + 1];
1808688a5c3eSHajimu UMEMOTO 		    addrs[j + 1] = addr;
1809688a5c3eSHajimu UMEMOTO 		} else
1810688a5c3eSHajimu UMEMOTO 		    break;
1811688a5c3eSHajimu UMEMOTO 	    }
1812688a5c3eSHajimu UMEMOTO 	    needsort++;
1813688a5c3eSHajimu UMEMOTO 	}
1814688a5c3eSHajimu UMEMOTO 
1815688a5c3eSHajimu UMEMOTO 	ai = sentinel;
1816688a5c3eSHajimu UMEMOTO 	for (i = 0; i < naddrs; ++i) {
1817688a5c3eSHajimu UMEMOTO 		ai->ai_next = addrs[i].ai;
1818688a5c3eSHajimu UMEMOTO 		ai = ai->ai_next;
1819688a5c3eSHajimu UMEMOTO 	}
1820688a5c3eSHajimu UMEMOTO 	ai->ai_next = NULL;
1821688a5c3eSHajimu UMEMOTO 	free(addrs);
1822688a5c3eSHajimu UMEMOTO 	return 0;
1823688a5c3eSHajimu UMEMOTO }
1824688a5c3eSHajimu UMEMOTO #endif /*RESOLVSORT*/
1825688a5c3eSHajimu UMEMOTO 
1826a42af91cSHajimu UMEMOTO /*ARGSUSED*/
1827a42af91cSHajimu UMEMOTO static int
1828248aee62SJacques Vidrine _dns_getaddrinfo(rv, cb_data, ap)
1829248aee62SJacques Vidrine 	void	*rv;
1830248aee62SJacques Vidrine 	void	*cb_data;
1831248aee62SJacques Vidrine 	va_list	 ap;
1832a42af91cSHajimu UMEMOTO {
1833a42af91cSHajimu UMEMOTO 	struct addrinfo *ai;
18345cd588cbSHajimu UMEMOTO 	querybuf *buf, *buf2;
1835a42af91cSHajimu UMEMOTO 	const char *name;
1836248aee62SJacques Vidrine 	const struct addrinfo *pai;
1837a42af91cSHajimu UMEMOTO 	struct addrinfo sentinel, *cur;
1838a42af91cSHajimu UMEMOTO 	struct res_target q, q2;
1839a42af91cSHajimu UMEMOTO 
1840248aee62SJacques Vidrine 	name = va_arg(ap, char *);
1841248aee62SJacques Vidrine 	pai = va_arg(ap, const struct addrinfo *);
1842248aee62SJacques Vidrine 
1843a42af91cSHajimu UMEMOTO 	memset(&q, 0, sizeof(q2));
1844a42af91cSHajimu UMEMOTO 	memset(&q2, 0, sizeof(q2));
1845a42af91cSHajimu UMEMOTO 	memset(&sentinel, 0, sizeof(sentinel));
1846a42af91cSHajimu UMEMOTO 	cur = &sentinel;
1847a42af91cSHajimu UMEMOTO 
18485cd588cbSHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
18495cd588cbSHajimu UMEMOTO 	if (!buf) {
18505cd588cbSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
18515cd588cbSHajimu UMEMOTO 		return NS_NOTFOUND;
18525cd588cbSHajimu UMEMOTO 	}
18535cd588cbSHajimu UMEMOTO 	buf2 = malloc(sizeof(*buf2));
18545cd588cbSHajimu UMEMOTO 	if (!buf2) {
18555cd588cbSHajimu UMEMOTO 		free(buf);
18565cd588cbSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
18575cd588cbSHajimu UMEMOTO 		return NS_NOTFOUND;
18585cd588cbSHajimu UMEMOTO 	}
18595cd588cbSHajimu UMEMOTO 
1860a42af91cSHajimu UMEMOTO 	switch (pai->ai_family) {
1861a42af91cSHajimu UMEMOTO 	case AF_UNSPEC:
1862a42af91cSHajimu UMEMOTO 		/* prefer IPv6 */
1863dd521ef1SHajimu UMEMOTO 		q.name = name;
1864b826397aSJun-ichiro itojun Hagino 		q.qclass = C_IN;
1865b826397aSJun-ichiro itojun Hagino 		q.qtype = T_AAAA;
18665cd588cbSHajimu UMEMOTO 		q.answer = buf->buf;
18675cd588cbSHajimu UMEMOTO 		q.anslen = sizeof(buf->buf);
1868a42af91cSHajimu UMEMOTO 		q.next = &q2;
1869a89c1d30SHajimu UMEMOTO 		q2.name = name;
1870b826397aSJun-ichiro itojun Hagino 		q2.qclass = C_IN;
1871b826397aSJun-ichiro itojun Hagino 		q2.qtype = T_A;
18725cd588cbSHajimu UMEMOTO 		q2.answer = buf2->buf;
18735cd588cbSHajimu UMEMOTO 		q2.anslen = sizeof(buf2->buf);
1874a42af91cSHajimu UMEMOTO 		break;
1875a42af91cSHajimu UMEMOTO 	case AF_INET:
1876dd521ef1SHajimu UMEMOTO 		q.name = name;
1877b826397aSJun-ichiro itojun Hagino 		q.qclass = C_IN;
1878b826397aSJun-ichiro itojun Hagino 		q.qtype = T_A;
18795cd588cbSHajimu UMEMOTO 		q.answer = buf->buf;
18805cd588cbSHajimu UMEMOTO 		q.anslen = sizeof(buf->buf);
1881a42af91cSHajimu UMEMOTO 		break;
1882a42af91cSHajimu UMEMOTO 	case AF_INET6:
1883dd521ef1SHajimu UMEMOTO 		q.name = name;
1884b826397aSJun-ichiro itojun Hagino 		q.qclass = C_IN;
1885b826397aSJun-ichiro itojun Hagino 		q.qtype = T_AAAA;
18865cd588cbSHajimu UMEMOTO 		q.answer = buf->buf;
18875cd588cbSHajimu UMEMOTO 		q.anslen = sizeof(buf->buf);
1888a42af91cSHajimu UMEMOTO 		break;
1889a42af91cSHajimu UMEMOTO 	default:
18905cd588cbSHajimu UMEMOTO 		free(buf);
18915cd588cbSHajimu UMEMOTO 		free(buf2);
1892248aee62SJacques Vidrine 		return NS_UNAVAIL;
1893a42af91cSHajimu UMEMOTO 	}
18945cd588cbSHajimu UMEMOTO 	if (res_searchN(name, &q) < 0) {
18955cd588cbSHajimu UMEMOTO 		free(buf);
18965cd588cbSHajimu UMEMOTO 		free(buf2);
1897248aee62SJacques Vidrine 		return NS_NOTFOUND;
18985cd588cbSHajimu UMEMOTO 	}
18995cd588cbSHajimu UMEMOTO 	ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1900a42af91cSHajimu UMEMOTO 	if (ai) {
1901a42af91cSHajimu UMEMOTO 		cur->ai_next = ai;
1902a42af91cSHajimu UMEMOTO 		while (cur && cur->ai_next)
1903a42af91cSHajimu UMEMOTO 			cur = cur->ai_next;
1904a42af91cSHajimu UMEMOTO 	}
1905a42af91cSHajimu UMEMOTO 	if (q.next) {
19065cd588cbSHajimu UMEMOTO 		ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1907a42af91cSHajimu UMEMOTO 		if (ai)
1908a42af91cSHajimu UMEMOTO 			cur->ai_next = ai;
1909a42af91cSHajimu UMEMOTO 	}
19105cd588cbSHajimu UMEMOTO 	free(buf);
19115cd588cbSHajimu UMEMOTO 	free(buf2);
1912a42af91cSHajimu UMEMOTO 	if (sentinel.ai_next == NULL)
1913a42af91cSHajimu UMEMOTO 		switch (h_errno) {
1914a42af91cSHajimu UMEMOTO 		case HOST_NOT_FOUND:
1915248aee62SJacques Vidrine 			return NS_NOTFOUND;
1916a42af91cSHajimu UMEMOTO 		case TRY_AGAIN:
1917248aee62SJacques Vidrine 			return NS_TRYAGAIN;
1918a42af91cSHajimu UMEMOTO 		default:
1919248aee62SJacques Vidrine 			return NS_UNAVAIL;
1920a42af91cSHajimu UMEMOTO 		}
1921248aee62SJacques Vidrine 	*((struct addrinfo **)rv) = sentinel.ai_next;
1922248aee62SJacques Vidrine 	return NS_SUCCESS;
1923248aee62SJacques Vidrine }
1924248aee62SJacques Vidrine 
1925248aee62SJacques Vidrine static void
1926248aee62SJacques Vidrine _sethtent()
1927248aee62SJacques Vidrine {
1928248aee62SJacques Vidrine 	if (!hostf)
1929248aee62SJacques Vidrine 		hostf = fopen(_PATH_HOSTS, "r" );
1930248aee62SJacques Vidrine 	else
1931248aee62SJacques Vidrine 		rewind(hostf);
1932248aee62SJacques Vidrine }
1933248aee62SJacques Vidrine 
1934248aee62SJacques Vidrine static void
1935248aee62SJacques Vidrine _endhtent()
1936248aee62SJacques Vidrine {
1937248aee62SJacques Vidrine 	if (hostf) {
1938248aee62SJacques Vidrine 		(void) fclose(hostf);
1939248aee62SJacques Vidrine 		hostf = NULL;
1940248aee62SJacques Vidrine 	}
1941a42af91cSHajimu UMEMOTO }
1942a42af91cSHajimu UMEMOTO 
1943a42af91cSHajimu UMEMOTO static struct addrinfo *
1944248aee62SJacques Vidrine _gethtent(name, pai)
1945a42af91cSHajimu UMEMOTO 	const char *name;
1946a42af91cSHajimu UMEMOTO 	const struct addrinfo *pai;
1947a42af91cSHajimu UMEMOTO {
1948a42af91cSHajimu UMEMOTO 	char *p;
1949a42af91cSHajimu UMEMOTO 	char *cp, *tname, *cname;
1950a42af91cSHajimu UMEMOTO 	struct addrinfo hints, *res0, *res;
1951a42af91cSHajimu UMEMOTO 	int error;
1952a42af91cSHajimu UMEMOTO 	const char *addr;
1953a42af91cSHajimu UMEMOTO 	char hostbuf[8*1024];
1954a42af91cSHajimu UMEMOTO 
1955248aee62SJacques Vidrine 	if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
1956248aee62SJacques Vidrine 		return (NULL);
1957a42af91cSHajimu UMEMOTO again:
1958a42af91cSHajimu UMEMOTO 	if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
1959a42af91cSHajimu UMEMOTO 		return (NULL);
1960a42af91cSHajimu UMEMOTO 	if (*p == '#')
1961a42af91cSHajimu UMEMOTO 		goto again;
1962a42af91cSHajimu UMEMOTO 	if (!(cp = strpbrk(p, "#\n")))
1963a42af91cSHajimu UMEMOTO 		goto again;
1964a42af91cSHajimu UMEMOTO 	*cp = '\0';
1965a42af91cSHajimu UMEMOTO 	if (!(cp = strpbrk(p, " \t")))
1966a42af91cSHajimu UMEMOTO 		goto again;
1967a42af91cSHajimu UMEMOTO 	*cp++ = '\0';
1968a42af91cSHajimu UMEMOTO 	addr = p;
1969a42af91cSHajimu UMEMOTO 	cname = NULL;
1970a42af91cSHajimu UMEMOTO 	/* if this is not something we're looking for, skip it. */
1971a42af91cSHajimu UMEMOTO 	while (cp && *cp) {
1972a42af91cSHajimu UMEMOTO 		if (*cp == ' ' || *cp == '\t') {
1973a42af91cSHajimu UMEMOTO 			cp++;
1974a42af91cSHajimu UMEMOTO 			continue;
1975a42af91cSHajimu UMEMOTO 		}
1976a42af91cSHajimu UMEMOTO 		tname = cp;
1977a42af91cSHajimu UMEMOTO 		if (cname == NULL)
1978a42af91cSHajimu UMEMOTO 			cname = cp;
1979a42af91cSHajimu UMEMOTO 		if ((cp = strpbrk(cp, " \t")) != NULL)
1980a42af91cSHajimu UMEMOTO 			*cp++ = '\0';
1981a42af91cSHajimu UMEMOTO 		if (strcasecmp(name, tname) == 0)
1982a42af91cSHajimu UMEMOTO 			goto found;
1983a42af91cSHajimu UMEMOTO 	}
1984a42af91cSHajimu UMEMOTO 	goto again;
1985a42af91cSHajimu UMEMOTO 
1986a42af91cSHajimu UMEMOTO found:
1987dd521ef1SHajimu UMEMOTO 	/* we should not glob socktype/protocol here */
1988dd521ef1SHajimu UMEMOTO 	memset(&hints, 0, sizeof(hints));
1989dd521ef1SHajimu UMEMOTO 	hints.ai_family = pai->ai_family;
1990dd521ef1SHajimu UMEMOTO 	hints.ai_socktype = SOCK_DGRAM;
1991dd521ef1SHajimu UMEMOTO 	hints.ai_protocol = 0;
1992a42af91cSHajimu UMEMOTO 	hints.ai_flags = AI_NUMERICHOST;
1993dd521ef1SHajimu UMEMOTO 	error = getaddrinfo(addr, "0", &hints, &res0);
1994a42af91cSHajimu UMEMOTO 	if (error)
1995a42af91cSHajimu UMEMOTO 		goto again;
1996a42af91cSHajimu UMEMOTO #ifdef FILTER_V4MAPPED
1997a42af91cSHajimu UMEMOTO 	/* XXX should check all items in the chain */
1998a42af91cSHajimu UMEMOTO 	if (res0->ai_family == AF_INET6 &&
1999a42af91cSHajimu UMEMOTO 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) {
2000a42af91cSHajimu UMEMOTO 		freeaddrinfo(res0);
2001a42af91cSHajimu UMEMOTO 		goto again;
2002a42af91cSHajimu UMEMOTO 	}
2003a42af91cSHajimu UMEMOTO #endif
2004a42af91cSHajimu UMEMOTO 	for (res = res0; res; res = res->ai_next) {
2005a42af91cSHajimu UMEMOTO 		/* cover it up */
2006a42af91cSHajimu UMEMOTO 		res->ai_flags = pai->ai_flags;
2007dd521ef1SHajimu UMEMOTO 		res->ai_socktype = pai->ai_socktype;
2008dd521ef1SHajimu UMEMOTO 		res->ai_protocol = pai->ai_protocol;
2009a42af91cSHajimu UMEMOTO 
2010a42af91cSHajimu UMEMOTO 		if (pai->ai_flags & AI_CANONNAME) {
2011a42af91cSHajimu UMEMOTO 			if (get_canonname(pai, res, cname) != 0) {
2012a42af91cSHajimu UMEMOTO 				freeaddrinfo(res0);
2013a42af91cSHajimu UMEMOTO 				goto again;
2014a42af91cSHajimu UMEMOTO 			}
2015a42af91cSHajimu UMEMOTO 		}
2016a42af91cSHajimu UMEMOTO 	}
2017a42af91cSHajimu UMEMOTO 	return res0;
2018a42af91cSHajimu UMEMOTO }
2019a42af91cSHajimu UMEMOTO 
2020a42af91cSHajimu UMEMOTO /*ARGSUSED*/
2021a42af91cSHajimu UMEMOTO static int
2022248aee62SJacques Vidrine _files_getaddrinfo(rv, cb_data, ap)
2023248aee62SJacques Vidrine 	void	*rv;
2024248aee62SJacques Vidrine 	void	*cb_data;
2025248aee62SJacques Vidrine 	va_list	 ap;
2026a42af91cSHajimu UMEMOTO {
2027248aee62SJacques Vidrine 	const char *name;
2028248aee62SJacques Vidrine 	const struct addrinfo *pai;
2029a42af91cSHajimu UMEMOTO 	struct addrinfo sentinel, *cur;
2030a42af91cSHajimu UMEMOTO 	struct addrinfo *p;
2031a42af91cSHajimu UMEMOTO 
2032248aee62SJacques Vidrine 	name = va_arg(ap, char *);
2033248aee62SJacques Vidrine 	pai = va_arg(ap, struct addrinfo *);
2034248aee62SJacques Vidrine 
2035248aee62SJacques Vidrine 	memset(&sentinel, 0, sizeof(sentinel));
2036a42af91cSHajimu UMEMOTO 	cur = &sentinel;
2037a42af91cSHajimu UMEMOTO 
203833dee819SBrian Feldman 	THREAD_LOCK();
2039248aee62SJacques Vidrine 	_sethtent();
2040248aee62SJacques Vidrine 	while ((p = _gethtent(name, pai)) != NULL) {
2041a42af91cSHajimu UMEMOTO 		cur->ai_next = p;
2042a42af91cSHajimu UMEMOTO 		while (cur && cur->ai_next)
2043a42af91cSHajimu UMEMOTO 			cur = cur->ai_next;
2044a42af91cSHajimu UMEMOTO 	}
2045248aee62SJacques Vidrine 	_endhtent();
204633dee819SBrian Feldman 	THREAD_UNLOCK();
2047a42af91cSHajimu UMEMOTO 
2048248aee62SJacques Vidrine 	*((struct addrinfo **)rv) = sentinel.ai_next;
2049248aee62SJacques Vidrine 	if (sentinel.ai_next == NULL)
2050248aee62SJacques Vidrine 		return NS_NOTFOUND;
2051248aee62SJacques Vidrine 	return NS_SUCCESS;
2052a42af91cSHajimu UMEMOTO }
2053a42af91cSHajimu UMEMOTO 
2054a42af91cSHajimu UMEMOTO #ifdef YP
2055248aee62SJacques Vidrine static char *__ypdomain;
2056a42af91cSHajimu UMEMOTO 
2057248aee62SJacques Vidrine /*ARGSUSED*/
2058248aee62SJacques Vidrine static struct addrinfo *
2059248aee62SJacques Vidrine _yphostent(line, pai)
2060248aee62SJacques Vidrine 	char *line;
2061248aee62SJacques Vidrine 	const struct addrinfo *pai;
2062248aee62SJacques Vidrine {
2063248aee62SJacques Vidrine 	struct addrinfo sentinel, *cur;
2064248aee62SJacques Vidrine 	struct addrinfo hints, *res, *res0;
2065248aee62SJacques Vidrine 	int error;
2066248aee62SJacques Vidrine 	char *p = line;
2067248aee62SJacques Vidrine 	const char *addr, *canonname;
2068248aee62SJacques Vidrine 	char *nextline;
2069248aee62SJacques Vidrine 	char *cp;
2070248aee62SJacques Vidrine 
2071248aee62SJacques Vidrine 	addr = canonname = NULL;
2072248aee62SJacques Vidrine 
2073248aee62SJacques Vidrine 	memset(&sentinel, 0, sizeof(sentinel));
2074a42af91cSHajimu UMEMOTO 	cur = &sentinel;
2075a42af91cSHajimu UMEMOTO 
2076248aee62SJacques Vidrine nextline:
2077248aee62SJacques Vidrine 	/* terminate line */
2078248aee62SJacques Vidrine 	cp = strchr(p, '\n');
2079248aee62SJacques Vidrine 	if (cp) {
2080248aee62SJacques Vidrine 		*cp++ = '\0';
2081248aee62SJacques Vidrine 		nextline = cp;
2082248aee62SJacques Vidrine 	} else
2083248aee62SJacques Vidrine 		nextline = NULL;
2084a42af91cSHajimu UMEMOTO 
2085248aee62SJacques Vidrine 	cp = strpbrk(p, " \t");
2086248aee62SJacques Vidrine 	if (cp == NULL) {
2087248aee62SJacques Vidrine 		if (canonname == NULL)
2088248aee62SJacques Vidrine 			return (NULL);
2089248aee62SJacques Vidrine 		else
2090248aee62SJacques Vidrine 			goto done;
2091a42af91cSHajimu UMEMOTO 	}
2092248aee62SJacques Vidrine 	*cp++ = '\0';
2093a42af91cSHajimu UMEMOTO 
2094248aee62SJacques Vidrine 	addr = p;
2095a42af91cSHajimu UMEMOTO 
2096248aee62SJacques Vidrine 	while (cp && *cp) {
2097248aee62SJacques Vidrine 		if (*cp == ' ' || *cp == '\t') {
2098248aee62SJacques Vidrine 			cp++;
2099a42af91cSHajimu UMEMOTO 			continue;
2100248aee62SJacques Vidrine 		}
2101248aee62SJacques Vidrine 		if (!canonname)
2102248aee62SJacques Vidrine 			canonname = cp;
2103248aee62SJacques Vidrine 		if ((cp = strpbrk(cp, " \t")) != NULL)
2104248aee62SJacques Vidrine 			*cp++ = '\0';
2105a42af91cSHajimu UMEMOTO 	}
2106a42af91cSHajimu UMEMOTO 
2107bf838688SHajimu UMEMOTO 	hints = *pai;
2108248aee62SJacques Vidrine 	hints.ai_flags = AI_NUMERICHOST;
2109bf838688SHajimu UMEMOTO 	error = getaddrinfo(addr, NULL, &hints, &res0);
2110248aee62SJacques Vidrine 	if (error == 0) {
2111248aee62SJacques Vidrine 		for (res = res0; res; res = res->ai_next) {
2112248aee62SJacques Vidrine 			/* cover it up */
2113248aee62SJacques Vidrine 			res->ai_flags = pai->ai_flags;
2114248aee62SJacques Vidrine 
2115248aee62SJacques Vidrine 			if (pai->ai_flags & AI_CANONNAME)
2116248aee62SJacques Vidrine 				(void)get_canonname(pai, res, canonname);
2117248aee62SJacques Vidrine 		}
2118248aee62SJacques Vidrine 	} else
2119248aee62SJacques Vidrine 		res0 = NULL;
2120248aee62SJacques Vidrine 	if (res0) {
2121248aee62SJacques Vidrine 		cur->ai_next = res0;
2122a42af91cSHajimu UMEMOTO 		while (cur && cur->ai_next)
2123a42af91cSHajimu UMEMOTO 			cur = cur->ai_next;
2124a42af91cSHajimu UMEMOTO 	}
2125a42af91cSHajimu UMEMOTO 
2126248aee62SJacques Vidrine 	if (nextline) {
2127248aee62SJacques Vidrine 		p = nextline;
2128248aee62SJacques Vidrine 		goto nextline;
2129248aee62SJacques Vidrine 	}
2130a42af91cSHajimu UMEMOTO 
2131248aee62SJacques Vidrine done:
2132248aee62SJacques Vidrine 	return sentinel.ai_next;
2133248aee62SJacques Vidrine }
2134248aee62SJacques Vidrine 
2135248aee62SJacques Vidrine /*ARGSUSED*/
2136248aee62SJacques Vidrine static int
2137248aee62SJacques Vidrine _yp_getaddrinfo(rv, cb_data, ap)
2138248aee62SJacques Vidrine 	void	*rv;
2139248aee62SJacques Vidrine 	void	*cb_data;
2140248aee62SJacques Vidrine 	va_list	 ap;
2141248aee62SJacques Vidrine {
2142248aee62SJacques Vidrine 	struct addrinfo sentinel, *cur;
2143248aee62SJacques Vidrine 	struct addrinfo *ai = NULL;
2144248aee62SJacques Vidrine 	static char *__ypcurrent;
2145248aee62SJacques Vidrine 	int __ypcurrentlen, r;
2146248aee62SJacques Vidrine 	const char *name;
2147248aee62SJacques Vidrine 	const struct addrinfo *pai;
2148248aee62SJacques Vidrine 
2149248aee62SJacques Vidrine 	name = va_arg(ap, char *);
2150248aee62SJacques Vidrine 	pai = va_arg(ap, const struct addrinfo *);
2151248aee62SJacques Vidrine 
2152248aee62SJacques Vidrine 	memset(&sentinel, 0, sizeof(sentinel));
2153248aee62SJacques Vidrine 	cur = &sentinel;
2154248aee62SJacques Vidrine 
215533dee819SBrian Feldman 	THREAD_LOCK();
2156248aee62SJacques Vidrine 	if (!__ypdomain) {
215733dee819SBrian Feldman 		if (_yp_check(&__ypdomain) == 0) {
215833dee819SBrian Feldman 			THREAD_UNLOCK();
2159248aee62SJacques Vidrine 			return NS_UNAVAIL;
2160248aee62SJacques Vidrine 		}
216133dee819SBrian Feldman 	}
2162248aee62SJacques Vidrine 	if (__ypcurrent)
2163248aee62SJacques Vidrine 		free(__ypcurrent);
2164248aee62SJacques Vidrine 	__ypcurrent = NULL;
2165248aee62SJacques Vidrine 
2166248aee62SJacques Vidrine 	/* hosts.byname is only for IPv4 (Solaris8) */
2167248aee62SJacques Vidrine 	if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
2168248aee62SJacques Vidrine 		r = yp_match(__ypdomain, "hosts.byname", name,
2169248aee62SJacques Vidrine 			(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
2170248aee62SJacques Vidrine 		if (r == 0) {
2171248aee62SJacques Vidrine 			struct addrinfo ai4;
2172248aee62SJacques Vidrine 
2173248aee62SJacques Vidrine 			ai4 = *pai;
2174248aee62SJacques Vidrine 			ai4.ai_family = AF_INET;
2175248aee62SJacques Vidrine 			ai = _yphostent(__ypcurrent, &ai4);
2176248aee62SJacques Vidrine 			if (ai) {
2177248aee62SJacques Vidrine 				cur->ai_next = ai;
2178248aee62SJacques Vidrine 				while (cur && cur->ai_next)
2179248aee62SJacques Vidrine 					cur = cur->ai_next;
2180248aee62SJacques Vidrine 			}
2181248aee62SJacques Vidrine 		}
2182248aee62SJacques Vidrine 	}
2183248aee62SJacques Vidrine 
2184248aee62SJacques Vidrine 	/* ipnodes.byname can hold both IPv4/v6 */
2185248aee62SJacques Vidrine 	r = yp_match(__ypdomain, "ipnodes.byname", name,
2186248aee62SJacques Vidrine 		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
2187248aee62SJacques Vidrine 	if (r == 0) {
2188248aee62SJacques Vidrine 		ai = _yphostent(__ypcurrent, pai);
2189248aee62SJacques Vidrine 		if (ai) {
2190248aee62SJacques Vidrine 			cur->ai_next = ai;
2191248aee62SJacques Vidrine 			while (cur && cur->ai_next)
2192248aee62SJacques Vidrine 				cur = cur->ai_next;
2193248aee62SJacques Vidrine 		}
2194248aee62SJacques Vidrine 	}
219533dee819SBrian Feldman 	THREAD_UNLOCK();
2196248aee62SJacques Vidrine 
2197248aee62SJacques Vidrine 	if (sentinel.ai_next == NULL) {
2198248aee62SJacques Vidrine 		h_errno = HOST_NOT_FOUND;
2199248aee62SJacques Vidrine 		return NS_NOTFOUND;
2200248aee62SJacques Vidrine 	}
2201248aee62SJacques Vidrine 	*((struct addrinfo **)rv) = sentinel.ai_next;
2202248aee62SJacques Vidrine 	return NS_SUCCESS;
2203a42af91cSHajimu UMEMOTO }
2204a42af91cSHajimu UMEMOTO #endif
2205a42af91cSHajimu UMEMOTO 
2206a42af91cSHajimu UMEMOTO /* resolver logic */
2207a42af91cSHajimu UMEMOTO 
2208c05ac53bSDavid E. O'Brien extern const char *__hostalias(const char *);
2209a42af91cSHajimu UMEMOTO 
2210a42af91cSHajimu UMEMOTO /*
2211a42af91cSHajimu UMEMOTO  * Formulate a normal query, send, and await answer.
2212a42af91cSHajimu UMEMOTO  * Returned answer is placed in supplied buffer "answer".
2213a42af91cSHajimu UMEMOTO  * Perform preliminary check of answer, returning success only
2214a42af91cSHajimu UMEMOTO  * if no error is indicated and the answer count is nonzero.
2215a42af91cSHajimu UMEMOTO  * Return the size of the response on success, -1 on error.
2216a42af91cSHajimu UMEMOTO  * Error number is left in h_errno.
2217a42af91cSHajimu UMEMOTO  *
2218a42af91cSHajimu UMEMOTO  * Caller must parse answer and determine whether it answers the question.
2219a42af91cSHajimu UMEMOTO  */
2220a42af91cSHajimu UMEMOTO static int
2221a42af91cSHajimu UMEMOTO res_queryN(name, target)
2222a42af91cSHajimu UMEMOTO 	const char *name;	/* domain name */
2223a42af91cSHajimu UMEMOTO 	struct res_target *target;
2224a42af91cSHajimu UMEMOTO {
22255cd588cbSHajimu UMEMOTO 	u_char *buf;
2226a42af91cSHajimu UMEMOTO 	HEADER *hp;
2227a42af91cSHajimu UMEMOTO 	int n;
2228a42af91cSHajimu UMEMOTO 	struct res_target *t;
2229a42af91cSHajimu UMEMOTO 	int rcode;
2230a42af91cSHajimu UMEMOTO 	int ancount;
2231a42af91cSHajimu UMEMOTO 
2232a42af91cSHajimu UMEMOTO 	rcode = NOERROR;
2233a42af91cSHajimu UMEMOTO 	ancount = 0;
2234a42af91cSHajimu UMEMOTO 
2235a42af91cSHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2236a42af91cSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
2237a42af91cSHajimu UMEMOTO 		return (-1);
2238a42af91cSHajimu UMEMOTO 	}
2239a42af91cSHajimu UMEMOTO 
22405cd588cbSHajimu UMEMOTO 	buf = malloc(MAXPACKET);
22415cd588cbSHajimu UMEMOTO 	if (!buf) {
22425cd588cbSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
22435cd588cbSHajimu UMEMOTO 		return -1;
22445cd588cbSHajimu UMEMOTO 	}
22455cd588cbSHajimu UMEMOTO 
2246a42af91cSHajimu UMEMOTO 	for (t = target; t; t = t->next) {
2247a42af91cSHajimu UMEMOTO 		int class, type;
2248a42af91cSHajimu UMEMOTO 		u_char *answer;
2249a42af91cSHajimu UMEMOTO 		int anslen;
2250a42af91cSHajimu UMEMOTO 
2251a42af91cSHajimu UMEMOTO 		hp = (HEADER *)(void *)t->answer;
2252a42af91cSHajimu UMEMOTO 		hp->rcode = NOERROR;	/* default */
2253a42af91cSHajimu UMEMOTO 
2254a42af91cSHajimu UMEMOTO 		/* make it easier... */
2255b826397aSJun-ichiro itojun Hagino 		class = t->qclass;
2256b826397aSJun-ichiro itojun Hagino 		type = t->qtype;
2257a42af91cSHajimu UMEMOTO 		answer = t->answer;
2258a42af91cSHajimu UMEMOTO 		anslen = t->anslen;
2259a42af91cSHajimu UMEMOTO #ifdef DEBUG
2260a42af91cSHajimu UMEMOTO 		if (_res.options & RES_DEBUG)
2261a42af91cSHajimu UMEMOTO 			printf(";; res_query(%s, %d, %d)\n", name, class, type);
2262a42af91cSHajimu UMEMOTO #endif
2263a42af91cSHajimu UMEMOTO 
2264a42af91cSHajimu UMEMOTO 		n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
22655cd588cbSHajimu UMEMOTO 		    buf, MAXPACKET);
2266ce6282dbSHajimu UMEMOTO 		if (n > 0 && (_res.options & RES_USE_EDNS0) != 0)
22675cd588cbSHajimu UMEMOTO 			n = res_opt(n, buf, MAXPACKET, anslen);
2268a42af91cSHajimu UMEMOTO 		if (n <= 0) {
2269a42af91cSHajimu UMEMOTO #ifdef DEBUG
2270a42af91cSHajimu UMEMOTO 			if (_res.options & RES_DEBUG)
2271a42af91cSHajimu UMEMOTO 				printf(";; res_query: mkquery failed\n");
2272a42af91cSHajimu UMEMOTO #endif
22735cd588cbSHajimu UMEMOTO 			free(buf);
2274a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2275a42af91cSHajimu UMEMOTO 			return (n);
2276a42af91cSHajimu UMEMOTO 		}
2277a42af91cSHajimu UMEMOTO 		n = res_send(buf, n, answer, anslen);
2278a42af91cSHajimu UMEMOTO #if 0
2279a42af91cSHajimu UMEMOTO 		if (n < 0) {
2280a42af91cSHajimu UMEMOTO #ifdef DEBUG
2281a42af91cSHajimu UMEMOTO 			if (_res.options & RES_DEBUG)
2282a42af91cSHajimu UMEMOTO 				printf(";; res_query: send error\n");
2283a42af91cSHajimu UMEMOTO #endif
22845cd588cbSHajimu UMEMOTO 			free(buf);
2285a42af91cSHajimu UMEMOTO 			h_errno = TRY_AGAIN;
2286a42af91cSHajimu UMEMOTO 			return (n);
2287a42af91cSHajimu UMEMOTO 		}
2288a42af91cSHajimu UMEMOTO #endif
2289a42af91cSHajimu UMEMOTO 
229054384cf3SJacques Vidrine 		if (n < 0 || n > anslen)
229154384cf3SJacques Vidrine 			hp->rcode = FORMERR; /* XXX not very informative */
229254384cf3SJacques Vidrine 		if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
2293a42af91cSHajimu UMEMOTO 			rcode = hp->rcode;	/* record most recent error */
2294a42af91cSHajimu UMEMOTO #ifdef DEBUG
2295a42af91cSHajimu UMEMOTO 			if (_res.options & RES_DEBUG)
2296dd521ef1SHajimu UMEMOTO 				printf(";; rcode = %u, ancount=%u\n", hp->rcode,
2297a42af91cSHajimu UMEMOTO 				    ntohs(hp->ancount));
2298a42af91cSHajimu UMEMOTO #endif
2299a42af91cSHajimu UMEMOTO 			continue;
2300a42af91cSHajimu UMEMOTO 		}
2301a42af91cSHajimu UMEMOTO 
2302a42af91cSHajimu UMEMOTO 		ancount += ntohs(hp->ancount);
2303a42af91cSHajimu UMEMOTO 
2304a42af91cSHajimu UMEMOTO 		t->n = n;
2305a42af91cSHajimu UMEMOTO 	}
2306a42af91cSHajimu UMEMOTO 
23075cd588cbSHajimu UMEMOTO 	free(buf);
23085cd588cbSHajimu UMEMOTO 
2309a42af91cSHajimu UMEMOTO 	if (ancount == 0) {
2310a42af91cSHajimu UMEMOTO 		switch (rcode) {
2311a42af91cSHajimu UMEMOTO 		case NXDOMAIN:
2312a42af91cSHajimu UMEMOTO 			h_errno = HOST_NOT_FOUND;
2313a42af91cSHajimu UMEMOTO 			break;
2314a42af91cSHajimu UMEMOTO 		case SERVFAIL:
2315a42af91cSHajimu UMEMOTO 			h_errno = TRY_AGAIN;
2316a42af91cSHajimu UMEMOTO 			break;
2317a42af91cSHajimu UMEMOTO 		case NOERROR:
2318a42af91cSHajimu UMEMOTO 			h_errno = NO_DATA;
2319a42af91cSHajimu UMEMOTO 			break;
2320a42af91cSHajimu UMEMOTO 		case FORMERR:
2321a42af91cSHajimu UMEMOTO 		case NOTIMP:
2322a42af91cSHajimu UMEMOTO 		case REFUSED:
2323a42af91cSHajimu UMEMOTO 		default:
2324a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2325a42af91cSHajimu UMEMOTO 			break;
2326a42af91cSHajimu UMEMOTO 		}
2327a42af91cSHajimu UMEMOTO 		return (-1);
2328a42af91cSHajimu UMEMOTO 	}
2329a42af91cSHajimu UMEMOTO 	return (ancount);
2330a42af91cSHajimu UMEMOTO }
2331a42af91cSHajimu UMEMOTO 
2332a42af91cSHajimu UMEMOTO /*
2333a42af91cSHajimu UMEMOTO  * Formulate a normal query, send, and retrieve answer in supplied buffer.
2334a42af91cSHajimu UMEMOTO  * Return the size of the response on success, -1 on error.
2335a42af91cSHajimu UMEMOTO  * If enabled, implement search rules until answer or unrecoverable failure
2336a42af91cSHajimu UMEMOTO  * is detected.  Error code, if any, is left in h_errno.
2337a42af91cSHajimu UMEMOTO  */
2338a42af91cSHajimu UMEMOTO static int
2339a42af91cSHajimu UMEMOTO res_searchN(name, target)
2340a42af91cSHajimu UMEMOTO 	const char *name;	/* domain name */
2341a42af91cSHajimu UMEMOTO 	struct res_target *target;
2342a42af91cSHajimu UMEMOTO {
2343a42af91cSHajimu UMEMOTO 	const char *cp, * const *domain;
2344a42af91cSHajimu UMEMOTO 	HEADER *hp = (HEADER *)(void *)target->answer;	/*XXX*/
2345a42af91cSHajimu UMEMOTO 	u_int dots;
2346a42af91cSHajimu UMEMOTO 	int trailing_dot, ret, saved_herrno;
2347a42af91cSHajimu UMEMOTO 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
2348a42af91cSHajimu UMEMOTO 
2349a42af91cSHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2350a42af91cSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
2351a42af91cSHajimu UMEMOTO 		return (-1);
2352a42af91cSHajimu UMEMOTO 	}
2353a42af91cSHajimu UMEMOTO 
2354a42af91cSHajimu UMEMOTO 	errno = 0;
2355a42af91cSHajimu UMEMOTO 	h_errno = HOST_NOT_FOUND;	/* default, if we never query */
2356a42af91cSHajimu UMEMOTO 	dots = 0;
2357a42af91cSHajimu UMEMOTO 	for (cp = name; *cp; cp++)
2358a42af91cSHajimu UMEMOTO 		dots += (*cp == '.');
2359a42af91cSHajimu UMEMOTO 	trailing_dot = 0;
2360a42af91cSHajimu UMEMOTO 	if (cp > name && *--cp == '.')
2361a42af91cSHajimu UMEMOTO 		trailing_dot++;
2362a42af91cSHajimu UMEMOTO 
2363a42af91cSHajimu UMEMOTO 	/*
2364a42af91cSHajimu UMEMOTO 	 * if there aren't any dots, it could be a user-level alias
2365a42af91cSHajimu UMEMOTO 	 */
2366a42af91cSHajimu UMEMOTO 	if (!dots && (cp = __hostalias(name)) != NULL)
2367a42af91cSHajimu UMEMOTO 		return (res_queryN(cp, target));
2368a42af91cSHajimu UMEMOTO 
2369a42af91cSHajimu UMEMOTO 	/*
2370a42af91cSHajimu UMEMOTO 	 * If there are dots in the name already, let's just give it a try
2371a42af91cSHajimu UMEMOTO 	 * 'as is'.  The threshold can be set with the "ndots" option.
2372a42af91cSHajimu UMEMOTO 	 */
2373a42af91cSHajimu UMEMOTO 	saved_herrno = -1;
2374a42af91cSHajimu UMEMOTO 	if (dots >= _res.ndots) {
2375a42af91cSHajimu UMEMOTO 		ret = res_querydomainN(name, NULL, target);
2376a42af91cSHajimu UMEMOTO 		if (ret > 0)
2377a42af91cSHajimu UMEMOTO 			return (ret);
2378a42af91cSHajimu UMEMOTO 		saved_herrno = h_errno;
2379a42af91cSHajimu UMEMOTO 		tried_as_is++;
2380a42af91cSHajimu UMEMOTO 	}
2381a42af91cSHajimu UMEMOTO 
2382a42af91cSHajimu UMEMOTO 	/*
2383a42af91cSHajimu UMEMOTO 	 * We do at least one level of search if
2384a42af91cSHajimu UMEMOTO 	 *	- there is no dot and RES_DEFNAME is set, or
2385a42af91cSHajimu UMEMOTO 	 *	- there is at least one dot, there is no trailing dot,
2386a42af91cSHajimu UMEMOTO 	 *	  and RES_DNSRCH is set.
2387a42af91cSHajimu UMEMOTO 	 */
2388a42af91cSHajimu UMEMOTO 	if ((!dots && (_res.options & RES_DEFNAMES)) ||
2389a42af91cSHajimu UMEMOTO 	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
2390a42af91cSHajimu UMEMOTO 		int done = 0;
2391a42af91cSHajimu UMEMOTO 
2392a42af91cSHajimu UMEMOTO 		for (domain = (const char * const *)_res.dnsrch;
2393a42af91cSHajimu UMEMOTO 		   *domain && !done;
2394a42af91cSHajimu UMEMOTO 		   domain++) {
2395a42af91cSHajimu UMEMOTO 
2396a42af91cSHajimu UMEMOTO 			ret = res_querydomainN(name, *domain, target);
2397a42af91cSHajimu UMEMOTO 			if (ret > 0)
2398a42af91cSHajimu UMEMOTO 				return (ret);
2399a42af91cSHajimu UMEMOTO 
2400a42af91cSHajimu UMEMOTO 			/*
2401a42af91cSHajimu UMEMOTO 			 * If no server present, give up.
2402a42af91cSHajimu UMEMOTO 			 * If name isn't found in this domain,
2403a42af91cSHajimu UMEMOTO 			 * keep trying higher domains in the search list
2404a42af91cSHajimu UMEMOTO 			 * (if that's enabled).
2405a42af91cSHajimu UMEMOTO 			 * On a NO_DATA error, keep trying, otherwise
2406a42af91cSHajimu UMEMOTO 			 * a wildcard entry of another type could keep us
2407a42af91cSHajimu UMEMOTO 			 * from finding this entry higher in the domain.
2408a42af91cSHajimu UMEMOTO 			 * If we get some other error (negative answer or
2409a42af91cSHajimu UMEMOTO 			 * server failure), then stop searching up,
2410a42af91cSHajimu UMEMOTO 			 * but try the input name below in case it's
2411a42af91cSHajimu UMEMOTO 			 * fully-qualified.
2412a42af91cSHajimu UMEMOTO 			 */
2413a42af91cSHajimu UMEMOTO 			if (errno == ECONNREFUSED) {
2414a42af91cSHajimu UMEMOTO 				h_errno = TRY_AGAIN;
2415a42af91cSHajimu UMEMOTO 				return (-1);
2416a42af91cSHajimu UMEMOTO 			}
2417a42af91cSHajimu UMEMOTO 
2418a42af91cSHajimu UMEMOTO 			switch (h_errno) {
2419a42af91cSHajimu UMEMOTO 			case NO_DATA:
2420a42af91cSHajimu UMEMOTO 				got_nodata++;
2421a42af91cSHajimu UMEMOTO 				/* FALLTHROUGH */
2422a42af91cSHajimu UMEMOTO 			case HOST_NOT_FOUND:
2423a42af91cSHajimu UMEMOTO 				/* keep trying */
2424a42af91cSHajimu UMEMOTO 				break;
2425a42af91cSHajimu UMEMOTO 			case TRY_AGAIN:
2426a42af91cSHajimu UMEMOTO 				if (hp->rcode == SERVFAIL) {
2427a42af91cSHajimu UMEMOTO 					/* try next search element, if any */
2428a42af91cSHajimu UMEMOTO 					got_servfail++;
2429a42af91cSHajimu UMEMOTO 					break;
2430a42af91cSHajimu UMEMOTO 				}
2431a42af91cSHajimu UMEMOTO 				/* FALLTHROUGH */
2432a42af91cSHajimu UMEMOTO 			default:
2433a42af91cSHajimu UMEMOTO 				/* anything else implies that we're done */
2434a42af91cSHajimu UMEMOTO 				done++;
2435a42af91cSHajimu UMEMOTO 			}
2436a42af91cSHajimu UMEMOTO 			/*
2437a42af91cSHajimu UMEMOTO 			 * if we got here for some reason other than DNSRCH,
2438a42af91cSHajimu UMEMOTO 			 * we only wanted one iteration of the loop, so stop.
2439a42af91cSHajimu UMEMOTO 			 */
2440a42af91cSHajimu UMEMOTO 			if (!(_res.options & RES_DNSRCH))
2441a42af91cSHajimu UMEMOTO 			        done++;
2442a42af91cSHajimu UMEMOTO 		}
2443a42af91cSHajimu UMEMOTO 	}
2444a42af91cSHajimu UMEMOTO 
2445a42af91cSHajimu UMEMOTO 	/*
2446a42af91cSHajimu UMEMOTO 	 * if we have not already tried the name "as is", do that now.
2447a42af91cSHajimu UMEMOTO 	 * note that we do this regardless of how many dots were in the
2448a42af91cSHajimu UMEMOTO 	 * name or whether it ends with a dot.
2449a42af91cSHajimu UMEMOTO 	 */
2450a42af91cSHajimu UMEMOTO 	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
2451a42af91cSHajimu UMEMOTO 		ret = res_querydomainN(name, NULL, target);
2452a42af91cSHajimu UMEMOTO 		if (ret > 0)
2453a42af91cSHajimu UMEMOTO 			return (ret);
2454a42af91cSHajimu UMEMOTO 	}
2455a42af91cSHajimu UMEMOTO 
2456a42af91cSHajimu UMEMOTO 	/*
2457a42af91cSHajimu UMEMOTO 	 * if we got here, we didn't satisfy the search.
2458a42af91cSHajimu UMEMOTO 	 * if we did an initial full query, return that query's h_errno
2459a42af91cSHajimu UMEMOTO 	 * (note that we wouldn't be here if that query had succeeded).
2460a42af91cSHajimu UMEMOTO 	 * else if we ever got a nodata, send that back as the reason.
2461a42af91cSHajimu UMEMOTO 	 * else send back meaningless h_errno, that being the one from
2462a42af91cSHajimu UMEMOTO 	 * the last DNSRCH we did.
2463a42af91cSHajimu UMEMOTO 	 */
2464a42af91cSHajimu UMEMOTO 	if (saved_herrno != -1)
2465a42af91cSHajimu UMEMOTO 		h_errno = saved_herrno;
2466a42af91cSHajimu UMEMOTO 	else if (got_nodata)
2467a42af91cSHajimu UMEMOTO 		h_errno = NO_DATA;
2468a42af91cSHajimu UMEMOTO 	else if (got_servfail)
2469a42af91cSHajimu UMEMOTO 		h_errno = TRY_AGAIN;
2470a42af91cSHajimu UMEMOTO 	return (-1);
2471a42af91cSHajimu UMEMOTO }
2472a42af91cSHajimu UMEMOTO 
2473a42af91cSHajimu UMEMOTO /*
2474a42af91cSHajimu UMEMOTO  * Perform a call on res_query on the concatenation of name and domain,
2475a42af91cSHajimu UMEMOTO  * removing a trailing dot from name if domain is NULL.
2476a42af91cSHajimu UMEMOTO  */
2477a42af91cSHajimu UMEMOTO static int
2478a42af91cSHajimu UMEMOTO res_querydomainN(name, domain, target)
2479a42af91cSHajimu UMEMOTO 	const char *name, *domain;
2480a42af91cSHajimu UMEMOTO 	struct res_target *target;
2481a42af91cSHajimu UMEMOTO {
2482a42af91cSHajimu UMEMOTO 	char nbuf[MAXDNAME];
2483a42af91cSHajimu UMEMOTO 	const char *longname = nbuf;
2484a42af91cSHajimu UMEMOTO 	size_t n, d;
2485a42af91cSHajimu UMEMOTO 
2486a42af91cSHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2487a42af91cSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
2488a42af91cSHajimu UMEMOTO 		return (-1);
2489a42af91cSHajimu UMEMOTO 	}
2490a42af91cSHajimu UMEMOTO #ifdef DEBUG
2491a42af91cSHajimu UMEMOTO 	if (_res.options & RES_DEBUG)
2492a42af91cSHajimu UMEMOTO 		printf(";; res_querydomain(%s, %s)\n",
2493a42af91cSHajimu UMEMOTO 			name, domain?domain:"<Nil>");
2494a42af91cSHajimu UMEMOTO #endif
2495a42af91cSHajimu UMEMOTO 	if (domain == NULL) {
2496a42af91cSHajimu UMEMOTO 		/*
2497a42af91cSHajimu UMEMOTO 		 * Check for trailing '.';
2498a42af91cSHajimu UMEMOTO 		 * copy without '.' if present.
2499a42af91cSHajimu UMEMOTO 		 */
2500a42af91cSHajimu UMEMOTO 		n = strlen(name);
2501a42af91cSHajimu UMEMOTO 		if (n >= MAXDNAME) {
2502a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2503a42af91cSHajimu UMEMOTO 			return (-1);
2504a42af91cSHajimu UMEMOTO 		}
2505a42af91cSHajimu UMEMOTO 		if (n > 0 && name[--n] == '.') {
2506a42af91cSHajimu UMEMOTO 			strncpy(nbuf, name, n);
2507a42af91cSHajimu UMEMOTO 			nbuf[n] = '\0';
2508a42af91cSHajimu UMEMOTO 		} else
2509a42af91cSHajimu UMEMOTO 			longname = name;
2510a42af91cSHajimu UMEMOTO 	} else {
2511a42af91cSHajimu UMEMOTO 		n = strlen(name);
2512a42af91cSHajimu UMEMOTO 		d = strlen(domain);
2513a42af91cSHajimu UMEMOTO 		if (n + d + 1 >= MAXDNAME) {
2514a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2515a42af91cSHajimu UMEMOTO 			return (-1);
2516a42af91cSHajimu UMEMOTO 		}
2517dd521ef1SHajimu UMEMOTO 		snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
2518a42af91cSHajimu UMEMOTO 	}
2519a42af91cSHajimu UMEMOTO 	return (res_queryN(longname, target));
2520a42af91cSHajimu UMEMOTO }
2521