xref: /freebsd/lib/libc/net/getaddrinfo.c (revision 4c6867a867ad07908c0b7f43788412b49cc26447)
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 /*
30871918af6SHajimu UMEMOTO  * XXX: Our res_*() is 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
31171918af6SHajimu UMEMOTO  * functions which call res_*().
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 
13517d56d374SYoshinobu Inoue 		if ((sp = getservbyname(servname, proto)) == NULL)
13527d56d374SYoshinobu Inoue 			return EAI_SERVICE;
13537d56d374SYoshinobu Inoue 		port = sp->s_port;
13547d56d374SYoshinobu Inoue 	}
13557d56d374SYoshinobu Inoue 
13567d56d374SYoshinobu Inoue 	if (!matchonly) {
13577d56d374SYoshinobu Inoue 		switch (ai->ai_family) {
13587d56d374SYoshinobu Inoue 		case AF_INET:
1359a42af91cSHajimu UMEMOTO 			((struct sockaddr_in *)(void *)
1360a42af91cSHajimu UMEMOTO 			    ai->ai_addr)->sin_port = port;
13617d56d374SYoshinobu Inoue 			break;
13627d56d374SYoshinobu Inoue #ifdef INET6
13637d56d374SYoshinobu Inoue 		case AF_INET6:
1364a42af91cSHajimu UMEMOTO 			((struct sockaddr_in6 *)(void *)
1365a42af91cSHajimu UMEMOTO 			    ai->ai_addr)->sin6_port = port;
13667d56d374SYoshinobu Inoue 			break;
13677d56d374SYoshinobu Inoue #endif
13687d56d374SYoshinobu Inoue 		}
13697d56d374SYoshinobu Inoue 	}
13707d56d374SYoshinobu Inoue 
13717d56d374SYoshinobu Inoue 	return 0;
13727d56d374SYoshinobu Inoue }
13737d56d374SYoshinobu Inoue 
13747d56d374SYoshinobu Inoue static const struct afd *
13757d56d374SYoshinobu Inoue find_afd(af)
13767d56d374SYoshinobu Inoue 	int af;
13777d56d374SYoshinobu Inoue {
13787d56d374SYoshinobu Inoue 	const struct afd *afd;
13797d56d374SYoshinobu Inoue 
13807d56d374SYoshinobu Inoue 	if (af == PF_UNSPEC)
13817d56d374SYoshinobu Inoue 		return NULL;
13827d56d374SYoshinobu Inoue 	for (afd = afdl; afd->a_af; afd++) {
13837d56d374SYoshinobu Inoue 		if (afd->a_af == af)
13847d56d374SYoshinobu Inoue 			return afd;
13857d56d374SYoshinobu Inoue 	}
13867d56d374SYoshinobu Inoue 	return NULL;
13877d56d374SYoshinobu Inoue }
1388a42af91cSHajimu UMEMOTO 
1389a42af91cSHajimu UMEMOTO /*
1390a42af91cSHajimu UMEMOTO  * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
1391a42af91cSHajimu UMEMOTO  * will take care of it.
1392a42af91cSHajimu UMEMOTO  * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
1393a42af91cSHajimu UMEMOTO  * if the code is right or not.
1394bf838688SHajimu UMEMOTO  *
1395bf838688SHajimu UMEMOTO  * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
1396bf838688SHajimu UMEMOTO  * _dns_getaddrinfo.
1397a42af91cSHajimu UMEMOTO  */
1398a42af91cSHajimu UMEMOTO static int
1399bf838688SHajimu UMEMOTO addrconfig(pai)
1400bf838688SHajimu UMEMOTO 	struct addrinfo *pai;
1401a42af91cSHajimu UMEMOTO {
1402bf838688SHajimu UMEMOTO 	int s, af;
1403a42af91cSHajimu UMEMOTO 
1404bf838688SHajimu UMEMOTO 	/*
1405bf838688SHajimu UMEMOTO 	 * TODO:
1406bf838688SHajimu UMEMOTO 	 * Note that implementation dependent test for address
1407bf838688SHajimu UMEMOTO 	 * configuration should be done everytime called
1408bf838688SHajimu UMEMOTO 	 * (or apropriate interval),
1409bf838688SHajimu UMEMOTO 	 * because addresses will be dynamically assigned or deleted.
1410bf838688SHajimu UMEMOTO 	 */
1411bf838688SHajimu UMEMOTO 	af = pai->ai_family;
1412bf838688SHajimu UMEMOTO 	if (af == AF_UNSPEC) {
1413bf838688SHajimu UMEMOTO 		if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1414bf838688SHajimu UMEMOTO 			af = AF_INET;
1415bf838688SHajimu UMEMOTO 		else {
1416bf838688SHajimu UMEMOTO 			_close(s);
1417bf838688SHajimu UMEMOTO 			if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1418bf838688SHajimu UMEMOTO 				af = AF_INET6;
1419bf838688SHajimu UMEMOTO 			else
1420bf838688SHajimu UMEMOTO 				_close(s);
1421bf838688SHajimu UMEMOTO 		}
1422bf838688SHajimu UMEMOTO 	}
1423bf838688SHajimu UMEMOTO 	if (af != AF_UNSPEC) {
1424bf838688SHajimu UMEMOTO 		if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
1425a42af91cSHajimu UMEMOTO 			return 0;
1426bf838688SHajimu UMEMOTO 		_close(s);
1427bf838688SHajimu UMEMOTO 	}
1428bf838688SHajimu UMEMOTO 	pai->ai_family = af;
1429a42af91cSHajimu UMEMOTO 	return 1;
1430a42af91cSHajimu UMEMOTO }
1431a42af91cSHajimu UMEMOTO 
1432a42af91cSHajimu UMEMOTO #ifdef INET6
1433a42af91cSHajimu UMEMOTO /* convert a string to a scope identifier. XXX: IPv6 specific */
1434a42af91cSHajimu UMEMOTO static int
1435a89c1d30SHajimu UMEMOTO ip6_str2scopeid(scope, sin6, scopeid)
1436a42af91cSHajimu UMEMOTO 	char *scope;
1437a42af91cSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
1438a89c1d30SHajimu UMEMOTO 	u_int32_t *scopeid;
1439a42af91cSHajimu UMEMOTO {
1440a89c1d30SHajimu UMEMOTO 	u_long lscopeid;
1441bf838688SHajimu UMEMOTO 	struct in6_addr *a6;
1442a42af91cSHajimu UMEMOTO 	char *ep;
1443a42af91cSHajimu UMEMOTO 
1444bf838688SHajimu UMEMOTO 	a6 = &sin6->sin6_addr;
1445bf838688SHajimu UMEMOTO 
1446ec20fe00SJun-ichiro itojun Hagino 	/* empty scopeid portion is invalid */
1447ec20fe00SJun-ichiro itojun Hagino 	if (*scope == '\0')
1448ec20fe00SJun-ichiro itojun Hagino 		return -1;
1449ec20fe00SJun-ichiro itojun Hagino 
1450bf838688SHajimu UMEMOTO 	if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1451a42af91cSHajimu UMEMOTO 		/*
1452a42af91cSHajimu UMEMOTO 		 * We currently assume a one-to-one mapping between links
1453a42af91cSHajimu UMEMOTO 		 * and interfaces, so we simply use interface indices for
1454a42af91cSHajimu UMEMOTO 		 * like-local scopes.
1455a42af91cSHajimu UMEMOTO 		 */
1456a89c1d30SHajimu UMEMOTO 		*scopeid = if_nametoindex(scope);
1457a89c1d30SHajimu UMEMOTO 		if (*scopeid == 0)
1458a42af91cSHajimu UMEMOTO 			goto trynumeric;
1459a89c1d30SHajimu UMEMOTO 		return 0;
1460a42af91cSHajimu UMEMOTO 	}
1461a42af91cSHajimu UMEMOTO 
1462a42af91cSHajimu UMEMOTO 	/* still unclear about literal, allow numeric only - placeholder */
1463a42af91cSHajimu UMEMOTO 	if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1464a42af91cSHajimu UMEMOTO 		goto trynumeric;
1465a42af91cSHajimu UMEMOTO 	if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1466a42af91cSHajimu UMEMOTO 		goto trynumeric;
1467a42af91cSHajimu UMEMOTO 	else
1468a42af91cSHajimu UMEMOTO 		goto trynumeric;	/* global */
1469a42af91cSHajimu UMEMOTO 
1470a42af91cSHajimu UMEMOTO 	/* try to convert to a numeric id as a last resort */
1471a42af91cSHajimu UMEMOTO   trynumeric:
1472a89c1d30SHajimu UMEMOTO 	errno = 0;
1473a89c1d30SHajimu UMEMOTO 	lscopeid = strtoul(scope, &ep, 10);
1474a89c1d30SHajimu UMEMOTO 	*scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1475a89c1d30SHajimu UMEMOTO 	if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1476a89c1d30SHajimu UMEMOTO 		return 0;
1477a42af91cSHajimu UMEMOTO 	else
1478a42af91cSHajimu UMEMOTO 		return -1;
1479a42af91cSHajimu UMEMOTO }
1480a42af91cSHajimu UMEMOTO #endif
1481a42af91cSHajimu UMEMOTO 
1482688a5c3eSHajimu UMEMOTO /*
1483688a5c3eSHajimu UMEMOTO  * FQDN hostname, DNS lookup
1484688a5c3eSHajimu UMEMOTO  */
1485688a5c3eSHajimu UMEMOTO static int
1486688a5c3eSHajimu UMEMOTO explore_fqdn(pai, hostname, servname, res)
1487688a5c3eSHajimu UMEMOTO 	const struct addrinfo *pai;
1488688a5c3eSHajimu UMEMOTO 	const char *hostname;
1489688a5c3eSHajimu UMEMOTO 	const char *servname;
1490688a5c3eSHajimu UMEMOTO 	struct addrinfo **res;
1491688a5c3eSHajimu UMEMOTO {
1492688a5c3eSHajimu UMEMOTO 	struct addrinfo *result;
1493688a5c3eSHajimu UMEMOTO 	struct addrinfo *cur;
1494688a5c3eSHajimu UMEMOTO 	int error = 0;
1495688a5c3eSHajimu UMEMOTO 	static const ns_dtab dtab[] = {
1496688a5c3eSHajimu UMEMOTO 		NS_FILES_CB(_files_getaddrinfo, NULL)
1497688a5c3eSHajimu UMEMOTO 		{ NSSRC_DNS, _dns_getaddrinfo, NULL },	/* force -DHESIOD */
1498688a5c3eSHajimu UMEMOTO 		NS_NIS_CB(_yp_getaddrinfo, NULL)
1499688a5c3eSHajimu UMEMOTO 		{ 0 }
150069b0a4b6SJim Pirzyk 	};
150169b0a4b6SJim Pirzyk 
1502688a5c3eSHajimu UMEMOTO 	result = NULL;
150369b0a4b6SJim Pirzyk 
1504688a5c3eSHajimu UMEMOTO 	THREAD_LOCK();
1505688a5c3eSHajimu UMEMOTO 
1506688a5c3eSHajimu UMEMOTO 	/*
1507688a5c3eSHajimu UMEMOTO 	 * if the servname does not match socktype/protocol, ignore it.
1508688a5c3eSHajimu UMEMOTO 	 */
1509688a5c3eSHajimu UMEMOTO 	if (get_portmatch(pai, servname) != 0) {
1510688a5c3eSHajimu UMEMOTO 		THREAD_UNLOCK();
151169b0a4b6SJim Pirzyk 		return 0;
151269b0a4b6SJim Pirzyk 	}
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 	}
1533688a5c3eSHajimu UMEMOTO 	THREAD_UNLOCK();
153469b0a4b6SJim Pirzyk 
1535688a5c3eSHajimu UMEMOTO 	*res = result;
1536688a5c3eSHajimu UMEMOTO 
153769b0a4b6SJim Pirzyk 	return 0;
1538688a5c3eSHajimu UMEMOTO 
1539688a5c3eSHajimu UMEMOTO free:
1540688a5c3eSHajimu UMEMOTO 	THREAD_UNLOCK();
1541688a5c3eSHajimu UMEMOTO 	if (result)
1542688a5c3eSHajimu UMEMOTO 		freeaddrinfo(result);
1543688a5c3eSHajimu UMEMOTO 	return error;
154469b0a4b6SJim Pirzyk }
154569b0a4b6SJim Pirzyk 
1546a42af91cSHajimu UMEMOTO #ifdef DEBUG
1547a42af91cSHajimu UMEMOTO static const char AskedForGot[] =
1548a42af91cSHajimu UMEMOTO 	"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1549a42af91cSHajimu UMEMOTO #endif
1550248aee62SJacques Vidrine static FILE *hostf = NULL;
1551a42af91cSHajimu UMEMOTO 
1552a42af91cSHajimu UMEMOTO static struct addrinfo *
1553a42af91cSHajimu UMEMOTO getanswer(answer, anslen, qname, qtype, pai)
1554a42af91cSHajimu UMEMOTO 	const querybuf *answer;
1555a42af91cSHajimu UMEMOTO 	int anslen;
1556a42af91cSHajimu UMEMOTO 	const char *qname;
1557a42af91cSHajimu UMEMOTO 	int qtype;
1558a42af91cSHajimu UMEMOTO 	const struct addrinfo *pai;
1559a42af91cSHajimu UMEMOTO {
1560a42af91cSHajimu UMEMOTO 	struct addrinfo sentinel, *cur;
1561a42af91cSHajimu UMEMOTO 	struct addrinfo ai;
1562a42af91cSHajimu UMEMOTO 	const struct afd *afd;
1563a42af91cSHajimu UMEMOTO 	char *canonname;
1564a42af91cSHajimu UMEMOTO 	const HEADER *hp;
1565a42af91cSHajimu UMEMOTO 	const u_char *cp;
1566a42af91cSHajimu UMEMOTO 	int n;
1567a42af91cSHajimu UMEMOTO 	const u_char *eom;
1568dd521ef1SHajimu UMEMOTO 	char *bp, *ep;
1569dd521ef1SHajimu UMEMOTO 	int type, class, ancount, qdcount;
1570a42af91cSHajimu UMEMOTO 	int haveanswer, had_error;
1571a42af91cSHajimu UMEMOTO 	char tbuf[MAXDNAME];
1572c05ac53bSDavid E. O'Brien 	int (*name_ok)(const char *);
1573a42af91cSHajimu UMEMOTO 	char hostbuf[8*1024];
1574a42af91cSHajimu UMEMOTO 
1575a42af91cSHajimu UMEMOTO 	memset(&sentinel, 0, sizeof(sentinel));
1576a42af91cSHajimu UMEMOTO 	cur = &sentinel;
1577a42af91cSHajimu UMEMOTO 
1578a42af91cSHajimu UMEMOTO 	canonname = NULL;
1579a42af91cSHajimu UMEMOTO 	eom = answer->buf + anslen;
1580a42af91cSHajimu UMEMOTO 	switch (qtype) {
1581a42af91cSHajimu UMEMOTO 	case T_A:
1582a42af91cSHajimu UMEMOTO 	case T_AAAA:
1583a42af91cSHajimu UMEMOTO 	case T_ANY:	/*use T_ANY only for T_A/T_AAAA lookup*/
1584a42af91cSHajimu UMEMOTO 		name_ok = res_hnok;
1585a42af91cSHajimu UMEMOTO 		break;
1586a42af91cSHajimu UMEMOTO 	default:
1587a42af91cSHajimu UMEMOTO 		return (NULL);	/* XXX should be abort(); */
1588a42af91cSHajimu UMEMOTO 	}
1589a42af91cSHajimu UMEMOTO 	/*
1590a42af91cSHajimu UMEMOTO 	 * find first satisfactory answer
1591a42af91cSHajimu UMEMOTO 	 */
1592a42af91cSHajimu UMEMOTO 	hp = &answer->hdr;
1593a42af91cSHajimu UMEMOTO 	ancount = ntohs(hp->ancount);
1594a42af91cSHajimu UMEMOTO 	qdcount = ntohs(hp->qdcount);
1595a42af91cSHajimu UMEMOTO 	bp = hostbuf;
1596dd521ef1SHajimu UMEMOTO 	ep = hostbuf + sizeof hostbuf;
1597a42af91cSHajimu UMEMOTO 	cp = answer->buf + HFIXEDSZ;
1598a42af91cSHajimu UMEMOTO 	if (qdcount != 1) {
1599a42af91cSHajimu UMEMOTO 		h_errno = NO_RECOVERY;
1600a42af91cSHajimu UMEMOTO 		return (NULL);
1601a42af91cSHajimu UMEMOTO 	}
1602dd521ef1SHajimu UMEMOTO 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1603a42af91cSHajimu UMEMOTO 	if ((n < 0) || !(*name_ok)(bp)) {
1604a42af91cSHajimu UMEMOTO 		h_errno = NO_RECOVERY;
1605a42af91cSHajimu UMEMOTO 		return (NULL);
1606a42af91cSHajimu UMEMOTO 	}
1607a42af91cSHajimu UMEMOTO 	cp += n + QFIXEDSZ;
1608a42af91cSHajimu UMEMOTO 	if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1609a42af91cSHajimu UMEMOTO 		/* res_send() has already verified that the query name is the
1610a42af91cSHajimu UMEMOTO 		 * same as the one we sent; this just gets the expanded name
1611a42af91cSHajimu UMEMOTO 		 * (i.e., with the succeeding search-domain tacked on).
1612a42af91cSHajimu UMEMOTO 		 */
1613a42af91cSHajimu UMEMOTO 		n = strlen(bp) + 1;		/* for the \0 */
1614a42af91cSHajimu UMEMOTO 		if (n >= MAXHOSTNAMELEN) {
1615a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
1616a42af91cSHajimu UMEMOTO 			return (NULL);
1617a42af91cSHajimu UMEMOTO 		}
1618a42af91cSHajimu UMEMOTO 		canonname = bp;
1619a42af91cSHajimu UMEMOTO 		bp += n;
1620a42af91cSHajimu UMEMOTO 		/* The qname can be abbreviated, but h_name is now absolute. */
1621a42af91cSHajimu UMEMOTO 		qname = canonname;
1622a42af91cSHajimu UMEMOTO 	}
1623a42af91cSHajimu UMEMOTO 	haveanswer = 0;
1624a42af91cSHajimu UMEMOTO 	had_error = 0;
1625a42af91cSHajimu UMEMOTO 	while (ancount-- > 0 && cp < eom && !had_error) {
1626dd521ef1SHajimu UMEMOTO 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1627a42af91cSHajimu UMEMOTO 		if ((n < 0) || !(*name_ok)(bp)) {
1628a42af91cSHajimu UMEMOTO 			had_error++;
1629a42af91cSHajimu UMEMOTO 			continue;
1630a42af91cSHajimu UMEMOTO 		}
1631a42af91cSHajimu UMEMOTO 		cp += n;			/* name */
1632a42af91cSHajimu UMEMOTO 		type = _getshort(cp);
1633a42af91cSHajimu UMEMOTO  		cp += INT16SZ;			/* type */
1634a42af91cSHajimu UMEMOTO 		class = _getshort(cp);
1635a42af91cSHajimu UMEMOTO  		cp += INT16SZ + INT32SZ;	/* class, TTL */
1636a42af91cSHajimu UMEMOTO 		n = _getshort(cp);
1637a42af91cSHajimu UMEMOTO 		cp += INT16SZ;			/* len */
1638a42af91cSHajimu UMEMOTO 		if (class != C_IN) {
1639a42af91cSHajimu UMEMOTO 			/* XXX - debug? syslog? */
1640a42af91cSHajimu UMEMOTO 			cp += n;
1641a42af91cSHajimu UMEMOTO 			continue;		/* XXX - had_error++ ? */
1642a42af91cSHajimu UMEMOTO 		}
1643a42af91cSHajimu UMEMOTO 		if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1644a42af91cSHajimu UMEMOTO 		    type == T_CNAME) {
1645a42af91cSHajimu UMEMOTO 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1646a42af91cSHajimu UMEMOTO 			if ((n < 0) || !(*name_ok)(tbuf)) {
1647a42af91cSHajimu UMEMOTO 				had_error++;
1648a42af91cSHajimu UMEMOTO 				continue;
1649a42af91cSHajimu UMEMOTO 			}
1650a42af91cSHajimu UMEMOTO 			cp += n;
1651a42af91cSHajimu UMEMOTO 			/* Get canonical name. */
1652a42af91cSHajimu UMEMOTO 			n = strlen(tbuf) + 1;	/* for the \0 */
1653dd521ef1SHajimu UMEMOTO 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1654a42af91cSHajimu UMEMOTO 				had_error++;
1655a42af91cSHajimu UMEMOTO 				continue;
1656a42af91cSHajimu UMEMOTO 			}
1657d0509082SJacques Vidrine 			strlcpy(bp, tbuf, ep - bp);
1658a42af91cSHajimu UMEMOTO 			canonname = bp;
1659a42af91cSHajimu UMEMOTO 			bp += n;
1660a42af91cSHajimu UMEMOTO 			continue;
1661a42af91cSHajimu UMEMOTO 		}
1662a42af91cSHajimu UMEMOTO 		if (qtype == T_ANY) {
1663a42af91cSHajimu UMEMOTO 			if (!(type == T_A || type == T_AAAA)) {
1664a42af91cSHajimu UMEMOTO 				cp += n;
1665a42af91cSHajimu UMEMOTO 				continue;
1666a42af91cSHajimu UMEMOTO 			}
1667a42af91cSHajimu UMEMOTO 		} else if (type != qtype) {
1668a42af91cSHajimu UMEMOTO #ifdef DEBUG
1669a42af91cSHajimu UMEMOTO 			if (type != T_KEY && type != T_SIG)
1670a42af91cSHajimu UMEMOTO 				syslog(LOG_NOTICE|LOG_AUTH,
1671a42af91cSHajimu UMEMOTO 	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1672a42af91cSHajimu UMEMOTO 				       qname, p_class(C_IN), p_type(qtype),
1673a42af91cSHajimu UMEMOTO 				       p_type(type));
1674a42af91cSHajimu UMEMOTO #endif
1675a42af91cSHajimu UMEMOTO 			cp += n;
1676a42af91cSHajimu UMEMOTO 			continue;		/* XXX - had_error++ ? */
1677a42af91cSHajimu UMEMOTO 		}
1678a42af91cSHajimu UMEMOTO 		switch (type) {
1679a42af91cSHajimu UMEMOTO 		case T_A:
1680a42af91cSHajimu UMEMOTO 		case T_AAAA:
1681a42af91cSHajimu UMEMOTO 			if (strcasecmp(canonname, bp) != 0) {
1682a42af91cSHajimu UMEMOTO #ifdef DEBUG
1683a42af91cSHajimu UMEMOTO 				syslog(LOG_NOTICE|LOG_AUTH,
1684a42af91cSHajimu UMEMOTO 				       AskedForGot, canonname, bp);
1685a42af91cSHajimu UMEMOTO #endif
1686a42af91cSHajimu UMEMOTO 				cp += n;
1687a42af91cSHajimu UMEMOTO 				continue;	/* XXX - had_error++ ? */
1688a42af91cSHajimu UMEMOTO 			}
1689a42af91cSHajimu UMEMOTO 			if (type == T_A && n != INADDRSZ) {
1690a42af91cSHajimu UMEMOTO 				cp += n;
1691a42af91cSHajimu UMEMOTO 				continue;
1692a42af91cSHajimu UMEMOTO 			}
1693a42af91cSHajimu UMEMOTO 			if (type == T_AAAA && n != IN6ADDRSZ) {
1694a42af91cSHajimu UMEMOTO 				cp += n;
1695a42af91cSHajimu UMEMOTO 				continue;
1696a42af91cSHajimu UMEMOTO 			}
1697a42af91cSHajimu UMEMOTO #ifdef FILTER_V4MAPPED
1698a42af91cSHajimu UMEMOTO 			if (type == T_AAAA) {
1699a42af91cSHajimu UMEMOTO 				struct in6_addr in6;
1700a42af91cSHajimu UMEMOTO 				memcpy(&in6, cp, sizeof(in6));
1701a42af91cSHajimu UMEMOTO 				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1702a42af91cSHajimu UMEMOTO 					cp += n;
1703a42af91cSHajimu UMEMOTO 					continue;
1704a42af91cSHajimu UMEMOTO 				}
1705a42af91cSHajimu UMEMOTO 			}
1706a42af91cSHajimu UMEMOTO #endif
1707a42af91cSHajimu UMEMOTO 			if (!haveanswer) {
1708a42af91cSHajimu UMEMOTO 				int nn;
1709a42af91cSHajimu UMEMOTO 
1710a42af91cSHajimu UMEMOTO 				canonname = bp;
1711a42af91cSHajimu UMEMOTO 				nn = strlen(bp) + 1;	/* for the \0 */
1712a42af91cSHajimu UMEMOTO 				bp += nn;
1713a42af91cSHajimu UMEMOTO 			}
1714a42af91cSHajimu UMEMOTO 
1715a42af91cSHajimu UMEMOTO 			/* don't overwrite pai */
1716a42af91cSHajimu UMEMOTO 			ai = *pai;
1717a42af91cSHajimu UMEMOTO 			ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1718a42af91cSHajimu UMEMOTO 			afd = find_afd(ai.ai_family);
1719a42af91cSHajimu UMEMOTO 			if (afd == NULL) {
1720a42af91cSHajimu UMEMOTO 				cp += n;
1721a42af91cSHajimu UMEMOTO 				continue;
1722a42af91cSHajimu UMEMOTO 			}
1723a42af91cSHajimu UMEMOTO 			cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1724a42af91cSHajimu UMEMOTO 			if (cur->ai_next == NULL)
1725a42af91cSHajimu UMEMOTO 				had_error++;
1726a42af91cSHajimu UMEMOTO 			while (cur && cur->ai_next)
1727a42af91cSHajimu UMEMOTO 				cur = cur->ai_next;
1728a42af91cSHajimu UMEMOTO 			cp += n;
1729a42af91cSHajimu UMEMOTO 			break;
1730a42af91cSHajimu UMEMOTO 		default:
1731a42af91cSHajimu UMEMOTO 			abort();
1732a42af91cSHajimu UMEMOTO 		}
1733a42af91cSHajimu UMEMOTO 		if (!had_error)
1734a42af91cSHajimu UMEMOTO 			haveanswer++;
1735a42af91cSHajimu UMEMOTO 	}
1736a42af91cSHajimu UMEMOTO 	if (haveanswer) {
173769b0a4b6SJim Pirzyk #if defined(RESOLVSORT)
173869b0a4b6SJim Pirzyk 		/*
173969b0a4b6SJim Pirzyk 		 * We support only IPv4 address for backward
174069b0a4b6SJim Pirzyk 		 * compatibility against gethostbyname(3).
174169b0a4b6SJim Pirzyk 		 */
174269b0a4b6SJim Pirzyk 		if (_res.nsort && qtype == T_A) {
174369b0a4b6SJim Pirzyk 			if (addr4sort(&sentinel) < 0) {
174469b0a4b6SJim Pirzyk 				freeaddrinfo(sentinel.ai_next);
174569b0a4b6SJim Pirzyk 				h_errno = NO_RECOVERY;
174669b0a4b6SJim Pirzyk 				return NULL;
174769b0a4b6SJim Pirzyk 			}
174869b0a4b6SJim Pirzyk 		}
174969b0a4b6SJim Pirzyk #endif /*RESOLVSORT*/
1750a42af91cSHajimu UMEMOTO 		if (!canonname)
1751a42af91cSHajimu UMEMOTO 			(void)get_canonname(pai, sentinel.ai_next, qname);
1752a42af91cSHajimu UMEMOTO 		else
1753a42af91cSHajimu UMEMOTO 			(void)get_canonname(pai, sentinel.ai_next, canonname);
1754a42af91cSHajimu UMEMOTO 		h_errno = NETDB_SUCCESS;
1755a42af91cSHajimu UMEMOTO 		return sentinel.ai_next;
1756a42af91cSHajimu UMEMOTO 	}
1757a42af91cSHajimu UMEMOTO 
1758a42af91cSHajimu UMEMOTO 	h_errno = NO_RECOVERY;
1759a42af91cSHajimu UMEMOTO 	return NULL;
1760a42af91cSHajimu UMEMOTO }
1761a42af91cSHajimu UMEMOTO 
1762688a5c3eSHajimu UMEMOTO #ifdef RESOLVSORT
1763688a5c3eSHajimu UMEMOTO struct addr_ptr {
1764688a5c3eSHajimu UMEMOTO 	struct addrinfo *ai;
1765688a5c3eSHajimu UMEMOTO 	int aval;
1766688a5c3eSHajimu UMEMOTO };
1767688a5c3eSHajimu UMEMOTO 
1768688a5c3eSHajimu UMEMOTO static int
1769688a5c3eSHajimu UMEMOTO addr4sort(struct addrinfo *sentinel)
1770688a5c3eSHajimu UMEMOTO {
1771688a5c3eSHajimu UMEMOTO 	struct addrinfo *ai;
1772688a5c3eSHajimu UMEMOTO 	struct addr_ptr *addrs, addr;
1773688a5c3eSHajimu UMEMOTO 	struct sockaddr_in *sin;
1774688a5c3eSHajimu UMEMOTO 	int naddrs, i, j;
1775688a5c3eSHajimu UMEMOTO 	int needsort = 0;
1776688a5c3eSHajimu UMEMOTO 
1777688a5c3eSHajimu UMEMOTO 	if (!sentinel)
1778688a5c3eSHajimu UMEMOTO 		return -1;
1779688a5c3eSHajimu UMEMOTO 	naddrs = 0;
1780688a5c3eSHajimu UMEMOTO 	for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
1781688a5c3eSHajimu UMEMOTO 		naddrs++;
1782688a5c3eSHajimu UMEMOTO 	if (naddrs < 2)
1783688a5c3eSHajimu UMEMOTO 		return 0;		/* We don't need sorting. */
1784688a5c3eSHajimu UMEMOTO 	if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
1785688a5c3eSHajimu UMEMOTO 		return -1;
1786688a5c3eSHajimu UMEMOTO 	i = 0;
1787688a5c3eSHajimu UMEMOTO 	for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
1788688a5c3eSHajimu UMEMOTO 		sin = (struct sockaddr_in *)ai->ai_addr;
1789688a5c3eSHajimu UMEMOTO 		for (j = 0; (unsigned)j < _res.nsort; j++) {
1790688a5c3eSHajimu UMEMOTO 			if (_res.sort_list[j].addr.s_addr ==
1791688a5c3eSHajimu UMEMOTO 			    (sin->sin_addr.s_addr & _res.sort_list[j].mask))
1792688a5c3eSHajimu UMEMOTO 				break;
1793688a5c3eSHajimu UMEMOTO 		}
1794688a5c3eSHajimu UMEMOTO 		addrs[i].ai = ai;
1795688a5c3eSHajimu UMEMOTO 		addrs[i].aval = j;
1796688a5c3eSHajimu UMEMOTO 		if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
1797688a5c3eSHajimu UMEMOTO 			needsort = i;
1798688a5c3eSHajimu UMEMOTO 		i++;
1799688a5c3eSHajimu UMEMOTO 	}
1800688a5c3eSHajimu UMEMOTO 	if (!needsort) {
1801688a5c3eSHajimu UMEMOTO 		free(addrs);
1802688a5c3eSHajimu UMEMOTO 		return 0;
1803688a5c3eSHajimu UMEMOTO 	}
1804688a5c3eSHajimu UMEMOTO 
1805688a5c3eSHajimu UMEMOTO 	while (needsort < naddrs) {
1806688a5c3eSHajimu UMEMOTO 	    for (j = needsort - 1; j >= 0; j--) {
1807688a5c3eSHajimu UMEMOTO 		if (addrs[j].aval > addrs[j+1].aval) {
1808688a5c3eSHajimu UMEMOTO 		    addr = addrs[j];
1809688a5c3eSHajimu UMEMOTO 		    addrs[j] = addrs[j + 1];
1810688a5c3eSHajimu UMEMOTO 		    addrs[j + 1] = addr;
1811688a5c3eSHajimu UMEMOTO 		} else
1812688a5c3eSHajimu UMEMOTO 		    break;
1813688a5c3eSHajimu UMEMOTO 	    }
1814688a5c3eSHajimu UMEMOTO 	    needsort++;
1815688a5c3eSHajimu UMEMOTO 	}
1816688a5c3eSHajimu UMEMOTO 
1817688a5c3eSHajimu UMEMOTO 	ai = sentinel;
1818688a5c3eSHajimu UMEMOTO 	for (i = 0; i < naddrs; ++i) {
1819688a5c3eSHajimu UMEMOTO 		ai->ai_next = addrs[i].ai;
1820688a5c3eSHajimu UMEMOTO 		ai = ai->ai_next;
1821688a5c3eSHajimu UMEMOTO 	}
1822688a5c3eSHajimu UMEMOTO 	ai->ai_next = NULL;
1823688a5c3eSHajimu UMEMOTO 	free(addrs);
1824688a5c3eSHajimu UMEMOTO 	return 0;
1825688a5c3eSHajimu UMEMOTO }
1826688a5c3eSHajimu UMEMOTO #endif /*RESOLVSORT*/
1827688a5c3eSHajimu UMEMOTO 
1828a42af91cSHajimu UMEMOTO /*ARGSUSED*/
1829a42af91cSHajimu UMEMOTO static int
1830248aee62SJacques Vidrine _dns_getaddrinfo(rv, cb_data, ap)
1831248aee62SJacques Vidrine 	void	*rv;
1832248aee62SJacques Vidrine 	void	*cb_data;
1833248aee62SJacques Vidrine 	va_list	 ap;
1834a42af91cSHajimu UMEMOTO {
1835a42af91cSHajimu UMEMOTO 	struct addrinfo *ai;
18365cd588cbSHajimu UMEMOTO 	querybuf *buf, *buf2;
1837a42af91cSHajimu UMEMOTO 	const char *name;
1838248aee62SJacques Vidrine 	const struct addrinfo *pai;
1839a42af91cSHajimu UMEMOTO 	struct addrinfo sentinel, *cur;
1840a42af91cSHajimu UMEMOTO 	struct res_target q, q2;
1841a42af91cSHajimu UMEMOTO 
1842248aee62SJacques Vidrine 	name = va_arg(ap, char *);
1843248aee62SJacques Vidrine 	pai = va_arg(ap, const struct addrinfo *);
1844248aee62SJacques Vidrine 
1845a42af91cSHajimu UMEMOTO 	memset(&q, 0, sizeof(q2));
1846a42af91cSHajimu UMEMOTO 	memset(&q2, 0, sizeof(q2));
1847a42af91cSHajimu UMEMOTO 	memset(&sentinel, 0, sizeof(sentinel));
1848a42af91cSHajimu UMEMOTO 	cur = &sentinel;
1849a42af91cSHajimu UMEMOTO 
18505cd588cbSHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
18515cd588cbSHajimu UMEMOTO 	if (!buf) {
18525cd588cbSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
18535cd588cbSHajimu UMEMOTO 		return NS_NOTFOUND;
18545cd588cbSHajimu UMEMOTO 	}
18555cd588cbSHajimu UMEMOTO 	buf2 = malloc(sizeof(*buf2));
18565cd588cbSHajimu UMEMOTO 	if (!buf2) {
18575cd588cbSHajimu UMEMOTO 		free(buf);
18585cd588cbSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
18595cd588cbSHajimu UMEMOTO 		return NS_NOTFOUND;
18605cd588cbSHajimu UMEMOTO 	}
18615cd588cbSHajimu UMEMOTO 
1862a42af91cSHajimu UMEMOTO 	switch (pai->ai_family) {
1863a42af91cSHajimu UMEMOTO 	case AF_UNSPEC:
1864a42af91cSHajimu UMEMOTO 		/* prefer IPv6 */
1865dd521ef1SHajimu UMEMOTO 		q.name = name;
1866b826397aSJun-ichiro itojun Hagino 		q.qclass = C_IN;
1867b826397aSJun-ichiro itojun Hagino 		q.qtype = T_AAAA;
18685cd588cbSHajimu UMEMOTO 		q.answer = buf->buf;
18695cd588cbSHajimu UMEMOTO 		q.anslen = sizeof(buf->buf);
1870a42af91cSHajimu UMEMOTO 		q.next = &q2;
1871a89c1d30SHajimu UMEMOTO 		q2.name = name;
1872b826397aSJun-ichiro itojun Hagino 		q2.qclass = C_IN;
1873b826397aSJun-ichiro itojun Hagino 		q2.qtype = T_A;
18745cd588cbSHajimu UMEMOTO 		q2.answer = buf2->buf;
18755cd588cbSHajimu UMEMOTO 		q2.anslen = sizeof(buf2->buf);
1876a42af91cSHajimu UMEMOTO 		break;
1877a42af91cSHajimu UMEMOTO 	case AF_INET:
1878dd521ef1SHajimu UMEMOTO 		q.name = name;
1879b826397aSJun-ichiro itojun Hagino 		q.qclass = C_IN;
1880b826397aSJun-ichiro itojun Hagino 		q.qtype = T_A;
18815cd588cbSHajimu UMEMOTO 		q.answer = buf->buf;
18825cd588cbSHajimu UMEMOTO 		q.anslen = sizeof(buf->buf);
1883a42af91cSHajimu UMEMOTO 		break;
1884a42af91cSHajimu UMEMOTO 	case AF_INET6:
1885dd521ef1SHajimu UMEMOTO 		q.name = name;
1886b826397aSJun-ichiro itojun Hagino 		q.qclass = C_IN;
1887b826397aSJun-ichiro itojun Hagino 		q.qtype = T_AAAA;
18885cd588cbSHajimu UMEMOTO 		q.answer = buf->buf;
18895cd588cbSHajimu UMEMOTO 		q.anslen = sizeof(buf->buf);
1890a42af91cSHajimu UMEMOTO 		break;
1891a42af91cSHajimu UMEMOTO 	default:
18925cd588cbSHajimu UMEMOTO 		free(buf);
18935cd588cbSHajimu UMEMOTO 		free(buf2);
1894248aee62SJacques Vidrine 		return NS_UNAVAIL;
1895a42af91cSHajimu UMEMOTO 	}
18965cd588cbSHajimu UMEMOTO 	if (res_searchN(name, &q) < 0) {
18975cd588cbSHajimu UMEMOTO 		free(buf);
18985cd588cbSHajimu UMEMOTO 		free(buf2);
1899248aee62SJacques Vidrine 		return NS_NOTFOUND;
19005cd588cbSHajimu UMEMOTO 	}
19015cd588cbSHajimu UMEMOTO 	ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1902a42af91cSHajimu UMEMOTO 	if (ai) {
1903a42af91cSHajimu UMEMOTO 		cur->ai_next = ai;
1904a42af91cSHajimu UMEMOTO 		while (cur && cur->ai_next)
1905a42af91cSHajimu UMEMOTO 			cur = cur->ai_next;
1906a42af91cSHajimu UMEMOTO 	}
1907a42af91cSHajimu UMEMOTO 	if (q.next) {
19085cd588cbSHajimu UMEMOTO 		ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1909a42af91cSHajimu UMEMOTO 		if (ai)
1910a42af91cSHajimu UMEMOTO 			cur->ai_next = ai;
1911a42af91cSHajimu UMEMOTO 	}
19125cd588cbSHajimu UMEMOTO 	free(buf);
19135cd588cbSHajimu UMEMOTO 	free(buf2);
1914a42af91cSHajimu UMEMOTO 	if (sentinel.ai_next == NULL)
1915a42af91cSHajimu UMEMOTO 		switch (h_errno) {
1916a42af91cSHajimu UMEMOTO 		case HOST_NOT_FOUND:
1917248aee62SJacques Vidrine 			return NS_NOTFOUND;
1918a42af91cSHajimu UMEMOTO 		case TRY_AGAIN:
1919248aee62SJacques Vidrine 			return NS_TRYAGAIN;
1920a42af91cSHajimu UMEMOTO 		default:
1921248aee62SJacques Vidrine 			return NS_UNAVAIL;
1922a42af91cSHajimu UMEMOTO 		}
1923248aee62SJacques Vidrine 	*((struct addrinfo **)rv) = sentinel.ai_next;
1924248aee62SJacques Vidrine 	return NS_SUCCESS;
1925248aee62SJacques Vidrine }
1926248aee62SJacques Vidrine 
1927248aee62SJacques Vidrine static void
1928248aee62SJacques Vidrine _sethtent()
1929248aee62SJacques Vidrine {
1930248aee62SJacques Vidrine 	if (!hostf)
1931248aee62SJacques Vidrine 		hostf = fopen(_PATH_HOSTS, "r" );
1932248aee62SJacques Vidrine 	else
1933248aee62SJacques Vidrine 		rewind(hostf);
1934248aee62SJacques Vidrine }
1935248aee62SJacques Vidrine 
1936248aee62SJacques Vidrine static void
1937248aee62SJacques Vidrine _endhtent()
1938248aee62SJacques Vidrine {
1939248aee62SJacques Vidrine 	if (hostf) {
1940248aee62SJacques Vidrine 		(void) fclose(hostf);
1941248aee62SJacques Vidrine 		hostf = NULL;
1942248aee62SJacques Vidrine 	}
1943a42af91cSHajimu UMEMOTO }
1944a42af91cSHajimu UMEMOTO 
1945a42af91cSHajimu UMEMOTO static struct addrinfo *
1946248aee62SJacques Vidrine _gethtent(name, pai)
1947a42af91cSHajimu UMEMOTO 	const char *name;
1948a42af91cSHajimu UMEMOTO 	const struct addrinfo *pai;
1949a42af91cSHajimu UMEMOTO {
1950a42af91cSHajimu UMEMOTO 	char *p;
1951a42af91cSHajimu UMEMOTO 	char *cp, *tname, *cname;
1952a42af91cSHajimu UMEMOTO 	struct addrinfo hints, *res0, *res;
1953a42af91cSHajimu UMEMOTO 	int error;
1954a42af91cSHajimu UMEMOTO 	const char *addr;
1955a42af91cSHajimu UMEMOTO 	char hostbuf[8*1024];
1956a42af91cSHajimu UMEMOTO 
1957248aee62SJacques Vidrine 	if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
1958248aee62SJacques Vidrine 		return (NULL);
1959a42af91cSHajimu UMEMOTO again:
1960a42af91cSHajimu UMEMOTO 	if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
1961a42af91cSHajimu UMEMOTO 		return (NULL);
1962a42af91cSHajimu UMEMOTO 	if (*p == '#')
1963a42af91cSHajimu UMEMOTO 		goto again;
1964a42af91cSHajimu UMEMOTO 	if (!(cp = strpbrk(p, "#\n")))
1965a42af91cSHajimu UMEMOTO 		goto again;
1966a42af91cSHajimu UMEMOTO 	*cp = '\0';
1967a42af91cSHajimu UMEMOTO 	if (!(cp = strpbrk(p, " \t")))
1968a42af91cSHajimu UMEMOTO 		goto again;
1969a42af91cSHajimu UMEMOTO 	*cp++ = '\0';
1970a42af91cSHajimu UMEMOTO 	addr = p;
1971a42af91cSHajimu UMEMOTO 	cname = NULL;
1972a42af91cSHajimu UMEMOTO 	/* if this is not something we're looking for, skip it. */
1973a42af91cSHajimu UMEMOTO 	while (cp && *cp) {
1974a42af91cSHajimu UMEMOTO 		if (*cp == ' ' || *cp == '\t') {
1975a42af91cSHajimu UMEMOTO 			cp++;
1976a42af91cSHajimu UMEMOTO 			continue;
1977a42af91cSHajimu UMEMOTO 		}
1978a42af91cSHajimu UMEMOTO 		tname = cp;
1979a42af91cSHajimu UMEMOTO 		if (cname == NULL)
1980a42af91cSHajimu UMEMOTO 			cname = cp;
1981a42af91cSHajimu UMEMOTO 		if ((cp = strpbrk(cp, " \t")) != NULL)
1982a42af91cSHajimu UMEMOTO 			*cp++ = '\0';
1983a42af91cSHajimu UMEMOTO 		if (strcasecmp(name, tname) == 0)
1984a42af91cSHajimu UMEMOTO 			goto found;
1985a42af91cSHajimu UMEMOTO 	}
1986a42af91cSHajimu UMEMOTO 	goto again;
1987a42af91cSHajimu UMEMOTO 
1988a42af91cSHajimu UMEMOTO found:
1989dd521ef1SHajimu UMEMOTO 	/* we should not glob socktype/protocol here */
1990dd521ef1SHajimu UMEMOTO 	memset(&hints, 0, sizeof(hints));
1991dd521ef1SHajimu UMEMOTO 	hints.ai_family = pai->ai_family;
1992dd521ef1SHajimu UMEMOTO 	hints.ai_socktype = SOCK_DGRAM;
1993dd521ef1SHajimu UMEMOTO 	hints.ai_protocol = 0;
1994a42af91cSHajimu UMEMOTO 	hints.ai_flags = AI_NUMERICHOST;
1995dd521ef1SHajimu UMEMOTO 	error = getaddrinfo(addr, "0", &hints, &res0);
1996a42af91cSHajimu UMEMOTO 	if (error)
1997a42af91cSHajimu UMEMOTO 		goto again;
1998a42af91cSHajimu UMEMOTO #ifdef FILTER_V4MAPPED
1999a42af91cSHajimu UMEMOTO 	/* XXX should check all items in the chain */
2000a42af91cSHajimu UMEMOTO 	if (res0->ai_family == AF_INET6 &&
2001a42af91cSHajimu UMEMOTO 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) {
2002a42af91cSHajimu UMEMOTO 		freeaddrinfo(res0);
2003a42af91cSHajimu UMEMOTO 		goto again;
2004a42af91cSHajimu UMEMOTO 	}
2005a42af91cSHajimu UMEMOTO #endif
2006a42af91cSHajimu UMEMOTO 	for (res = res0; res; res = res->ai_next) {
2007a42af91cSHajimu UMEMOTO 		/* cover it up */
2008a42af91cSHajimu UMEMOTO 		res->ai_flags = pai->ai_flags;
2009dd521ef1SHajimu UMEMOTO 		res->ai_socktype = pai->ai_socktype;
2010dd521ef1SHajimu UMEMOTO 		res->ai_protocol = pai->ai_protocol;
2011a42af91cSHajimu UMEMOTO 
2012a42af91cSHajimu UMEMOTO 		if (pai->ai_flags & AI_CANONNAME) {
2013a42af91cSHajimu UMEMOTO 			if (get_canonname(pai, res, cname) != 0) {
2014a42af91cSHajimu UMEMOTO 				freeaddrinfo(res0);
2015a42af91cSHajimu UMEMOTO 				goto again;
2016a42af91cSHajimu UMEMOTO 			}
2017a42af91cSHajimu UMEMOTO 		}
2018a42af91cSHajimu UMEMOTO 	}
2019a42af91cSHajimu UMEMOTO 	return res0;
2020a42af91cSHajimu UMEMOTO }
2021a42af91cSHajimu UMEMOTO 
2022a42af91cSHajimu UMEMOTO /*ARGSUSED*/
2023a42af91cSHajimu UMEMOTO static int
2024248aee62SJacques Vidrine _files_getaddrinfo(rv, cb_data, ap)
2025248aee62SJacques Vidrine 	void	*rv;
2026248aee62SJacques Vidrine 	void	*cb_data;
2027248aee62SJacques Vidrine 	va_list	 ap;
2028a42af91cSHajimu UMEMOTO {
2029248aee62SJacques Vidrine 	const char *name;
2030248aee62SJacques Vidrine 	const struct addrinfo *pai;
2031a42af91cSHajimu UMEMOTO 	struct addrinfo sentinel, *cur;
2032a42af91cSHajimu UMEMOTO 	struct addrinfo *p;
2033a42af91cSHajimu UMEMOTO 
2034248aee62SJacques Vidrine 	name = va_arg(ap, char *);
2035248aee62SJacques Vidrine 	pai = va_arg(ap, struct addrinfo *);
2036248aee62SJacques Vidrine 
2037248aee62SJacques Vidrine 	memset(&sentinel, 0, sizeof(sentinel));
2038a42af91cSHajimu UMEMOTO 	cur = &sentinel;
2039a42af91cSHajimu UMEMOTO 
2040248aee62SJacques Vidrine 	_sethtent();
2041248aee62SJacques Vidrine 	while ((p = _gethtent(name, pai)) != NULL) {
2042a42af91cSHajimu UMEMOTO 		cur->ai_next = p;
2043a42af91cSHajimu UMEMOTO 		while (cur && cur->ai_next)
2044a42af91cSHajimu UMEMOTO 			cur = cur->ai_next;
2045a42af91cSHajimu UMEMOTO 	}
2046248aee62SJacques Vidrine 	_endhtent();
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 
2155248aee62SJacques Vidrine 	if (!__ypdomain) {
2156248aee62SJacques Vidrine 		if (_yp_check(&__ypdomain) == 0)
2157248aee62SJacques Vidrine 			return NS_UNAVAIL;
2158248aee62SJacques Vidrine 	}
2159248aee62SJacques Vidrine 	if (__ypcurrent)
2160248aee62SJacques Vidrine 		free(__ypcurrent);
2161248aee62SJacques Vidrine 	__ypcurrent = NULL;
2162248aee62SJacques Vidrine 
2163248aee62SJacques Vidrine 	/* hosts.byname is only for IPv4 (Solaris8) */
2164248aee62SJacques Vidrine 	if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
2165248aee62SJacques Vidrine 		r = yp_match(__ypdomain, "hosts.byname", name,
2166248aee62SJacques Vidrine 			(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
2167248aee62SJacques Vidrine 		if (r == 0) {
2168248aee62SJacques Vidrine 			struct addrinfo ai4;
2169248aee62SJacques Vidrine 
2170248aee62SJacques Vidrine 			ai4 = *pai;
2171248aee62SJacques Vidrine 			ai4.ai_family = AF_INET;
2172248aee62SJacques Vidrine 			ai = _yphostent(__ypcurrent, &ai4);
2173248aee62SJacques Vidrine 			if (ai) {
2174248aee62SJacques Vidrine 				cur->ai_next = ai;
2175248aee62SJacques Vidrine 				while (cur && cur->ai_next)
2176248aee62SJacques Vidrine 					cur = cur->ai_next;
2177248aee62SJacques Vidrine 			}
2178248aee62SJacques Vidrine 		}
2179248aee62SJacques Vidrine 	}
2180248aee62SJacques Vidrine 
2181248aee62SJacques Vidrine 	/* ipnodes.byname can hold both IPv4/v6 */
2182248aee62SJacques Vidrine 	r = yp_match(__ypdomain, "ipnodes.byname", name,
2183248aee62SJacques Vidrine 		(int)strlen(name), &__ypcurrent, &__ypcurrentlen);
2184248aee62SJacques Vidrine 	if (r == 0) {
2185248aee62SJacques Vidrine 		ai = _yphostent(__ypcurrent, pai);
2186248aee62SJacques Vidrine 		if (ai) {
2187248aee62SJacques Vidrine 			cur->ai_next = ai;
2188248aee62SJacques Vidrine 			while (cur && cur->ai_next)
2189248aee62SJacques Vidrine 				cur = cur->ai_next;
2190248aee62SJacques Vidrine 		}
2191248aee62SJacques Vidrine 	}
2192248aee62SJacques Vidrine 
2193248aee62SJacques Vidrine 	if (sentinel.ai_next == NULL) {
2194248aee62SJacques Vidrine 		h_errno = HOST_NOT_FOUND;
2195248aee62SJacques Vidrine 		return NS_NOTFOUND;
2196248aee62SJacques Vidrine 	}
2197248aee62SJacques Vidrine 	*((struct addrinfo **)rv) = sentinel.ai_next;
2198248aee62SJacques Vidrine 	return NS_SUCCESS;
2199a42af91cSHajimu UMEMOTO }
2200a42af91cSHajimu UMEMOTO #endif
2201a42af91cSHajimu UMEMOTO 
2202a42af91cSHajimu UMEMOTO /* resolver logic */
2203a42af91cSHajimu UMEMOTO 
2204c05ac53bSDavid E. O'Brien extern const char *__hostalias(const char *);
2205a42af91cSHajimu UMEMOTO extern int h_errno;
2206a42af91cSHajimu UMEMOTO 
2207a42af91cSHajimu UMEMOTO /*
2208a42af91cSHajimu UMEMOTO  * Formulate a normal query, send, and await answer.
2209a42af91cSHajimu UMEMOTO  * Returned answer is placed in supplied buffer "answer".
2210a42af91cSHajimu UMEMOTO  * Perform preliminary check of answer, returning success only
2211a42af91cSHajimu UMEMOTO  * if no error is indicated and the answer count is nonzero.
2212a42af91cSHajimu UMEMOTO  * Return the size of the response on success, -1 on error.
2213a42af91cSHajimu UMEMOTO  * Error number is left in h_errno.
2214a42af91cSHajimu UMEMOTO  *
2215a42af91cSHajimu UMEMOTO  * Caller must parse answer and determine whether it answers the question.
2216a42af91cSHajimu UMEMOTO  */
2217a42af91cSHajimu UMEMOTO static int
2218a42af91cSHajimu UMEMOTO res_queryN(name, target)
2219a42af91cSHajimu UMEMOTO 	const char *name;	/* domain name */
2220a42af91cSHajimu UMEMOTO 	struct res_target *target;
2221a42af91cSHajimu UMEMOTO {
22225cd588cbSHajimu UMEMOTO 	u_char *buf;
2223a42af91cSHajimu UMEMOTO 	HEADER *hp;
2224a42af91cSHajimu UMEMOTO 	int n;
2225a42af91cSHajimu UMEMOTO 	struct res_target *t;
2226a42af91cSHajimu UMEMOTO 	int rcode;
2227a42af91cSHajimu UMEMOTO 	int ancount;
2228a42af91cSHajimu UMEMOTO 
2229a42af91cSHajimu UMEMOTO 	rcode = NOERROR;
2230a42af91cSHajimu UMEMOTO 	ancount = 0;
2231a42af91cSHajimu UMEMOTO 
2232a42af91cSHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2233a42af91cSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
2234a42af91cSHajimu UMEMOTO 		return (-1);
2235a42af91cSHajimu UMEMOTO 	}
2236a42af91cSHajimu UMEMOTO 
22375cd588cbSHajimu UMEMOTO 	buf = malloc(MAXPACKET);
22385cd588cbSHajimu UMEMOTO 	if (!buf) {
22395cd588cbSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
22405cd588cbSHajimu UMEMOTO 		return -1;
22415cd588cbSHajimu UMEMOTO 	}
22425cd588cbSHajimu UMEMOTO 
2243a42af91cSHajimu UMEMOTO 	for (t = target; t; t = t->next) {
2244a42af91cSHajimu UMEMOTO 		int class, type;
2245a42af91cSHajimu UMEMOTO 		u_char *answer;
2246a42af91cSHajimu UMEMOTO 		int anslen;
2247a42af91cSHajimu UMEMOTO 
2248a42af91cSHajimu UMEMOTO 		hp = (HEADER *)(void *)t->answer;
2249a42af91cSHajimu UMEMOTO 		hp->rcode = NOERROR;	/* default */
2250a42af91cSHajimu UMEMOTO 
2251a42af91cSHajimu UMEMOTO 		/* make it easier... */
2252b826397aSJun-ichiro itojun Hagino 		class = t->qclass;
2253b826397aSJun-ichiro itojun Hagino 		type = t->qtype;
2254a42af91cSHajimu UMEMOTO 		answer = t->answer;
2255a42af91cSHajimu UMEMOTO 		anslen = t->anslen;
2256a42af91cSHajimu UMEMOTO #ifdef DEBUG
2257a42af91cSHajimu UMEMOTO 		if (_res.options & RES_DEBUG)
2258a42af91cSHajimu UMEMOTO 			printf(";; res_query(%s, %d, %d)\n", name, class, type);
2259a42af91cSHajimu UMEMOTO #endif
2260a42af91cSHajimu UMEMOTO 
2261a42af91cSHajimu UMEMOTO 		n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
22625cd588cbSHajimu UMEMOTO 		    buf, MAXPACKET);
2263ce6282dbSHajimu UMEMOTO 		if (n > 0 && (_res.options & RES_USE_EDNS0) != 0)
22645cd588cbSHajimu UMEMOTO 			n = res_opt(n, buf, MAXPACKET, anslen);
2265a42af91cSHajimu UMEMOTO 		if (n <= 0) {
2266a42af91cSHajimu UMEMOTO #ifdef DEBUG
2267a42af91cSHajimu UMEMOTO 			if (_res.options & RES_DEBUG)
2268a42af91cSHajimu UMEMOTO 				printf(";; res_query: mkquery failed\n");
2269a42af91cSHajimu UMEMOTO #endif
22705cd588cbSHajimu UMEMOTO 			free(buf);
2271a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2272a42af91cSHajimu UMEMOTO 			return (n);
2273a42af91cSHajimu UMEMOTO 		}
2274a42af91cSHajimu UMEMOTO 		n = res_send(buf, n, answer, anslen);
2275a42af91cSHajimu UMEMOTO #if 0
2276a42af91cSHajimu UMEMOTO 		if (n < 0) {
2277a42af91cSHajimu UMEMOTO #ifdef DEBUG
2278a42af91cSHajimu UMEMOTO 			if (_res.options & RES_DEBUG)
2279a42af91cSHajimu UMEMOTO 				printf(";; res_query: send error\n");
2280a42af91cSHajimu UMEMOTO #endif
22815cd588cbSHajimu UMEMOTO 			free(buf);
2282a42af91cSHajimu UMEMOTO 			h_errno = TRY_AGAIN;
2283a42af91cSHajimu UMEMOTO 			return (n);
2284a42af91cSHajimu UMEMOTO 		}
2285a42af91cSHajimu UMEMOTO #endif
2286a42af91cSHajimu UMEMOTO 
228754384cf3SJacques Vidrine 		if (n < 0 || n > anslen)
228854384cf3SJacques Vidrine 			hp->rcode = FORMERR; /* XXX not very informative */
228954384cf3SJacques Vidrine 		if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
2290a42af91cSHajimu UMEMOTO 			rcode = hp->rcode;	/* record most recent error */
2291a42af91cSHajimu UMEMOTO #ifdef DEBUG
2292a42af91cSHajimu UMEMOTO 			if (_res.options & RES_DEBUG)
2293dd521ef1SHajimu UMEMOTO 				printf(";; rcode = %u, ancount=%u\n", hp->rcode,
2294a42af91cSHajimu UMEMOTO 				    ntohs(hp->ancount));
2295a42af91cSHajimu UMEMOTO #endif
2296a42af91cSHajimu UMEMOTO 			continue;
2297a42af91cSHajimu UMEMOTO 		}
2298a42af91cSHajimu UMEMOTO 
2299a42af91cSHajimu UMEMOTO 		ancount += ntohs(hp->ancount);
2300a42af91cSHajimu UMEMOTO 
2301a42af91cSHajimu UMEMOTO 		t->n = n;
2302a42af91cSHajimu UMEMOTO 	}
2303a42af91cSHajimu UMEMOTO 
23045cd588cbSHajimu UMEMOTO 	free(buf);
23055cd588cbSHajimu UMEMOTO 
2306a42af91cSHajimu UMEMOTO 	if (ancount == 0) {
2307a42af91cSHajimu UMEMOTO 		switch (rcode) {
2308a42af91cSHajimu UMEMOTO 		case NXDOMAIN:
2309a42af91cSHajimu UMEMOTO 			h_errno = HOST_NOT_FOUND;
2310a42af91cSHajimu UMEMOTO 			break;
2311a42af91cSHajimu UMEMOTO 		case SERVFAIL:
2312a42af91cSHajimu UMEMOTO 			h_errno = TRY_AGAIN;
2313a42af91cSHajimu UMEMOTO 			break;
2314a42af91cSHajimu UMEMOTO 		case NOERROR:
2315a42af91cSHajimu UMEMOTO 			h_errno = NO_DATA;
2316a42af91cSHajimu UMEMOTO 			break;
2317a42af91cSHajimu UMEMOTO 		case FORMERR:
2318a42af91cSHajimu UMEMOTO 		case NOTIMP:
2319a42af91cSHajimu UMEMOTO 		case REFUSED:
2320a42af91cSHajimu UMEMOTO 		default:
2321a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2322a42af91cSHajimu UMEMOTO 			break;
2323a42af91cSHajimu UMEMOTO 		}
2324a42af91cSHajimu UMEMOTO 		return (-1);
2325a42af91cSHajimu UMEMOTO 	}
2326a42af91cSHajimu UMEMOTO 	return (ancount);
2327a42af91cSHajimu UMEMOTO }
2328a42af91cSHajimu UMEMOTO 
2329a42af91cSHajimu UMEMOTO /*
2330a42af91cSHajimu UMEMOTO  * Formulate a normal query, send, and retrieve answer in supplied buffer.
2331a42af91cSHajimu UMEMOTO  * Return the size of the response on success, -1 on error.
2332a42af91cSHajimu UMEMOTO  * If enabled, implement search rules until answer or unrecoverable failure
2333a42af91cSHajimu UMEMOTO  * is detected.  Error code, if any, is left in h_errno.
2334a42af91cSHajimu UMEMOTO  */
2335a42af91cSHajimu UMEMOTO static int
2336a42af91cSHajimu UMEMOTO res_searchN(name, target)
2337a42af91cSHajimu UMEMOTO 	const char *name;	/* domain name */
2338a42af91cSHajimu UMEMOTO 	struct res_target *target;
2339a42af91cSHajimu UMEMOTO {
2340a42af91cSHajimu UMEMOTO 	const char *cp, * const *domain;
2341a42af91cSHajimu UMEMOTO 	HEADER *hp = (HEADER *)(void *)target->answer;	/*XXX*/
2342a42af91cSHajimu UMEMOTO 	u_int dots;
2343a42af91cSHajimu UMEMOTO 	int trailing_dot, ret, saved_herrno;
2344a42af91cSHajimu UMEMOTO 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
2345a42af91cSHajimu UMEMOTO 
2346a42af91cSHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2347a42af91cSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
2348a42af91cSHajimu UMEMOTO 		return (-1);
2349a42af91cSHajimu UMEMOTO 	}
2350a42af91cSHajimu UMEMOTO 
2351a42af91cSHajimu UMEMOTO 	errno = 0;
2352a42af91cSHajimu UMEMOTO 	h_errno = HOST_NOT_FOUND;	/* default, if we never query */
2353a42af91cSHajimu UMEMOTO 	dots = 0;
2354a42af91cSHajimu UMEMOTO 	for (cp = name; *cp; cp++)
2355a42af91cSHajimu UMEMOTO 		dots += (*cp == '.');
2356a42af91cSHajimu UMEMOTO 	trailing_dot = 0;
2357a42af91cSHajimu UMEMOTO 	if (cp > name && *--cp == '.')
2358a42af91cSHajimu UMEMOTO 		trailing_dot++;
2359a42af91cSHajimu UMEMOTO 
2360a42af91cSHajimu UMEMOTO 	/*
2361a42af91cSHajimu UMEMOTO 	 * if there aren't any dots, it could be a user-level alias
2362a42af91cSHajimu UMEMOTO 	 */
2363a42af91cSHajimu UMEMOTO 	if (!dots && (cp = __hostalias(name)) != NULL)
2364a42af91cSHajimu UMEMOTO 		return (res_queryN(cp, target));
2365a42af91cSHajimu UMEMOTO 
2366a42af91cSHajimu UMEMOTO 	/*
2367a42af91cSHajimu UMEMOTO 	 * If there are dots in the name already, let's just give it a try
2368a42af91cSHajimu UMEMOTO 	 * 'as is'.  The threshold can be set with the "ndots" option.
2369a42af91cSHajimu UMEMOTO 	 */
2370a42af91cSHajimu UMEMOTO 	saved_herrno = -1;
2371a42af91cSHajimu UMEMOTO 	if (dots >= _res.ndots) {
2372a42af91cSHajimu UMEMOTO 		ret = res_querydomainN(name, NULL, target);
2373a42af91cSHajimu UMEMOTO 		if (ret > 0)
2374a42af91cSHajimu UMEMOTO 			return (ret);
2375a42af91cSHajimu UMEMOTO 		saved_herrno = h_errno;
2376a42af91cSHajimu UMEMOTO 		tried_as_is++;
2377a42af91cSHajimu UMEMOTO 	}
2378a42af91cSHajimu UMEMOTO 
2379a42af91cSHajimu UMEMOTO 	/*
2380a42af91cSHajimu UMEMOTO 	 * We do at least one level of search if
2381a42af91cSHajimu UMEMOTO 	 *	- there is no dot and RES_DEFNAME is set, or
2382a42af91cSHajimu UMEMOTO 	 *	- there is at least one dot, there is no trailing dot,
2383a42af91cSHajimu UMEMOTO 	 *	  and RES_DNSRCH is set.
2384a42af91cSHajimu UMEMOTO 	 */
2385a42af91cSHajimu UMEMOTO 	if ((!dots && (_res.options & RES_DEFNAMES)) ||
2386a42af91cSHajimu UMEMOTO 	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
2387a42af91cSHajimu UMEMOTO 		int done = 0;
2388a42af91cSHajimu UMEMOTO 
2389a42af91cSHajimu UMEMOTO 		for (domain = (const char * const *)_res.dnsrch;
2390a42af91cSHajimu UMEMOTO 		   *domain && !done;
2391a42af91cSHajimu UMEMOTO 		   domain++) {
2392a42af91cSHajimu UMEMOTO 
2393a42af91cSHajimu UMEMOTO 			ret = res_querydomainN(name, *domain, target);
2394a42af91cSHajimu UMEMOTO 			if (ret > 0)
2395a42af91cSHajimu UMEMOTO 				return (ret);
2396a42af91cSHajimu UMEMOTO 
2397a42af91cSHajimu UMEMOTO 			/*
2398a42af91cSHajimu UMEMOTO 			 * If no server present, give up.
2399a42af91cSHajimu UMEMOTO 			 * If name isn't found in this domain,
2400a42af91cSHajimu UMEMOTO 			 * keep trying higher domains in the search list
2401a42af91cSHajimu UMEMOTO 			 * (if that's enabled).
2402a42af91cSHajimu UMEMOTO 			 * On a NO_DATA error, keep trying, otherwise
2403a42af91cSHajimu UMEMOTO 			 * a wildcard entry of another type could keep us
2404a42af91cSHajimu UMEMOTO 			 * from finding this entry higher in the domain.
2405a42af91cSHajimu UMEMOTO 			 * If we get some other error (negative answer or
2406a42af91cSHajimu UMEMOTO 			 * server failure), then stop searching up,
2407a42af91cSHajimu UMEMOTO 			 * but try the input name below in case it's
2408a42af91cSHajimu UMEMOTO 			 * fully-qualified.
2409a42af91cSHajimu UMEMOTO 			 */
2410a42af91cSHajimu UMEMOTO 			if (errno == ECONNREFUSED) {
2411a42af91cSHajimu UMEMOTO 				h_errno = TRY_AGAIN;
2412a42af91cSHajimu UMEMOTO 				return (-1);
2413a42af91cSHajimu UMEMOTO 			}
2414a42af91cSHajimu UMEMOTO 
2415a42af91cSHajimu UMEMOTO 			switch (h_errno) {
2416a42af91cSHajimu UMEMOTO 			case NO_DATA:
2417a42af91cSHajimu UMEMOTO 				got_nodata++;
2418a42af91cSHajimu UMEMOTO 				/* FALLTHROUGH */
2419a42af91cSHajimu UMEMOTO 			case HOST_NOT_FOUND:
2420a42af91cSHajimu UMEMOTO 				/* keep trying */
2421a42af91cSHajimu UMEMOTO 				break;
2422a42af91cSHajimu UMEMOTO 			case TRY_AGAIN:
2423a42af91cSHajimu UMEMOTO 				if (hp->rcode == SERVFAIL) {
2424a42af91cSHajimu UMEMOTO 					/* try next search element, if any */
2425a42af91cSHajimu UMEMOTO 					got_servfail++;
2426a42af91cSHajimu UMEMOTO 					break;
2427a42af91cSHajimu UMEMOTO 				}
2428a42af91cSHajimu UMEMOTO 				/* FALLTHROUGH */
2429a42af91cSHajimu UMEMOTO 			default:
2430a42af91cSHajimu UMEMOTO 				/* anything else implies that we're done */
2431a42af91cSHajimu UMEMOTO 				done++;
2432a42af91cSHajimu UMEMOTO 			}
2433a42af91cSHajimu UMEMOTO 			/*
2434a42af91cSHajimu UMEMOTO 			 * if we got here for some reason other than DNSRCH,
2435a42af91cSHajimu UMEMOTO 			 * we only wanted one iteration of the loop, so stop.
2436a42af91cSHajimu UMEMOTO 			 */
2437a42af91cSHajimu UMEMOTO 			if (!(_res.options & RES_DNSRCH))
2438a42af91cSHajimu UMEMOTO 			        done++;
2439a42af91cSHajimu UMEMOTO 		}
2440a42af91cSHajimu UMEMOTO 	}
2441a42af91cSHajimu UMEMOTO 
2442a42af91cSHajimu UMEMOTO 	/*
2443a42af91cSHajimu UMEMOTO 	 * if we have not already tried the name "as is", do that now.
2444a42af91cSHajimu UMEMOTO 	 * note that we do this regardless of how many dots were in the
2445a42af91cSHajimu UMEMOTO 	 * name or whether it ends with a dot.
2446a42af91cSHajimu UMEMOTO 	 */
2447a42af91cSHajimu UMEMOTO 	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
2448a42af91cSHajimu UMEMOTO 		ret = res_querydomainN(name, NULL, target);
2449a42af91cSHajimu UMEMOTO 		if (ret > 0)
2450a42af91cSHajimu UMEMOTO 			return (ret);
2451a42af91cSHajimu UMEMOTO 	}
2452a42af91cSHajimu UMEMOTO 
2453a42af91cSHajimu UMEMOTO 	/*
2454a42af91cSHajimu UMEMOTO 	 * if we got here, we didn't satisfy the search.
2455a42af91cSHajimu UMEMOTO 	 * if we did an initial full query, return that query's h_errno
2456a42af91cSHajimu UMEMOTO 	 * (note that we wouldn't be here if that query had succeeded).
2457a42af91cSHajimu UMEMOTO 	 * else if we ever got a nodata, send that back as the reason.
2458a42af91cSHajimu UMEMOTO 	 * else send back meaningless h_errno, that being the one from
2459a42af91cSHajimu UMEMOTO 	 * the last DNSRCH we did.
2460a42af91cSHajimu UMEMOTO 	 */
2461a42af91cSHajimu UMEMOTO 	if (saved_herrno != -1)
2462a42af91cSHajimu UMEMOTO 		h_errno = saved_herrno;
2463a42af91cSHajimu UMEMOTO 	else if (got_nodata)
2464a42af91cSHajimu UMEMOTO 		h_errno = NO_DATA;
2465a42af91cSHajimu UMEMOTO 	else if (got_servfail)
2466a42af91cSHajimu UMEMOTO 		h_errno = TRY_AGAIN;
2467a42af91cSHajimu UMEMOTO 	return (-1);
2468a42af91cSHajimu UMEMOTO }
2469a42af91cSHajimu UMEMOTO 
2470a42af91cSHajimu UMEMOTO /*
2471a42af91cSHajimu UMEMOTO  * Perform a call on res_query on the concatenation of name and domain,
2472a42af91cSHajimu UMEMOTO  * removing a trailing dot from name if domain is NULL.
2473a42af91cSHajimu UMEMOTO  */
2474a42af91cSHajimu UMEMOTO static int
2475a42af91cSHajimu UMEMOTO res_querydomainN(name, domain, target)
2476a42af91cSHajimu UMEMOTO 	const char *name, *domain;
2477a42af91cSHajimu UMEMOTO 	struct res_target *target;
2478a42af91cSHajimu UMEMOTO {
2479a42af91cSHajimu UMEMOTO 	char nbuf[MAXDNAME];
2480a42af91cSHajimu UMEMOTO 	const char *longname = nbuf;
2481a42af91cSHajimu UMEMOTO 	size_t n, d;
2482a42af91cSHajimu UMEMOTO 
2483a42af91cSHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
2484a42af91cSHajimu UMEMOTO 		h_errno = NETDB_INTERNAL;
2485a42af91cSHajimu UMEMOTO 		return (-1);
2486a42af91cSHajimu UMEMOTO 	}
2487a42af91cSHajimu UMEMOTO #ifdef DEBUG
2488a42af91cSHajimu UMEMOTO 	if (_res.options & RES_DEBUG)
2489a42af91cSHajimu UMEMOTO 		printf(";; res_querydomain(%s, %s)\n",
2490a42af91cSHajimu UMEMOTO 			name, domain?domain:"<Nil>");
2491a42af91cSHajimu UMEMOTO #endif
2492a42af91cSHajimu UMEMOTO 	if (domain == NULL) {
2493a42af91cSHajimu UMEMOTO 		/*
2494a42af91cSHajimu UMEMOTO 		 * Check for trailing '.';
2495a42af91cSHajimu UMEMOTO 		 * copy without '.' if present.
2496a42af91cSHajimu UMEMOTO 		 */
2497a42af91cSHajimu UMEMOTO 		n = strlen(name);
2498a42af91cSHajimu UMEMOTO 		if (n >= MAXDNAME) {
2499a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2500a42af91cSHajimu UMEMOTO 			return (-1);
2501a42af91cSHajimu UMEMOTO 		}
2502a42af91cSHajimu UMEMOTO 		if (n > 0 && name[--n] == '.') {
2503a42af91cSHajimu UMEMOTO 			strncpy(nbuf, name, n);
2504a42af91cSHajimu UMEMOTO 			nbuf[n] = '\0';
2505a42af91cSHajimu UMEMOTO 		} else
2506a42af91cSHajimu UMEMOTO 			longname = name;
2507a42af91cSHajimu UMEMOTO 	} else {
2508a42af91cSHajimu UMEMOTO 		n = strlen(name);
2509a42af91cSHajimu UMEMOTO 		d = strlen(domain);
2510a42af91cSHajimu UMEMOTO 		if (n + d + 1 >= MAXDNAME) {
2511a42af91cSHajimu UMEMOTO 			h_errno = NO_RECOVERY;
2512a42af91cSHajimu UMEMOTO 			return (-1);
2513a42af91cSHajimu UMEMOTO 		}
2514dd521ef1SHajimu UMEMOTO 		snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
2515a42af91cSHajimu UMEMOTO 	}
2516a42af91cSHajimu UMEMOTO 	return (res_queryN(longname, target));
2517a42af91cSHajimu UMEMOTO }
2518