xref: /minix/external/bsd/bind/dist/lib/irs/getaddrinfo.c (revision 00b67f09)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: getaddrinfo.c,v 1.7 2014/12/10 04:37:59 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2009, 2012-2014  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  *
6*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek  *
10*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek  */
18*00b67f09SDavid van Moolenbroek 
19*00b67f09SDavid van Moolenbroek /* Id: getaddrinfo.c,v 1.3 2009/09/02 23:48:02 tbox Exp  */
20*00b67f09SDavid van Moolenbroek 
21*00b67f09SDavid van Moolenbroek /*! \file */
22*00b67f09SDavid van Moolenbroek 
23*00b67f09SDavid van Moolenbroek /**
24*00b67f09SDavid van Moolenbroek  *    getaddrinfo() is used to get a list of IP addresses and port
25*00b67f09SDavid van Moolenbroek  *    numbers for host hostname and service servname as defined in RFC3493.
26*00b67f09SDavid van Moolenbroek  *    hostname and servname are pointers to null-terminated strings
27*00b67f09SDavid van Moolenbroek  *    or NULL. hostname is either a host name or a numeric host address
28*00b67f09SDavid van Moolenbroek  *    string: a dotted decimal IPv4 address or an IPv6 address. servname is
29*00b67f09SDavid van Moolenbroek  *    either a decimal port number or a service name as listed in
30*00b67f09SDavid van Moolenbroek  *    /etc/services.
31*00b67f09SDavid van Moolenbroek  *
32*00b67f09SDavid van Moolenbroek  *    If the operating system does not provide a struct addrinfo, the
33*00b67f09SDavid van Moolenbroek  *    following structure is used:
34*00b67f09SDavid van Moolenbroek  *
35*00b67f09SDavid van Moolenbroek  * \code
36*00b67f09SDavid van Moolenbroek  * struct  addrinfo {
37*00b67f09SDavid van Moolenbroek  *         int             ai_flags;       // AI_PASSIVE, AI_CANONNAME
38*00b67f09SDavid van Moolenbroek  *         int             ai_family;      // PF_xxx
39*00b67f09SDavid van Moolenbroek  *         int             ai_socktype;    // SOCK_xxx
40*00b67f09SDavid van Moolenbroek  *         int             ai_protocol;    // 0 or IPPROTO_xxx for IPv4 and IPv6
41*00b67f09SDavid van Moolenbroek  *         size_t          ai_addrlen;     // length of ai_addr
42*00b67f09SDavid van Moolenbroek  *         char            *ai_canonname;  // canonical name for hostname
43*00b67f09SDavid van Moolenbroek  *         struct sockaddr *ai_addr;       // binary address
44*00b67f09SDavid van Moolenbroek  *         struct addrinfo *ai_next;       // next structure in linked list
45*00b67f09SDavid van Moolenbroek  * };
46*00b67f09SDavid van Moolenbroek  * \endcode
47*00b67f09SDavid van Moolenbroek  *
48*00b67f09SDavid van Moolenbroek  *
49*00b67f09SDavid van Moolenbroek  *    hints is an optional pointer to a struct addrinfo. This structure can
50*00b67f09SDavid van Moolenbroek  *    be used to provide hints concerning the type of socket that the caller
51*00b67f09SDavid van Moolenbroek  *    supports or wishes to use. The caller can supply the following
52*00b67f09SDavid van Moolenbroek  *    structure elements in *hints:
53*00b67f09SDavid van Moolenbroek  *
54*00b67f09SDavid van Moolenbroek  * <ul>
55*00b67f09SDavid van Moolenbroek  *    <li>ai_family:
56*00b67f09SDavid van Moolenbroek  *           The protocol family that should be used. When ai_family is set
57*00b67f09SDavid van Moolenbroek  *           to PF_UNSPEC, it means the caller will accept any protocol
58*00b67f09SDavid van Moolenbroek  *           family supported by the operating system.</li>
59*00b67f09SDavid van Moolenbroek  *
60*00b67f09SDavid van Moolenbroek  *    <li>ai_socktype:
61*00b67f09SDavid van Moolenbroek  *           denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
62*00b67f09SDavid van Moolenbroek  *           SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
63*00b67f09SDavid van Moolenbroek  *           will accept any socket type.</li>
64*00b67f09SDavid van Moolenbroek  *
65*00b67f09SDavid van Moolenbroek  *    <li>ai_protocol:
66*00b67f09SDavid van Moolenbroek  *           indicates which transport protocol is wanted: IPPROTO_UDP or
67*00b67f09SDavid van Moolenbroek  *           IPPROTO_TCP. If ai_protocol is zero the caller will accept any
68*00b67f09SDavid van Moolenbroek  *           protocol.</li>
69*00b67f09SDavid van Moolenbroek  *
70*00b67f09SDavid van Moolenbroek  *    <li>ai_flags:
71*00b67f09SDavid van Moolenbroek  *           Flag bits. If the AI_CANONNAME bit is set, a successful call to
72*00b67f09SDavid van Moolenbroek  *           getaddrinfo() will return a null-terminated string
73*00b67f09SDavid van Moolenbroek  *           containing the canonical name of the specified hostname in
74*00b67f09SDavid van Moolenbroek  *           ai_canonname of the first addrinfo structure returned. Setting
75*00b67f09SDavid van Moolenbroek  *           the AI_PASSIVE bit indicates that the returned socket address
76*00b67f09SDavid van Moolenbroek  *           structure is intended for used in a call to bind(2). In this
77*00b67f09SDavid van Moolenbroek  *           case, if the hostname argument is a NULL pointer, then the IP
78*00b67f09SDavid van Moolenbroek  *           address portion of the socket address structure will be set to
79*00b67f09SDavid van Moolenbroek  *           INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
80*00b67f09SDavid van Moolenbroek  *           address.<br /><br />
81*00b67f09SDavid van Moolenbroek  *
82*00b67f09SDavid van Moolenbroek  *           When ai_flags does not set the AI_PASSIVE bit, the returned
83*00b67f09SDavid van Moolenbroek  *           socket address structure will be ready for use in a call to
84*00b67f09SDavid van Moolenbroek  *           connect(2) for a connection-oriented protocol or connect(2),
85*00b67f09SDavid van Moolenbroek  *           sendto(2), or sendmsg(2) if a connectionless protocol was
86*00b67f09SDavid van Moolenbroek  *           chosen. The IP address portion of the socket address structure
87*00b67f09SDavid van Moolenbroek  *           will be set to the loopback address if hostname is a NULL
88*00b67f09SDavid van Moolenbroek  *           pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
89*00b67f09SDavid van Moolenbroek  *
90*00b67f09SDavid van Moolenbroek  *           If ai_flags is set to AI_NUMERICHOST it indicates that hostname
91*00b67f09SDavid van Moolenbroek  *           should be treated as a numeric string defining an IPv4 or IPv6
92*00b67f09SDavid van Moolenbroek  *           address and no name resolution should be attempted.
93*00b67f09SDavid van Moolenbroek  * </li></ul>
94*00b67f09SDavid van Moolenbroek  *
95*00b67f09SDavid van Moolenbroek  *    All other elements of the struct addrinfo passed via hints must be
96*00b67f09SDavid van Moolenbroek  *    zero.
97*00b67f09SDavid van Moolenbroek  *
98*00b67f09SDavid van Moolenbroek  *    A hints of NULL is treated as if the caller provided a struct addrinfo
99*00b67f09SDavid van Moolenbroek  *    initialized to zero with ai_familyset to PF_UNSPEC.
100*00b67f09SDavid van Moolenbroek  *
101*00b67f09SDavid van Moolenbroek  *    After a successful call to getaddrinfo(), *res is a pointer to a
102*00b67f09SDavid van Moolenbroek  *    linked list of one or more addrinfo structures. Each struct addrinfo
103*00b67f09SDavid van Moolenbroek  *    in this list cn be processed by following the ai_next pointer, until a
104*00b67f09SDavid van Moolenbroek  *    NULL pointer is encountered. The three members ai_family, ai_socktype,
105*00b67f09SDavid van Moolenbroek  *    and ai_protocol in each returned addrinfo structure contain the
106*00b67f09SDavid van Moolenbroek  *    corresponding arguments for a call to socket(2). For each addrinfo
107*00b67f09SDavid van Moolenbroek  *    structure in the list, the ai_addr member points to a filled-in socket
108*00b67f09SDavid van Moolenbroek  *    address structure of length ai_addrlen.
109*00b67f09SDavid van Moolenbroek  *
110*00b67f09SDavid van Moolenbroek  *    All of the information returned by getaddrinfo() is dynamically
111*00b67f09SDavid van Moolenbroek  *    allocated: the addrinfo structures, and the socket address structures
112*00b67f09SDavid van Moolenbroek  *    and canonical host name strings pointed to by the addrinfostructures.
113*00b67f09SDavid van Moolenbroek  *    Memory allocated for the dynamically allocated structures created by a
114*00b67f09SDavid van Moolenbroek  *    successful call to getaddrinfo() is released by freeaddrinfo().
115*00b67f09SDavid van Moolenbroek  *    ai is a pointer to a struct addrinfo created by a call to getaddrinfo().
116*00b67f09SDavid van Moolenbroek  *
117*00b67f09SDavid van Moolenbroek  * \section irsreturn RETURN VALUES
118*00b67f09SDavid van Moolenbroek  *
119*00b67f09SDavid van Moolenbroek  *    getaddrinfo() returns zero on success or one of the error codes
120*00b67f09SDavid van Moolenbroek  *    listed in gai_strerror() if an error occurs. If both hostname and
121*00b67f09SDavid van Moolenbroek  *    servname are NULL getaddrinfo() returns #EAI_NONAME.
122*00b67f09SDavid van Moolenbroek  *
123*00b67f09SDavid van Moolenbroek  * \section irssee SEE ALSO
124*00b67f09SDavid van Moolenbroek  *
125*00b67f09SDavid van Moolenbroek  *    getaddrinfo(), freeaddrinfo(),
126*00b67f09SDavid van Moolenbroek  *    gai_strerror(), RFC3493, getservbyname(3), connect(2),
127*00b67f09SDavid van Moolenbroek  *    sendto(2), sendmsg(2), socket(2).
128*00b67f09SDavid van Moolenbroek  */
129*00b67f09SDavid van Moolenbroek 
130*00b67f09SDavid van Moolenbroek #include <config.h>
131*00b67f09SDavid van Moolenbroek 
132*00b67f09SDavid van Moolenbroek #include <stdlib.h>
133*00b67f09SDavid van Moolenbroek #include <string.h>
134*00b67f09SDavid van Moolenbroek #include <errno.h>
135*00b67f09SDavid van Moolenbroek 
136*00b67f09SDavid van Moolenbroek #include <isc/app.h>
137*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
138*00b67f09SDavid van Moolenbroek #include <isc/lib.h>
139*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
140*00b67f09SDavid van Moolenbroek #include <isc/sockaddr.h>
141*00b67f09SDavid van Moolenbroek #include <isc/string.h>
142*00b67f09SDavid van Moolenbroek #include <isc/util.h>
143*00b67f09SDavid van Moolenbroek 
144*00b67f09SDavid van Moolenbroek #include <dns/client.h>
145*00b67f09SDavid van Moolenbroek #include <dns/fixedname.h>
146*00b67f09SDavid van Moolenbroek #include <dns/name.h>
147*00b67f09SDavid van Moolenbroek #include <dns/rdata.h>
148*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
149*00b67f09SDavid van Moolenbroek #include <dns/rdatastruct.h>
150*00b67f09SDavid van Moolenbroek #include <dns/rdatatype.h>
151*00b67f09SDavid van Moolenbroek #include <dns/result.h>
152*00b67f09SDavid van Moolenbroek 
153*00b67f09SDavid van Moolenbroek #include <irs/context.h>
154*00b67f09SDavid van Moolenbroek #include <irs/netdb.h>
155*00b67f09SDavid van Moolenbroek #include <irs/resconf.h>
156*00b67f09SDavid van Moolenbroek 
157*00b67f09SDavid van Moolenbroek #define SA(addr)	((struct sockaddr *)(addr))
158*00b67f09SDavid van Moolenbroek #define SIN(addr)	((struct sockaddr_in *)(addr))
159*00b67f09SDavid van Moolenbroek #define SIN6(addr)	((struct sockaddr_in6 *)(addr))
160*00b67f09SDavid van Moolenbroek #define SLOCAL(addr)	((struct sockaddr_un *)(addr))
161*00b67f09SDavid van Moolenbroek 
162*00b67f09SDavid van Moolenbroek /*! \struct addrinfo
163*00b67f09SDavid van Moolenbroek  */
164*00b67f09SDavid van Moolenbroek static struct addrinfo
165*00b67f09SDavid van Moolenbroek 	*ai_concat(struct addrinfo *ai1, struct addrinfo *ai2),
166*00b67f09SDavid van Moolenbroek 	*ai_reverse(struct addrinfo *oai),
167*00b67f09SDavid van Moolenbroek 	*ai_clone(struct addrinfo *oai, int family),
168*00b67f09SDavid van Moolenbroek 	*ai_alloc(int family, int addrlen);
169*00b67f09SDavid van Moolenbroek #ifdef AF_LOCAL
170*00b67f09SDavid van Moolenbroek static int get_local(const char *name, int socktype, struct addrinfo **res);
171*00b67f09SDavid van Moolenbroek #endif
172*00b67f09SDavid van Moolenbroek 
173*00b67f09SDavid van Moolenbroek static int
174*00b67f09SDavid van Moolenbroek resolve_name(int family, const char *hostname, int flags,
175*00b67f09SDavid van Moolenbroek 	     struct addrinfo **aip, int socktype, int port);
176*00b67f09SDavid van Moolenbroek 
177*00b67f09SDavid van Moolenbroek static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
178*00b67f09SDavid van Moolenbroek 		    int socktype, int port);
179*00b67f09SDavid van Moolenbroek static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
180*00b67f09SDavid van Moolenbroek 		    int socktype, int port);
181*00b67f09SDavid van Moolenbroek static void set_order(int, int (**)(const char *, int, struct addrinfo **,
182*00b67f09SDavid van Moolenbroek 				    int, int));
183*00b67f09SDavid van Moolenbroek static void _freeaddrinfo(struct addrinfo *ai);
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek #define FOUND_IPV4	0x1
186*00b67f09SDavid van Moolenbroek #define FOUND_IPV6	0x2
187*00b67f09SDavid van Moolenbroek #define FOUND_MAX	2
188*00b67f09SDavid van Moolenbroek 
189*00b67f09SDavid van Moolenbroek #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
190*00b67f09SDavid van Moolenbroek /*%
191*00b67f09SDavid van Moolenbroek  * Get a list of IP addresses and port numbers for host hostname and
192*00b67f09SDavid van Moolenbroek  * service servname.
193*00b67f09SDavid van Moolenbroek  */
194*00b67f09SDavid van Moolenbroek int
getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** res)195*00b67f09SDavid van Moolenbroek getaddrinfo(const char *hostname, const char *servname,
196*00b67f09SDavid van Moolenbroek 	    const struct addrinfo *hints, struct addrinfo **res)
197*00b67f09SDavid van Moolenbroek {
198*00b67f09SDavid van Moolenbroek 	struct servent *sp;
199*00b67f09SDavid van Moolenbroek 	const char *proto;
200*00b67f09SDavid van Moolenbroek 	int family, socktype, flags, protocol;
201*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai, *ai_list;
202*00b67f09SDavid van Moolenbroek 	int err = 0;
203*00b67f09SDavid van Moolenbroek 	int port, i;
204*00b67f09SDavid van Moolenbroek 	int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
205*00b67f09SDavid van Moolenbroek 				      int, int);
206*00b67f09SDavid van Moolenbroek 
207*00b67f09SDavid van Moolenbroek 	if (hostname == NULL && servname == NULL)
208*00b67f09SDavid van Moolenbroek 		return (EAI_NONAME);
209*00b67f09SDavid van Moolenbroek 
210*00b67f09SDavid van Moolenbroek 	proto = NULL;
211*00b67f09SDavid van Moolenbroek 	if (hints != NULL) {
212*00b67f09SDavid van Moolenbroek 		if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
213*00b67f09SDavid van Moolenbroek 			return (EAI_BADFLAGS);
214*00b67f09SDavid van Moolenbroek 		if (hints->ai_addrlen || hints->ai_canonname ||
215*00b67f09SDavid van Moolenbroek 		    hints->ai_addr || hints->ai_next) {
216*00b67f09SDavid van Moolenbroek 			errno = EINVAL;
217*00b67f09SDavid van Moolenbroek 			return (EAI_SYSTEM);
218*00b67f09SDavid van Moolenbroek 		}
219*00b67f09SDavid van Moolenbroek 		family = hints->ai_family;
220*00b67f09SDavid van Moolenbroek 		socktype = hints->ai_socktype;
221*00b67f09SDavid van Moolenbroek 		protocol = hints->ai_protocol;
222*00b67f09SDavid van Moolenbroek 		flags = hints->ai_flags;
223*00b67f09SDavid van Moolenbroek 		switch (family) {
224*00b67f09SDavid van Moolenbroek 		case AF_UNSPEC:
225*00b67f09SDavid van Moolenbroek 			switch (hints->ai_socktype) {
226*00b67f09SDavid van Moolenbroek 			case SOCK_STREAM:
227*00b67f09SDavid van Moolenbroek 				proto = "tcp";
228*00b67f09SDavid van Moolenbroek 				break;
229*00b67f09SDavid van Moolenbroek 			case SOCK_DGRAM:
230*00b67f09SDavid van Moolenbroek 				proto = "udp";
231*00b67f09SDavid van Moolenbroek 				break;
232*00b67f09SDavid van Moolenbroek 			}
233*00b67f09SDavid van Moolenbroek 			break;
234*00b67f09SDavid van Moolenbroek 		case AF_INET:
235*00b67f09SDavid van Moolenbroek 		case AF_INET6:
236*00b67f09SDavid van Moolenbroek 			switch (hints->ai_socktype) {
237*00b67f09SDavid van Moolenbroek 			case 0:
238*00b67f09SDavid van Moolenbroek 				break;
239*00b67f09SDavid van Moolenbroek 			case SOCK_STREAM:
240*00b67f09SDavid van Moolenbroek 				proto = "tcp";
241*00b67f09SDavid van Moolenbroek 				break;
242*00b67f09SDavid van Moolenbroek 			case SOCK_DGRAM:
243*00b67f09SDavid van Moolenbroek 				proto = "udp";
244*00b67f09SDavid van Moolenbroek 				break;
245*00b67f09SDavid van Moolenbroek 			case SOCK_RAW:
246*00b67f09SDavid van Moolenbroek 				break;
247*00b67f09SDavid van Moolenbroek 			default:
248*00b67f09SDavid van Moolenbroek 				return (EAI_SOCKTYPE);
249*00b67f09SDavid van Moolenbroek 			}
250*00b67f09SDavid van Moolenbroek 			break;
251*00b67f09SDavid van Moolenbroek #ifdef	AF_LOCAL
252*00b67f09SDavid van Moolenbroek 		case AF_LOCAL:
253*00b67f09SDavid van Moolenbroek 			switch (hints->ai_socktype) {
254*00b67f09SDavid van Moolenbroek 			case 0:
255*00b67f09SDavid van Moolenbroek 				break;
256*00b67f09SDavid van Moolenbroek 			case SOCK_STREAM:
257*00b67f09SDavid van Moolenbroek 				break;
258*00b67f09SDavid van Moolenbroek 			case SOCK_DGRAM:
259*00b67f09SDavid van Moolenbroek 				break;
260*00b67f09SDavid van Moolenbroek 			default:
261*00b67f09SDavid van Moolenbroek 				return (EAI_SOCKTYPE);
262*00b67f09SDavid van Moolenbroek 			}
263*00b67f09SDavid van Moolenbroek 			break;
264*00b67f09SDavid van Moolenbroek #endif
265*00b67f09SDavid van Moolenbroek 		default:
266*00b67f09SDavid van Moolenbroek 			return (EAI_FAMILY);
267*00b67f09SDavid van Moolenbroek 		}
268*00b67f09SDavid van Moolenbroek 	} else {
269*00b67f09SDavid van Moolenbroek 		protocol = 0;
270*00b67f09SDavid van Moolenbroek 		family = 0;
271*00b67f09SDavid van Moolenbroek 		socktype = 0;
272*00b67f09SDavid van Moolenbroek 		flags = 0;
273*00b67f09SDavid van Moolenbroek 	}
274*00b67f09SDavid van Moolenbroek 
275*00b67f09SDavid van Moolenbroek #ifdef	AF_LOCAL
276*00b67f09SDavid van Moolenbroek 	/*!
277*00b67f09SDavid van Moolenbroek 	 * First, deal with AF_LOCAL.  If the family was not set,
278*00b67f09SDavid van Moolenbroek 	 * then assume AF_LOCAL if the first character of the
279*00b67f09SDavid van Moolenbroek 	 * hostname/servname is '/'.
280*00b67f09SDavid van Moolenbroek 	 */
281*00b67f09SDavid van Moolenbroek 
282*00b67f09SDavid van Moolenbroek 	if (hostname != NULL &&
283*00b67f09SDavid van Moolenbroek 	    (family == AF_LOCAL || (family == 0 && *hostname == '/')))
284*00b67f09SDavid van Moolenbroek 		return (get_local(hostname, socktype, res));
285*00b67f09SDavid van Moolenbroek 
286*00b67f09SDavid van Moolenbroek 	if (servname != NULL &&
287*00b67f09SDavid van Moolenbroek 	    (family == AF_LOCAL || (family == 0 && *servname == '/')))
288*00b67f09SDavid van Moolenbroek 		return (get_local(servname, socktype, res));
289*00b67f09SDavid van Moolenbroek #endif
290*00b67f09SDavid van Moolenbroek 
291*00b67f09SDavid van Moolenbroek 	/*
292*00b67f09SDavid van Moolenbroek 	 * Ok, only AF_INET and AF_INET6 left.
293*00b67f09SDavid van Moolenbroek 	 */
294*00b67f09SDavid van Moolenbroek 	ai_list = NULL;
295*00b67f09SDavid van Moolenbroek 
296*00b67f09SDavid van Moolenbroek 	/*
297*00b67f09SDavid van Moolenbroek 	 * First, look up the service name (port) if it was
298*00b67f09SDavid van Moolenbroek 	 * requested.  If the socket type wasn't specified, then
299*00b67f09SDavid van Moolenbroek 	 * try and figure it out.
300*00b67f09SDavid van Moolenbroek 	 */
301*00b67f09SDavid van Moolenbroek 	if (servname != NULL) {
302*00b67f09SDavid van Moolenbroek 		char *e;
303*00b67f09SDavid van Moolenbroek 
304*00b67f09SDavid van Moolenbroek 		port = strtol(servname, &e, 10);
305*00b67f09SDavid van Moolenbroek 		if (*e == '\0') {
306*00b67f09SDavid van Moolenbroek 			if (socktype == 0)
307*00b67f09SDavid van Moolenbroek 				return (EAI_SOCKTYPE);
308*00b67f09SDavid van Moolenbroek 			if (port < 0 || port > 65535)
309*00b67f09SDavid van Moolenbroek 				return (EAI_SERVICE);
310*00b67f09SDavid van Moolenbroek 			port = htons((unsigned short) port);
311*00b67f09SDavid van Moolenbroek 		} else {
312*00b67f09SDavid van Moolenbroek 			sp = getservbyname(servname, proto);
313*00b67f09SDavid van Moolenbroek 			if (sp == NULL)
314*00b67f09SDavid van Moolenbroek 				return (EAI_SERVICE);
315*00b67f09SDavid van Moolenbroek 			port = sp->s_port;
316*00b67f09SDavid van Moolenbroek 			if (socktype == 0) {
317*00b67f09SDavid van Moolenbroek 				if (strcmp(sp->s_proto, "tcp") == 0)
318*00b67f09SDavid van Moolenbroek 					socktype = SOCK_STREAM;
319*00b67f09SDavid van Moolenbroek 				else if (strcmp(sp->s_proto, "udp") == 0)
320*00b67f09SDavid van Moolenbroek 					socktype = SOCK_DGRAM;
321*00b67f09SDavid van Moolenbroek 			}
322*00b67f09SDavid van Moolenbroek 		}
323*00b67f09SDavid van Moolenbroek 	} else
324*00b67f09SDavid van Moolenbroek 		port = 0;
325*00b67f09SDavid van Moolenbroek 
326*00b67f09SDavid van Moolenbroek 	/*
327*00b67f09SDavid van Moolenbroek 	 * Next, deal with just a service name, and no hostname.
328*00b67f09SDavid van Moolenbroek 	 * (we verified that one of them was non-null up above).
329*00b67f09SDavid van Moolenbroek 	 */
330*00b67f09SDavid van Moolenbroek 	if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
331*00b67f09SDavid van Moolenbroek 		if (family == AF_INET || family == 0) {
332*00b67f09SDavid van Moolenbroek 			ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
333*00b67f09SDavid van Moolenbroek 			if (ai == NULL)
334*00b67f09SDavid van Moolenbroek 				return (EAI_MEMORY);
335*00b67f09SDavid van Moolenbroek 			ai->ai_socktype = socktype;
336*00b67f09SDavid van Moolenbroek 			ai->ai_protocol = protocol;
337*00b67f09SDavid van Moolenbroek 			SIN(ai->ai_addr)->sin_port = port;
338*00b67f09SDavid van Moolenbroek 			ai->ai_next = ai_list;
339*00b67f09SDavid van Moolenbroek 			ai_list = ai;
340*00b67f09SDavid van Moolenbroek 		}
341*00b67f09SDavid van Moolenbroek 
342*00b67f09SDavid van Moolenbroek 		if (family == AF_INET6 || family == 0) {
343*00b67f09SDavid van Moolenbroek 			ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
344*00b67f09SDavid van Moolenbroek 			if (ai == NULL) {
345*00b67f09SDavid van Moolenbroek 				_freeaddrinfo(ai_list);
346*00b67f09SDavid van Moolenbroek 				return (EAI_MEMORY);
347*00b67f09SDavid van Moolenbroek 			}
348*00b67f09SDavid van Moolenbroek 			ai->ai_socktype = socktype;
349*00b67f09SDavid van Moolenbroek 			ai->ai_protocol = protocol;
350*00b67f09SDavid van Moolenbroek 			SIN6(ai->ai_addr)->sin6_port = port;
351*00b67f09SDavid van Moolenbroek 			ai->ai_next = ai_list;
352*00b67f09SDavid van Moolenbroek 			ai_list = ai;
353*00b67f09SDavid van Moolenbroek 		}
354*00b67f09SDavid van Moolenbroek 
355*00b67f09SDavid van Moolenbroek 		*res = ai_list;
356*00b67f09SDavid van Moolenbroek 		return (0);
357*00b67f09SDavid van Moolenbroek 	}
358*00b67f09SDavid van Moolenbroek 
359*00b67f09SDavid van Moolenbroek 	/*
360*00b67f09SDavid van Moolenbroek 	 * If the family isn't specified or AI_NUMERICHOST specified, check
361*00b67f09SDavid van Moolenbroek 	 * first to see if it is a numeric address.
362*00b67f09SDavid van Moolenbroek 	 * Though the gethostbyname2() routine will recognize numeric addresses,
363*00b67f09SDavid van Moolenbroek 	 * it will only recognize the format that it is being called for.  Thus,
364*00b67f09SDavid van Moolenbroek 	 * a numeric AF_INET address will be treated by the AF_INET6 call as
365*00b67f09SDavid van Moolenbroek 	 * a domain name, and vice versa.  Checking for both numerics here
366*00b67f09SDavid van Moolenbroek 	 * avoids that.
367*00b67f09SDavid van Moolenbroek 	 */
368*00b67f09SDavid van Moolenbroek 	if (hostname != NULL &&
369*00b67f09SDavid van Moolenbroek 	    (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
370*00b67f09SDavid van Moolenbroek 		char abuf[sizeof(struct in6_addr)];
371*00b67f09SDavid van Moolenbroek 		char nbuf[NI_MAXHOST];
372*00b67f09SDavid van Moolenbroek 		int addrsize, addroff;
373*00b67f09SDavid van Moolenbroek #ifdef IRS_HAVE_SIN6_SCOPE_ID
374*00b67f09SDavid van Moolenbroek 		char *p, *ep;
375*00b67f09SDavid van Moolenbroek 		char ntmp[NI_MAXHOST];
376*00b67f09SDavid van Moolenbroek 		isc_uint32_t scopeid;
377*00b67f09SDavid van Moolenbroek #endif
378*00b67f09SDavid van Moolenbroek 
379*00b67f09SDavid van Moolenbroek #ifdef IRS_HAVE_SIN6_SCOPE_ID
380*00b67f09SDavid van Moolenbroek 		/*
381*00b67f09SDavid van Moolenbroek 		 * Scope identifier portion.
382*00b67f09SDavid van Moolenbroek 		 */
383*00b67f09SDavid van Moolenbroek 		ntmp[0] = '\0';
384*00b67f09SDavid van Moolenbroek 		if (strchr(hostname, '%') != NULL) {
385*00b67f09SDavid van Moolenbroek 			strncpy(ntmp, hostname, sizeof(ntmp) - 1);
386*00b67f09SDavid van Moolenbroek 			ntmp[sizeof(ntmp) - 1] = '\0';
387*00b67f09SDavid van Moolenbroek 			p = strchr(ntmp, '%');
388*00b67f09SDavid van Moolenbroek 			ep = NULL;
389*00b67f09SDavid van Moolenbroek 
390*00b67f09SDavid van Moolenbroek 			/*
391*00b67f09SDavid van Moolenbroek 			 * Vendors may want to support non-numeric
392*00b67f09SDavid van Moolenbroek 			 * scopeid around here.
393*00b67f09SDavid van Moolenbroek 			 */
394*00b67f09SDavid van Moolenbroek 
395*00b67f09SDavid van Moolenbroek 			if (p != NULL)
396*00b67f09SDavid van Moolenbroek 				scopeid = (isc_uint32_t)strtoul(p + 1,
397*00b67f09SDavid van Moolenbroek 								&ep, 10);
398*00b67f09SDavid van Moolenbroek 			if (p != NULL && ep != NULL && ep[0] == '\0')
399*00b67f09SDavid van Moolenbroek 				*p = '\0';
400*00b67f09SDavid van Moolenbroek 			else {
401*00b67f09SDavid van Moolenbroek 				ntmp[0] = '\0';
402*00b67f09SDavid van Moolenbroek 				scopeid = 0;
403*00b67f09SDavid van Moolenbroek 			}
404*00b67f09SDavid van Moolenbroek 		} else
405*00b67f09SDavid van Moolenbroek 			scopeid = 0;
406*00b67f09SDavid van Moolenbroek #endif
407*00b67f09SDavid van Moolenbroek 
408*00b67f09SDavid van Moolenbroek 		if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf)
409*00b67f09SDavid van Moolenbroek 		    == 1) {
410*00b67f09SDavid van Moolenbroek 			if (family == AF_INET6) {
411*00b67f09SDavid van Moolenbroek 				/*
412*00b67f09SDavid van Moolenbroek 				 * Convert to a V4 mapped address.
413*00b67f09SDavid van Moolenbroek 				 */
414*00b67f09SDavid van Moolenbroek 				struct in6_addr *a6 = (struct in6_addr *)abuf;
415*00b67f09SDavid van Moolenbroek 				memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4);
416*00b67f09SDavid van Moolenbroek 				memset(&a6->s6_addr[10], 0xff, 2);
417*00b67f09SDavid van Moolenbroek 				memset(&a6->s6_addr[0], 0, 10);
418*00b67f09SDavid van Moolenbroek 				goto inet6_addr;
419*00b67f09SDavid van Moolenbroek 			}
420*00b67f09SDavid van Moolenbroek 			addrsize = sizeof(struct in_addr);
421*00b67f09SDavid van Moolenbroek 			addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
422*00b67f09SDavid van Moolenbroek 			family = AF_INET;
423*00b67f09SDavid van Moolenbroek 			goto common;
424*00b67f09SDavid van Moolenbroek #ifdef IRS_HAVE_SIN6_SCOPE_ID
425*00b67f09SDavid van Moolenbroek 		} else if (ntmp[0] != '\0' &&
426*00b67f09SDavid van Moolenbroek 			   inet_pton(AF_INET6, ntmp, abuf) == 1) {
427*00b67f09SDavid van Moolenbroek 			if (family && family != AF_INET6)
428*00b67f09SDavid van Moolenbroek 				return (EAI_NONAME);
429*00b67f09SDavid van Moolenbroek 			addrsize = sizeof(struct in6_addr);
430*00b67f09SDavid van Moolenbroek 			addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
431*00b67f09SDavid van Moolenbroek 			family = AF_INET6;
432*00b67f09SDavid van Moolenbroek 			goto common;
433*00b67f09SDavid van Moolenbroek #endif
434*00b67f09SDavid van Moolenbroek 		} else if (inet_pton(AF_INET6, hostname, abuf) == 1) {
435*00b67f09SDavid van Moolenbroek 			if (family != 0 && family != AF_INET6)
436*00b67f09SDavid van Moolenbroek 				return (EAI_NONAME);
437*00b67f09SDavid van Moolenbroek 		inet6_addr:
438*00b67f09SDavid van Moolenbroek 			addrsize = sizeof(struct in6_addr);
439*00b67f09SDavid van Moolenbroek 			addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
440*00b67f09SDavid van Moolenbroek 			family = AF_INET6;
441*00b67f09SDavid van Moolenbroek 
442*00b67f09SDavid van Moolenbroek 		common:
443*00b67f09SDavid van Moolenbroek 			ai = ai_alloc(family,
444*00b67f09SDavid van Moolenbroek 				      ((family == AF_INET6) ?
445*00b67f09SDavid van Moolenbroek 				       sizeof(struct sockaddr_in6) :
446*00b67f09SDavid van Moolenbroek 				       sizeof(struct sockaddr_in)));
447*00b67f09SDavid van Moolenbroek 			if (ai == NULL)
448*00b67f09SDavid van Moolenbroek 				return (EAI_MEMORY);
449*00b67f09SDavid van Moolenbroek 			ai_list = ai;
450*00b67f09SDavid van Moolenbroek 			ai->ai_socktype = socktype;
451*00b67f09SDavid van Moolenbroek 			SIN(ai->ai_addr)->sin_port = port;
452*00b67f09SDavid van Moolenbroek 			memmove((char *)ai->ai_addr + addroff, abuf, addrsize);
453*00b67f09SDavid van Moolenbroek 			if ((flags & AI_CANONNAME) != 0) {
454*00b67f09SDavid van Moolenbroek #ifdef IRS_HAVE_SIN6_SCOPE_ID
455*00b67f09SDavid van Moolenbroek 				if (ai->ai_family == AF_INET6)
456*00b67f09SDavid van Moolenbroek 					SIN6(ai->ai_addr)->sin6_scope_id =
457*00b67f09SDavid van Moolenbroek 						scopeid;
458*00b67f09SDavid van Moolenbroek #endif
459*00b67f09SDavid van Moolenbroek 				if (getnameinfo(ai->ai_addr,
460*00b67f09SDavid van Moolenbroek 						(socklen_t)ai->ai_addrlen,
461*00b67f09SDavid van Moolenbroek 						nbuf, sizeof(nbuf), NULL, 0,
462*00b67f09SDavid van Moolenbroek 						NI_NUMERICHOST) == 0) {
463*00b67f09SDavid van Moolenbroek 					ai->ai_canonname = strdup(nbuf);
464*00b67f09SDavid van Moolenbroek 					if (ai->ai_canonname == NULL) {
465*00b67f09SDavid van Moolenbroek 						_freeaddrinfo(ai);
466*00b67f09SDavid van Moolenbroek 						return (EAI_MEMORY);
467*00b67f09SDavid van Moolenbroek 					}
468*00b67f09SDavid van Moolenbroek 				} else {
469*00b67f09SDavid van Moolenbroek 					/* XXX raise error? */
470*00b67f09SDavid van Moolenbroek 					ai->ai_canonname = NULL;
471*00b67f09SDavid van Moolenbroek 				}
472*00b67f09SDavid van Moolenbroek 			}
473*00b67f09SDavid van Moolenbroek 			goto done;
474*00b67f09SDavid van Moolenbroek 		} else if ((flags & AI_NUMERICHOST) != 0) {
475*00b67f09SDavid van Moolenbroek 			return (EAI_NONAME);
476*00b67f09SDavid van Moolenbroek 		}
477*00b67f09SDavid van Moolenbroek 	}
478*00b67f09SDavid van Moolenbroek 
479*00b67f09SDavid van Moolenbroek 	if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
480*00b67f09SDavid van Moolenbroek 		set_order(family, net_order);
481*00b67f09SDavid van Moolenbroek 		for (i = 0; i < FOUND_MAX; i++) {
482*00b67f09SDavid van Moolenbroek 			if (net_order[i] == NULL)
483*00b67f09SDavid van Moolenbroek 				break;
484*00b67f09SDavid van Moolenbroek 			err = (net_order[i])(hostname, flags, &ai_list,
485*00b67f09SDavid van Moolenbroek 					     socktype, port);
486*00b67f09SDavid van Moolenbroek 			if (err != 0) {
487*00b67f09SDavid van Moolenbroek 				if (ai_list != NULL) {
488*00b67f09SDavid van Moolenbroek 					_freeaddrinfo(ai_list);
489*00b67f09SDavid van Moolenbroek 					ai_list = NULL;
490*00b67f09SDavid van Moolenbroek 				}
491*00b67f09SDavid van Moolenbroek 				break;
492*00b67f09SDavid van Moolenbroek 			}
493*00b67f09SDavid van Moolenbroek 		}
494*00b67f09SDavid van Moolenbroek 	} else
495*00b67f09SDavid van Moolenbroek 		err = resolve_name(family, hostname, flags, &ai_list,
496*00b67f09SDavid van Moolenbroek 				   socktype, port);
497*00b67f09SDavid van Moolenbroek 
498*00b67f09SDavid van Moolenbroek 	if (ai_list == NULL) {
499*00b67f09SDavid van Moolenbroek 		if (err == 0)
500*00b67f09SDavid van Moolenbroek 			err = EAI_NONAME;
501*00b67f09SDavid van Moolenbroek 		return (err);
502*00b67f09SDavid van Moolenbroek 	}
503*00b67f09SDavid van Moolenbroek 
504*00b67f09SDavid van Moolenbroek done:
505*00b67f09SDavid van Moolenbroek 	ai_list = ai_reverse(ai_list);
506*00b67f09SDavid van Moolenbroek 
507*00b67f09SDavid van Moolenbroek 	*res = ai_list;
508*00b67f09SDavid van Moolenbroek 	return (0);
509*00b67f09SDavid van Moolenbroek }
510*00b67f09SDavid van Moolenbroek 
511*00b67f09SDavid van Moolenbroek typedef struct gai_restrans {
512*00b67f09SDavid van Moolenbroek 	dns_clientrestrans_t	*xid;
513*00b67f09SDavid van Moolenbroek 	isc_boolean_t		is_inprogress;
514*00b67f09SDavid van Moolenbroek 	int			error;
515*00b67f09SDavid van Moolenbroek 	struct addrinfo		ai_sentinel;
516*00b67f09SDavid van Moolenbroek 	struct gai_resstate	*resstate;
517*00b67f09SDavid van Moolenbroek } gai_restrans_t;
518*00b67f09SDavid van Moolenbroek 
519*00b67f09SDavid van Moolenbroek typedef struct gai_resstate {
520*00b67f09SDavid van Moolenbroek 	isc_mem_t			*mctx;
521*00b67f09SDavid van Moolenbroek 	struct gai_statehead		*head;
522*00b67f09SDavid van Moolenbroek 	dns_fixedname_t			fixedname;
523*00b67f09SDavid van Moolenbroek 	dns_name_t			*qname;
524*00b67f09SDavid van Moolenbroek 	gai_restrans_t			*trans4;
525*00b67f09SDavid van Moolenbroek 	gai_restrans_t			*trans6;
526*00b67f09SDavid van Moolenbroek 	ISC_LINK(struct gai_resstate)	link;
527*00b67f09SDavid van Moolenbroek } gai_resstate_t;
528*00b67f09SDavid van Moolenbroek 
529*00b67f09SDavid van Moolenbroek typedef struct gai_statehead {
530*00b67f09SDavid van Moolenbroek 	int				ai_family;
531*00b67f09SDavid van Moolenbroek 	int				ai_flags;
532*00b67f09SDavid van Moolenbroek 	int				ai_socktype;
533*00b67f09SDavid van Moolenbroek 	int				ai_port;
534*00b67f09SDavid van Moolenbroek 	isc_appctx_t			*actx;
535*00b67f09SDavid van Moolenbroek 	dns_client_t			*dnsclient;
536*00b67f09SDavid van Moolenbroek 	ISC_LIST(struct gai_resstate)	resstates;
537*00b67f09SDavid van Moolenbroek 	unsigned int			activestates;
538*00b67f09SDavid van Moolenbroek } gai_statehead_t;
539*00b67f09SDavid van Moolenbroek 
540*00b67f09SDavid van Moolenbroek static isc_result_t
make_resstate(isc_mem_t * mctx,gai_statehead_t * head,const char * hostname,const char * domain,gai_resstate_t ** statep)541*00b67f09SDavid van Moolenbroek make_resstate(isc_mem_t *mctx, gai_statehead_t *head, const char *hostname,
542*00b67f09SDavid van Moolenbroek 	      const char *domain, gai_resstate_t **statep)
543*00b67f09SDavid van Moolenbroek {
544*00b67f09SDavid van Moolenbroek 	isc_result_t result;
545*00b67f09SDavid van Moolenbroek 	gai_resstate_t *state;
546*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixeddomain;
547*00b67f09SDavid van Moolenbroek 	dns_name_t *qdomain;
548*00b67f09SDavid van Moolenbroek 	unsigned int namelen;
549*00b67f09SDavid van Moolenbroek 	isc_buffer_t b;
550*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_v4 = ISC_FALSE;
551*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_v6 = ISC_FALSE;
552*00b67f09SDavid van Moolenbroek 
553*00b67f09SDavid van Moolenbroek 	state = isc_mem_get(mctx, sizeof(*state));
554*00b67f09SDavid van Moolenbroek 	if (state == NULL)
555*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
556*00b67f09SDavid van Moolenbroek 
557*00b67f09SDavid van Moolenbroek 	/* Construct base domain name */
558*00b67f09SDavid van Moolenbroek 	namelen = strlen(domain);
559*00b67f09SDavid van Moolenbroek 	isc_buffer_constinit(&b, domain, namelen);
560*00b67f09SDavid van Moolenbroek 	isc_buffer_add(&b, namelen);
561*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixeddomain);
562*00b67f09SDavid van Moolenbroek 	qdomain = dns_fixedname_name(&fixeddomain);
563*00b67f09SDavid van Moolenbroek 	result = dns_name_fromtext(qdomain, &b, dns_rootname, 0, NULL);
564*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
565*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, state, sizeof(*state));
566*00b67f09SDavid van Moolenbroek 		return (result);
567*00b67f09SDavid van Moolenbroek 	}
568*00b67f09SDavid van Moolenbroek 
569*00b67f09SDavid van Moolenbroek 	/* Construct query name */
570*00b67f09SDavid van Moolenbroek 	namelen = strlen(hostname);
571*00b67f09SDavid van Moolenbroek 	isc_buffer_constinit(&b, hostname, namelen);
572*00b67f09SDavid van Moolenbroek 	isc_buffer_add(&b, namelen);
573*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&state->fixedname);
574*00b67f09SDavid van Moolenbroek 	state->qname = dns_fixedname_name(&state->fixedname);
575*00b67f09SDavid van Moolenbroek 	result = dns_name_fromtext(state->qname, &b, qdomain, 0, NULL);
576*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
577*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, state, sizeof(*state));
578*00b67f09SDavid van Moolenbroek 		return (result);
579*00b67f09SDavid van Moolenbroek 	}
580*00b67f09SDavid van Moolenbroek 
581*00b67f09SDavid van Moolenbroek 	if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET)
582*00b67f09SDavid van Moolenbroek 		need_v4 = ISC_TRUE;
583*00b67f09SDavid van Moolenbroek 	if (head->ai_family == AF_UNSPEC || head->ai_family == AF_INET6)
584*00b67f09SDavid van Moolenbroek 		need_v6 = ISC_TRUE;
585*00b67f09SDavid van Moolenbroek 
586*00b67f09SDavid van Moolenbroek 	state->trans6 = NULL;
587*00b67f09SDavid van Moolenbroek 	state->trans4 = NULL;
588*00b67f09SDavid van Moolenbroek 	if (need_v4) {
589*00b67f09SDavid van Moolenbroek 		state->trans4 = isc_mem_get(mctx, sizeof(gai_restrans_t));
590*00b67f09SDavid van Moolenbroek 		if (state->trans4 == NULL) {
591*00b67f09SDavid van Moolenbroek 			isc_mem_put(mctx, state, sizeof(*state));
592*00b67f09SDavid van Moolenbroek 			return (ISC_R_NOMEMORY);
593*00b67f09SDavid van Moolenbroek 		}
594*00b67f09SDavid van Moolenbroek 		state->trans4->error = 0;
595*00b67f09SDavid van Moolenbroek 		state->trans4->xid = NULL;
596*00b67f09SDavid van Moolenbroek 		state->trans4->resstate = state;
597*00b67f09SDavid van Moolenbroek 		state->trans4->is_inprogress = ISC_TRUE;
598*00b67f09SDavid van Moolenbroek 		state->trans4->ai_sentinel.ai_next = NULL;
599*00b67f09SDavid van Moolenbroek 	}
600*00b67f09SDavid van Moolenbroek 	if (need_v6) {
601*00b67f09SDavid van Moolenbroek 		state->trans6 = isc_mem_get(mctx, sizeof(gai_restrans_t));
602*00b67f09SDavid van Moolenbroek 		if (state->trans6 == NULL) {
603*00b67f09SDavid van Moolenbroek 			if (state->trans4 != NULL)
604*00b67f09SDavid van Moolenbroek 				isc_mem_put(mctx, state->trans4,
605*00b67f09SDavid van Moolenbroek 					    sizeof(*state->trans4));
606*00b67f09SDavid van Moolenbroek 			isc_mem_put(mctx, state, sizeof(*state));
607*00b67f09SDavid van Moolenbroek 			return (ISC_R_NOMEMORY);
608*00b67f09SDavid van Moolenbroek 		}
609*00b67f09SDavid van Moolenbroek 		state->trans6->error = 0;
610*00b67f09SDavid van Moolenbroek 		state->trans6->xid = NULL;
611*00b67f09SDavid van Moolenbroek 		state->trans6->resstate = state;
612*00b67f09SDavid van Moolenbroek 		state->trans6->is_inprogress = ISC_TRUE;
613*00b67f09SDavid van Moolenbroek 		state->trans6->ai_sentinel.ai_next = NULL;
614*00b67f09SDavid van Moolenbroek 	}
615*00b67f09SDavid van Moolenbroek 
616*00b67f09SDavid van Moolenbroek 	state->mctx = mctx;
617*00b67f09SDavid van Moolenbroek 	state->head = head;
618*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(state, link);
619*00b67f09SDavid van Moolenbroek 
620*00b67f09SDavid van Moolenbroek 	*statep = state;
621*00b67f09SDavid van Moolenbroek 
622*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
623*00b67f09SDavid van Moolenbroek }
624*00b67f09SDavid van Moolenbroek 
625*00b67f09SDavid van Moolenbroek static isc_result_t
make_resstates(isc_mem_t * mctx,const char * hostname,gai_statehead_t * head,irs_resconf_t * resconf)626*00b67f09SDavid van Moolenbroek make_resstates(isc_mem_t *mctx, const char *hostname, gai_statehead_t *head,
627*00b67f09SDavid van Moolenbroek 	       irs_resconf_t *resconf)
628*00b67f09SDavid van Moolenbroek {
629*00b67f09SDavid van Moolenbroek 	isc_result_t result;
630*00b67f09SDavid van Moolenbroek 	irs_resconf_searchlist_t *searchlist;
631*00b67f09SDavid van Moolenbroek 	irs_resconf_search_t *searchent;
632*00b67f09SDavid van Moolenbroek 	gai_resstate_t *resstate, *resstate0;
633*00b67f09SDavid van Moolenbroek 
634*00b67f09SDavid van Moolenbroek 	resstate0 = NULL;
635*00b67f09SDavid van Moolenbroek 	result = make_resstate(mctx, head, hostname, ".", &resstate0);
636*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
637*00b67f09SDavid van Moolenbroek 		return (result);
638*00b67f09SDavid van Moolenbroek 
639*00b67f09SDavid van Moolenbroek 	searchlist = irs_resconf_getsearchlist(resconf);
640*00b67f09SDavid van Moolenbroek 	for (searchent = ISC_LIST_HEAD(*searchlist); searchent != NULL;
641*00b67f09SDavid van Moolenbroek 	     searchent = ISC_LIST_NEXT(searchent, link)) {
642*00b67f09SDavid van Moolenbroek 		resstate = NULL;
643*00b67f09SDavid van Moolenbroek 		result = make_resstate(mctx, head, hostname,
644*00b67f09SDavid van Moolenbroek 				       (const char *)searchent->domain,
645*00b67f09SDavid van Moolenbroek 				       &resstate);
646*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
647*00b67f09SDavid van Moolenbroek 			break;
648*00b67f09SDavid van Moolenbroek 
649*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(head->resstates, resstate, link);
650*00b67f09SDavid van Moolenbroek 		head->activestates++;
651*00b67f09SDavid van Moolenbroek 	}
652*00b67f09SDavid van Moolenbroek 
653*00b67f09SDavid van Moolenbroek 	/*
654*00b67f09SDavid van Moolenbroek 	 * Insert the original hostname either at the head or the tail of the
655*00b67f09SDavid van Moolenbroek 	 * state list, depending on the number of labels contained in the
656*00b67f09SDavid van Moolenbroek 	 * original name and the 'ndots' configuration parameter.
657*00b67f09SDavid van Moolenbroek 	 */
658*00b67f09SDavid van Moolenbroek 	if (dns_name_countlabels(resstate0->qname) >
659*00b67f09SDavid van Moolenbroek 	    irs_resconf_getndots(resconf) + 1) {
660*00b67f09SDavid van Moolenbroek 		ISC_LIST_PREPEND(head->resstates, resstate0, link);
661*00b67f09SDavid van Moolenbroek 	} else
662*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(head->resstates, resstate0, link);
663*00b67f09SDavid van Moolenbroek 	head->activestates++;
664*00b67f09SDavid van Moolenbroek 
665*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
666*00b67f09SDavid van Moolenbroek 		while ((resstate = ISC_LIST_HEAD(head->resstates)) != NULL) {
667*00b67f09SDavid van Moolenbroek 			ISC_LIST_UNLINK(head->resstates, resstate, link);
668*00b67f09SDavid van Moolenbroek 			if (resstate->trans4 != NULL) {
669*00b67f09SDavid van Moolenbroek 				isc_mem_put(mctx, resstate->trans4,
670*00b67f09SDavid van Moolenbroek 					    sizeof(*resstate->trans4));
671*00b67f09SDavid van Moolenbroek 			}
672*00b67f09SDavid van Moolenbroek 			if (resstate->trans6 != NULL) {
673*00b67f09SDavid van Moolenbroek 				isc_mem_put(mctx, resstate->trans6,
674*00b67f09SDavid van Moolenbroek 					    sizeof(*resstate->trans6));
675*00b67f09SDavid van Moolenbroek 			}
676*00b67f09SDavid van Moolenbroek 
677*00b67f09SDavid van Moolenbroek 			isc_mem_put(mctx, resstate, sizeof(*resstate));
678*00b67f09SDavid van Moolenbroek 		}
679*00b67f09SDavid van Moolenbroek 	}
680*00b67f09SDavid van Moolenbroek 
681*00b67f09SDavid van Moolenbroek 	return (result);
682*00b67f09SDavid van Moolenbroek }
683*00b67f09SDavid van Moolenbroek 
684*00b67f09SDavid van Moolenbroek static void
process_answer(isc_task_t * task,isc_event_t * event)685*00b67f09SDavid van Moolenbroek process_answer(isc_task_t *task, isc_event_t *event) {
686*00b67f09SDavid van Moolenbroek 	int error = 0, family;
687*00b67f09SDavid van Moolenbroek 	gai_restrans_t *trans = event->ev_arg;
688*00b67f09SDavid van Moolenbroek 	gai_resstate_t *resstate;
689*00b67f09SDavid van Moolenbroek 	dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
690*00b67f09SDavid van Moolenbroek 	dns_rdatatype_t qtype;
691*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
692*00b67f09SDavid van Moolenbroek 
693*00b67f09SDavid van Moolenbroek 	REQUIRE(trans != NULL);
694*00b67f09SDavid van Moolenbroek 	resstate = trans->resstate;
695*00b67f09SDavid van Moolenbroek 	REQUIRE(resstate != NULL);
696*00b67f09SDavid van Moolenbroek 	REQUIRE(task != NULL);
697*00b67f09SDavid van Moolenbroek 
698*00b67f09SDavid van Moolenbroek 	if (trans == resstate->trans4) {
699*00b67f09SDavid van Moolenbroek 		family = AF_INET;
700*00b67f09SDavid van Moolenbroek 		qtype = dns_rdatatype_a;
701*00b67f09SDavid van Moolenbroek 	} else {
702*00b67f09SDavid van Moolenbroek 		INSIST(trans == resstate->trans6);
703*00b67f09SDavid van Moolenbroek 		family = AF_INET6;
704*00b67f09SDavid van Moolenbroek 		qtype = dns_rdatatype_aaaa;
705*00b67f09SDavid van Moolenbroek 	}
706*00b67f09SDavid van Moolenbroek 
707*00b67f09SDavid van Moolenbroek 	INSIST(trans->is_inprogress);
708*00b67f09SDavid van Moolenbroek 	trans->is_inprogress = ISC_FALSE;
709*00b67f09SDavid van Moolenbroek 
710*00b67f09SDavid van Moolenbroek 	switch (rev->result) {
711*00b67f09SDavid van Moolenbroek 	case ISC_R_SUCCESS:
712*00b67f09SDavid van Moolenbroek 	case DNS_R_NCACHENXDOMAIN: /* treat this as a fatal error? */
713*00b67f09SDavid van Moolenbroek 	case DNS_R_NCACHENXRRSET:
714*00b67f09SDavid van Moolenbroek 		break;
715*00b67f09SDavid van Moolenbroek 	default:
716*00b67f09SDavid van Moolenbroek 		switch (rev->vresult) {
717*00b67f09SDavid van Moolenbroek 		case DNS_R_SIGINVALID:
718*00b67f09SDavid van Moolenbroek 		case DNS_R_SIGEXPIRED:
719*00b67f09SDavid van Moolenbroek 		case DNS_R_SIGFUTURE:
720*00b67f09SDavid van Moolenbroek 		case DNS_R_KEYUNAUTHORIZED:
721*00b67f09SDavid van Moolenbroek 		case DNS_R_MUSTBESECURE:
722*00b67f09SDavid van Moolenbroek 		case DNS_R_COVERINGNSEC:
723*00b67f09SDavid van Moolenbroek 		case DNS_R_NOTAUTHORITATIVE:
724*00b67f09SDavid van Moolenbroek 		case DNS_R_NOVALIDKEY:
725*00b67f09SDavid van Moolenbroek 		case DNS_R_NOVALIDDS:
726*00b67f09SDavid van Moolenbroek 		case DNS_R_NOVALIDSIG:
727*00b67f09SDavid van Moolenbroek 			error = EAI_INSECUREDATA;
728*00b67f09SDavid van Moolenbroek 			break;
729*00b67f09SDavid van Moolenbroek 		default:
730*00b67f09SDavid van Moolenbroek 			error = EAI_FAIL;
731*00b67f09SDavid van Moolenbroek 		}
732*00b67f09SDavid van Moolenbroek 		goto done;
733*00b67f09SDavid van Moolenbroek 	}
734*00b67f09SDavid van Moolenbroek 
735*00b67f09SDavid van Moolenbroek 	/* Parse the response and construct the addrinfo chain */
736*00b67f09SDavid van Moolenbroek 	for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
737*00b67f09SDavid van Moolenbroek 	     name = ISC_LIST_NEXT(name, link)) {
738*00b67f09SDavid van Moolenbroek 		isc_result_t result;
739*00b67f09SDavid van Moolenbroek 		dns_rdataset_t *rdataset;
740*00b67f09SDavid van Moolenbroek 		isc_buffer_t b;
741*00b67f09SDavid van Moolenbroek 		isc_region_t r;
742*00b67f09SDavid van Moolenbroek 		char t[1024];
743*00b67f09SDavid van Moolenbroek 
744*00b67f09SDavid van Moolenbroek 		for (rdataset = ISC_LIST_HEAD(name->list);
745*00b67f09SDavid van Moolenbroek 		     rdataset != NULL;
746*00b67f09SDavid van Moolenbroek 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
747*00b67f09SDavid van Moolenbroek 			if (!dns_rdataset_isassociated(rdataset))
748*00b67f09SDavid van Moolenbroek 				continue;
749*00b67f09SDavid van Moolenbroek 			if (rdataset->type != qtype)
750*00b67f09SDavid van Moolenbroek 				continue;
751*00b67f09SDavid van Moolenbroek 
752*00b67f09SDavid van Moolenbroek 			if ((resstate->head->ai_flags & AI_CANONNAME) != 0) {
753*00b67f09SDavid van Moolenbroek 				isc_buffer_init(&b, t, sizeof(t));
754*00b67f09SDavid van Moolenbroek 				result = dns_name_totext(name, ISC_TRUE, &b);
755*00b67f09SDavid van Moolenbroek 				if (result != ISC_R_SUCCESS) {
756*00b67f09SDavid van Moolenbroek 					error = EAI_FAIL;
757*00b67f09SDavid van Moolenbroek 					goto done;
758*00b67f09SDavid van Moolenbroek 				}
759*00b67f09SDavid van Moolenbroek 				isc_buffer_putuint8(&b, '\0');
760*00b67f09SDavid van Moolenbroek 				isc_buffer_usedregion(&b, &r);
761*00b67f09SDavid van Moolenbroek 			}
762*00b67f09SDavid van Moolenbroek 
763*00b67f09SDavid van Moolenbroek 			for (result = dns_rdataset_first(rdataset);
764*00b67f09SDavid van Moolenbroek 			     result == ISC_R_SUCCESS;
765*00b67f09SDavid van Moolenbroek 			     result = dns_rdataset_next(rdataset)) {
766*00b67f09SDavid van Moolenbroek 				struct addrinfo *ai;
767*00b67f09SDavid van Moolenbroek 				dns_rdata_t rdata;
768*00b67f09SDavid van Moolenbroek 				dns_rdata_in_a_t rdata_a;
769*00b67f09SDavid van Moolenbroek 				dns_rdata_in_aaaa_t rdata_aaaa;
770*00b67f09SDavid van Moolenbroek 
771*00b67f09SDavid van Moolenbroek 				ai = ai_alloc(family,
772*00b67f09SDavid van Moolenbroek 					      ((family == AF_INET6) ?
773*00b67f09SDavid van Moolenbroek 					       sizeof(struct sockaddr_in6) :
774*00b67f09SDavid van Moolenbroek 					       sizeof(struct sockaddr_in)));
775*00b67f09SDavid van Moolenbroek 				if (ai == NULL) {
776*00b67f09SDavid van Moolenbroek 					error = EAI_MEMORY;
777*00b67f09SDavid van Moolenbroek 					goto done;
778*00b67f09SDavid van Moolenbroek 				}
779*00b67f09SDavid van Moolenbroek 				ai->ai_socktype = resstate->head->ai_socktype;
780*00b67f09SDavid van Moolenbroek 				ai->ai_next = trans->ai_sentinel.ai_next;
781*00b67f09SDavid van Moolenbroek 				trans->ai_sentinel.ai_next = ai;
782*00b67f09SDavid van Moolenbroek 
783*00b67f09SDavid van Moolenbroek 				/*
784*00b67f09SDavid van Moolenbroek 				 * Set AF-specific parameters
785*00b67f09SDavid van Moolenbroek 				 * (IPv4/v6 address/port)
786*00b67f09SDavid van Moolenbroek 				 */
787*00b67f09SDavid van Moolenbroek 				dns_rdata_init(&rdata);
788*00b67f09SDavid van Moolenbroek 				switch (family) {
789*00b67f09SDavid van Moolenbroek 				case AF_INET:
790*00b67f09SDavid van Moolenbroek 					dns_rdataset_current(rdataset, &rdata);
791*00b67f09SDavid van Moolenbroek 					result = dns_rdata_tostruct(&rdata, &rdata_a,
792*00b67f09SDavid van Moolenbroek 								    NULL);
793*00b67f09SDavid van Moolenbroek 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
794*00b67f09SDavid van Moolenbroek 					SIN(ai->ai_addr)->sin_port =
795*00b67f09SDavid van Moolenbroek 						resstate->head->ai_port;
796*00b67f09SDavid van Moolenbroek 					memmove(&SIN(ai->ai_addr)->sin_addr,
797*00b67f09SDavid van Moolenbroek 						&rdata_a.in_addr, 4);
798*00b67f09SDavid van Moolenbroek 					dns_rdata_freestruct(&rdata_a);
799*00b67f09SDavid van Moolenbroek 					break;
800*00b67f09SDavid van Moolenbroek 				case AF_INET6:
801*00b67f09SDavid van Moolenbroek 					dns_rdataset_current(rdataset, &rdata);
802*00b67f09SDavid van Moolenbroek 					result = dns_rdata_tostruct(&rdata, &rdata_aaaa,
803*00b67f09SDavid van Moolenbroek 								    NULL);
804*00b67f09SDavid van Moolenbroek 					RUNTIME_CHECK(result == ISC_R_SUCCESS);
805*00b67f09SDavid van Moolenbroek 					SIN6(ai->ai_addr)->sin6_port =
806*00b67f09SDavid van Moolenbroek 						resstate->head->ai_port;
807*00b67f09SDavid van Moolenbroek 					memmove(&SIN6(ai->ai_addr)->sin6_addr,
808*00b67f09SDavid van Moolenbroek 						&rdata_aaaa.in6_addr, 16);
809*00b67f09SDavid van Moolenbroek 					dns_rdata_freestruct(&rdata_aaaa);
810*00b67f09SDavid van Moolenbroek 					break;
811*00b67f09SDavid van Moolenbroek 				}
812*00b67f09SDavid van Moolenbroek 
813*00b67f09SDavid van Moolenbroek 				if ((resstate->head->ai_flags & AI_CANONNAME)
814*00b67f09SDavid van Moolenbroek 				    != 0) {
815*00b67f09SDavid van Moolenbroek 					ai->ai_canonname =
816*00b67f09SDavid van Moolenbroek 						strdup((const char *)r.base);
817*00b67f09SDavid van Moolenbroek 					if (ai->ai_canonname == NULL) {
818*00b67f09SDavid van Moolenbroek 						error = EAI_MEMORY;
819*00b67f09SDavid van Moolenbroek 						goto done;
820*00b67f09SDavid van Moolenbroek 					}
821*00b67f09SDavid van Moolenbroek 				}
822*00b67f09SDavid van Moolenbroek 			}
823*00b67f09SDavid van Moolenbroek 		}
824*00b67f09SDavid van Moolenbroek 	}
825*00b67f09SDavid van Moolenbroek 
826*00b67f09SDavid van Moolenbroek  done:
827*00b67f09SDavid van Moolenbroek 	dns_client_freeresanswer(resstate->head->dnsclient, &rev->answerlist);
828*00b67f09SDavid van Moolenbroek 	dns_client_destroyrestrans(&trans->xid);
829*00b67f09SDavid van Moolenbroek 
830*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
831*00b67f09SDavid van Moolenbroek 
832*00b67f09SDavid van Moolenbroek 	/* Make sure that error == 0 iff we have a non-empty list */
833*00b67f09SDavid van Moolenbroek 	if (error == 0) {
834*00b67f09SDavid van Moolenbroek 		if (trans->ai_sentinel.ai_next == NULL)
835*00b67f09SDavid van Moolenbroek 			error = EAI_NONAME;
836*00b67f09SDavid van Moolenbroek 	} else {
837*00b67f09SDavid van Moolenbroek 		if (trans->ai_sentinel.ai_next != NULL) {
838*00b67f09SDavid van Moolenbroek 			_freeaddrinfo(trans->ai_sentinel.ai_next);
839*00b67f09SDavid van Moolenbroek 			trans->ai_sentinel.ai_next = NULL;
840*00b67f09SDavid van Moolenbroek 		}
841*00b67f09SDavid van Moolenbroek 	}
842*00b67f09SDavid van Moolenbroek 	trans->error = error;
843*00b67f09SDavid van Moolenbroek 
844*00b67f09SDavid van Moolenbroek 	/* Check whether we are done */
845*00b67f09SDavid van Moolenbroek 	if ((resstate->trans4 == NULL || !resstate->trans4->is_inprogress) &&
846*00b67f09SDavid van Moolenbroek 	    (resstate->trans6 == NULL || !resstate->trans6->is_inprogress)) {
847*00b67f09SDavid van Moolenbroek 		/*
848*00b67f09SDavid van Moolenbroek 		 * We're done for this state.  If there is no other outstanding
849*00b67f09SDavid van Moolenbroek 		 * state, we can exit.
850*00b67f09SDavid van Moolenbroek 		 */
851*00b67f09SDavid van Moolenbroek 		resstate->head->activestates--;
852*00b67f09SDavid van Moolenbroek 		if (resstate->head->activestates == 0) {
853*00b67f09SDavid van Moolenbroek 			isc_app_ctxsuspend(resstate->head->actx);
854*00b67f09SDavid van Moolenbroek 			return;
855*00b67f09SDavid van Moolenbroek 		}
856*00b67f09SDavid van Moolenbroek 
857*00b67f09SDavid van Moolenbroek 		/*
858*00b67f09SDavid van Moolenbroek 		 * There are outstanding states, but if we are at the head
859*00b67f09SDavid van Moolenbroek 		 * of the state list (i.e., at the highest search priority)
860*00b67f09SDavid van Moolenbroek 		 * and have any answer, we can stop now by canceling the
861*00b67f09SDavid van Moolenbroek 		 * others.
862*00b67f09SDavid van Moolenbroek 		 */
863*00b67f09SDavid van Moolenbroek 		if (resstate == ISC_LIST_HEAD(resstate->head->resstates)) {
864*00b67f09SDavid van Moolenbroek 			if ((resstate->trans4 != NULL &&
865*00b67f09SDavid van Moolenbroek 			     resstate->trans4->ai_sentinel.ai_next != NULL) ||
866*00b67f09SDavid van Moolenbroek 			    (resstate->trans6 != NULL &&
867*00b67f09SDavid van Moolenbroek 			     resstate->trans6->ai_sentinel.ai_next != NULL)) {
868*00b67f09SDavid van Moolenbroek 				gai_resstate_t *rest;
869*00b67f09SDavid van Moolenbroek 
870*00b67f09SDavid van Moolenbroek 				for (rest = ISC_LIST_NEXT(resstate, link);
871*00b67f09SDavid van Moolenbroek 				     rest != NULL;
872*00b67f09SDavid van Moolenbroek 				     rest = ISC_LIST_NEXT(rest, link)) {
873*00b67f09SDavid van Moolenbroek 					if (rest->trans4 != NULL &&
874*00b67f09SDavid van Moolenbroek 					    rest->trans4->xid != NULL)
875*00b67f09SDavid van Moolenbroek 						dns_client_cancelresolve(
876*00b67f09SDavid van Moolenbroek 							rest->trans4->xid);
877*00b67f09SDavid van Moolenbroek 					if (rest->trans6 != NULL &&
878*00b67f09SDavid van Moolenbroek 					    rest->trans6->xid != NULL)
879*00b67f09SDavid van Moolenbroek 						dns_client_cancelresolve(
880*00b67f09SDavid van Moolenbroek 							rest->trans6->xid);
881*00b67f09SDavid van Moolenbroek 				}
882*00b67f09SDavid van Moolenbroek 			} else {
883*00b67f09SDavid van Moolenbroek 				/*
884*00b67f09SDavid van Moolenbroek 				 * This search fails, so we move to the tail
885*00b67f09SDavid van Moolenbroek 				 * of the list so that the next entry will
886*00b67f09SDavid van Moolenbroek 				 * have the highest priority.
887*00b67f09SDavid van Moolenbroek 				 */
888*00b67f09SDavid van Moolenbroek 				ISC_LIST_UNLINK(resstate->head->resstates,
889*00b67f09SDavid van Moolenbroek 						resstate, link);
890*00b67f09SDavid van Moolenbroek 				ISC_LIST_APPEND(resstate->head->resstates,
891*00b67f09SDavid van Moolenbroek 						resstate, link);
892*00b67f09SDavid van Moolenbroek 			}
893*00b67f09SDavid van Moolenbroek 		}
894*00b67f09SDavid van Moolenbroek 	}
895*00b67f09SDavid van Moolenbroek }
896*00b67f09SDavid van Moolenbroek 
897*00b67f09SDavid van Moolenbroek static int
resolve_name(int family,const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)898*00b67f09SDavid van Moolenbroek resolve_name(int family, const char *hostname, int flags,
899*00b67f09SDavid van Moolenbroek 	     struct addrinfo **aip, int socktype, int port)
900*00b67f09SDavid van Moolenbroek {
901*00b67f09SDavid van Moolenbroek 	isc_result_t result;
902*00b67f09SDavid van Moolenbroek 	irs_context_t *irsctx;
903*00b67f09SDavid van Moolenbroek 	irs_resconf_t *conf;
904*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
905*00b67f09SDavid van Moolenbroek 	isc_appctx_t *actx;
906*00b67f09SDavid van Moolenbroek 	isc_task_t *task;
907*00b67f09SDavid van Moolenbroek 	int terror = 0;
908*00b67f09SDavid van Moolenbroek 	int error = 0;
909*00b67f09SDavid van Moolenbroek 	dns_client_t *client;
910*00b67f09SDavid van Moolenbroek 	gai_resstate_t *resstate;
911*00b67f09SDavid van Moolenbroek 	gai_statehead_t head;
912*00b67f09SDavid van Moolenbroek 	isc_boolean_t all_fail = ISC_TRUE;
913*00b67f09SDavid van Moolenbroek 
914*00b67f09SDavid van Moolenbroek 	/* get IRS context and the associated parameters */
915*00b67f09SDavid van Moolenbroek 	irsctx = NULL;
916*00b67f09SDavid van Moolenbroek 	result = irs_context_get(&irsctx);
917*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
918*00b67f09SDavid van Moolenbroek 		return (EAI_FAIL);
919*00b67f09SDavid van Moolenbroek 	actx = irs_context_getappctx(irsctx);
920*00b67f09SDavid van Moolenbroek 
921*00b67f09SDavid van Moolenbroek 	mctx = irs_context_getmctx(irsctx);
922*00b67f09SDavid van Moolenbroek 	task = irs_context_gettask(irsctx);
923*00b67f09SDavid van Moolenbroek 	conf = irs_context_getresconf(irsctx);
924*00b67f09SDavid van Moolenbroek 	client = irs_context_getdnsclient(irsctx);
925*00b67f09SDavid van Moolenbroek 
926*00b67f09SDavid van Moolenbroek 	/* construct resolution states */
927*00b67f09SDavid van Moolenbroek 	head.activestates = 0;
928*00b67f09SDavid van Moolenbroek 	head.ai_family = family;
929*00b67f09SDavid van Moolenbroek 	head.ai_socktype = socktype;
930*00b67f09SDavid van Moolenbroek 	head.ai_flags = flags;
931*00b67f09SDavid van Moolenbroek 	head.ai_port = port;
932*00b67f09SDavid van Moolenbroek 	head.actx = actx;
933*00b67f09SDavid van Moolenbroek 	head.dnsclient = client;
934*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(head.resstates);
935*00b67f09SDavid van Moolenbroek 	result = make_resstates(mctx, hostname, &head, conf);
936*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
937*00b67f09SDavid van Moolenbroek 		return (EAI_FAIL);
938*00b67f09SDavid van Moolenbroek 
939*00b67f09SDavid van Moolenbroek 	for (resstate = ISC_LIST_HEAD(head.resstates);
940*00b67f09SDavid van Moolenbroek 	     resstate != NULL; resstate = ISC_LIST_NEXT(resstate, link)) {
941*00b67f09SDavid van Moolenbroek 		if (resstate->trans4 != NULL) {
942*00b67f09SDavid van Moolenbroek 			result = dns_client_startresolve(client,
943*00b67f09SDavid van Moolenbroek 							 resstate->qname,
944*00b67f09SDavid van Moolenbroek 							 dns_rdataclass_in,
945*00b67f09SDavid van Moolenbroek 							 dns_rdatatype_a,
946*00b67f09SDavid van Moolenbroek 							 0, task,
947*00b67f09SDavid van Moolenbroek 							 process_answer,
948*00b67f09SDavid van Moolenbroek 							 resstate->trans4,
949*00b67f09SDavid van Moolenbroek 							 &resstate->trans4->xid);
950*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
951*00b67f09SDavid van Moolenbroek 				resstate->trans4->is_inprogress = ISC_TRUE;
952*00b67f09SDavid van Moolenbroek 				all_fail = ISC_FALSE;
953*00b67f09SDavid van Moolenbroek 			} else
954*00b67f09SDavid van Moolenbroek 				resstate->trans4->is_inprogress = ISC_FALSE;
955*00b67f09SDavid van Moolenbroek 		}
956*00b67f09SDavid van Moolenbroek 		if (resstate->trans6 != NULL) {
957*00b67f09SDavid van Moolenbroek 			result = dns_client_startresolve(client,
958*00b67f09SDavid van Moolenbroek 							 resstate->qname,
959*00b67f09SDavid van Moolenbroek 							 dns_rdataclass_in,
960*00b67f09SDavid van Moolenbroek 							 dns_rdatatype_aaaa,
961*00b67f09SDavid van Moolenbroek 							 0, task,
962*00b67f09SDavid van Moolenbroek 							 process_answer,
963*00b67f09SDavid van Moolenbroek 							 resstate->trans6,
964*00b67f09SDavid van Moolenbroek 							 &resstate->trans6->xid);
965*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
966*00b67f09SDavid van Moolenbroek 				resstate->trans6->is_inprogress = ISC_TRUE;
967*00b67f09SDavid van Moolenbroek 				all_fail = ISC_FALSE;
968*00b67f09SDavid van Moolenbroek 			} else
969*00b67f09SDavid van Moolenbroek 				resstate->trans6->is_inprogress= ISC_FALSE;
970*00b67f09SDavid van Moolenbroek 		}
971*00b67f09SDavid van Moolenbroek 	}
972*00b67f09SDavid van Moolenbroek 	if (!all_fail) {
973*00b67f09SDavid van Moolenbroek 		/* Start all the events */
974*00b67f09SDavid van Moolenbroek 		isc_app_ctxrun(actx);
975*00b67f09SDavid van Moolenbroek 	} else
976*00b67f09SDavid van Moolenbroek 		error = EAI_FAIL;
977*00b67f09SDavid van Moolenbroek 
978*00b67f09SDavid van Moolenbroek 	/* Cleanup */
979*00b67f09SDavid van Moolenbroek 	while ((resstate = ISC_LIST_HEAD(head.resstates)) != NULL) {
980*00b67f09SDavid van Moolenbroek 		int terror4 = 0, terror6 = 0;
981*00b67f09SDavid van Moolenbroek 
982*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(head.resstates, resstate, link);
983*00b67f09SDavid van Moolenbroek 
984*00b67f09SDavid van Moolenbroek 		if (*aip == NULL) {
985*00b67f09SDavid van Moolenbroek 			struct addrinfo *sentinel4 = NULL;
986*00b67f09SDavid van Moolenbroek 			struct addrinfo *sentinel6 = NULL;
987*00b67f09SDavid van Moolenbroek 
988*00b67f09SDavid van Moolenbroek 			if (resstate->trans4 != NULL) {
989*00b67f09SDavid van Moolenbroek 				sentinel4 =
990*00b67f09SDavid van Moolenbroek 					resstate->trans4->ai_sentinel.ai_next;
991*00b67f09SDavid van Moolenbroek 				resstate->trans4->ai_sentinel.ai_next = NULL;
992*00b67f09SDavid van Moolenbroek 			}
993*00b67f09SDavid van Moolenbroek 			if (resstate->trans6 != NULL) {
994*00b67f09SDavid van Moolenbroek 				sentinel6 =
995*00b67f09SDavid van Moolenbroek 					resstate->trans6->ai_sentinel.ai_next;
996*00b67f09SDavid van Moolenbroek 				resstate->trans6->ai_sentinel.ai_next = NULL;
997*00b67f09SDavid van Moolenbroek 			}
998*00b67f09SDavid van Moolenbroek 			*aip = ai_concat(sentinel4, sentinel6);
999*00b67f09SDavid van Moolenbroek 		}
1000*00b67f09SDavid van Moolenbroek 
1001*00b67f09SDavid van Moolenbroek 		if (resstate->trans4 != NULL) {
1002*00b67f09SDavid van Moolenbroek 			INSIST(resstate->trans4->xid == NULL);
1003*00b67f09SDavid van Moolenbroek 			terror4 = resstate->trans4->error;
1004*00b67f09SDavid van Moolenbroek 			isc_mem_put(mctx, resstate->trans4,
1005*00b67f09SDavid van Moolenbroek 				    sizeof(*resstate->trans4));
1006*00b67f09SDavid van Moolenbroek 		}
1007*00b67f09SDavid van Moolenbroek 		if (resstate->trans6 != NULL) {
1008*00b67f09SDavid van Moolenbroek 			INSIST(resstate->trans6->xid == NULL);
1009*00b67f09SDavid van Moolenbroek 			terror6 = resstate->trans6->error;
1010*00b67f09SDavid van Moolenbroek 			isc_mem_put(mctx, resstate->trans6,
1011*00b67f09SDavid van Moolenbroek 				    sizeof(*resstate->trans6));
1012*00b67f09SDavid van Moolenbroek 		}
1013*00b67f09SDavid van Moolenbroek 
1014*00b67f09SDavid van Moolenbroek 		/*
1015*00b67f09SDavid van Moolenbroek 		 * If the entire lookup fails, we need to choose an appropriate
1016*00b67f09SDavid van Moolenbroek 		 * error code from individual codes.  We'll try to provide as
1017*00b67f09SDavid van Moolenbroek 		 * specific a code as possible.  In general, we are going to
1018*00b67f09SDavid van Moolenbroek 		 * find an error code other than EAI_NONAME (which is too
1019*00b67f09SDavid van Moolenbroek 		 * generic and may actually not be problematic in some cases).
1020*00b67f09SDavid van Moolenbroek 		 * EAI_NONAME will be set below if no better code is found.
1021*00b67f09SDavid van Moolenbroek 		 */
1022*00b67f09SDavid van Moolenbroek 		if (terror == 0 || terror == EAI_NONAME) {
1023*00b67f09SDavid van Moolenbroek 			if (terror4 != 0 && terror4 != EAI_NONAME)
1024*00b67f09SDavid van Moolenbroek 				terror = terror4;
1025*00b67f09SDavid van Moolenbroek 			else if (terror6 != 0 && terror6 != EAI_NONAME)
1026*00b67f09SDavid van Moolenbroek 				terror = terror6;
1027*00b67f09SDavid van Moolenbroek 		}
1028*00b67f09SDavid van Moolenbroek 
1029*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, resstate, sizeof(*resstate));
1030*00b67f09SDavid van Moolenbroek 	}
1031*00b67f09SDavid van Moolenbroek 
1032*00b67f09SDavid van Moolenbroek 	if (*aip == NULL) {
1033*00b67f09SDavid van Moolenbroek 		error = terror;
1034*00b67f09SDavid van Moolenbroek 		if (error == 0)
1035*00b67f09SDavid van Moolenbroek 			error = EAI_NONAME;
1036*00b67f09SDavid van Moolenbroek 	}
1037*00b67f09SDavid van Moolenbroek 
1038*00b67f09SDavid van Moolenbroek #if 1	/*  XXX: enabled for finding leaks.  should be cleaned up later. */
1039*00b67f09SDavid van Moolenbroek 	isc_app_ctxfinish(actx);
1040*00b67f09SDavid van Moolenbroek 	irs_context_destroy(&irsctx);
1041*00b67f09SDavid van Moolenbroek #endif
1042*00b67f09SDavid van Moolenbroek 
1043*00b67f09SDavid van Moolenbroek 	return (error);
1044*00b67f09SDavid van Moolenbroek }
1045*00b67f09SDavid van Moolenbroek 
1046*00b67f09SDavid van Moolenbroek static char *
irs_strsep(char ** stringp,const char * delim)1047*00b67f09SDavid van Moolenbroek irs_strsep(char **stringp, const char *delim) {
1048*00b67f09SDavid van Moolenbroek 	char *string = *stringp;
1049*00b67f09SDavid van Moolenbroek 	char *s;
1050*00b67f09SDavid van Moolenbroek 	const char *d;
1051*00b67f09SDavid van Moolenbroek 	char sc, dc;
1052*00b67f09SDavid van Moolenbroek 
1053*00b67f09SDavid van Moolenbroek 	if (string == NULL)
1054*00b67f09SDavid van Moolenbroek 		return (NULL);
1055*00b67f09SDavid van Moolenbroek 
1056*00b67f09SDavid van Moolenbroek 	for (s = string; *s != '\0'; s++) {
1057*00b67f09SDavid van Moolenbroek 		sc = *s;
1058*00b67f09SDavid van Moolenbroek 		for (d = delim; (dc = *d) != '\0'; d++)
1059*00b67f09SDavid van Moolenbroek 			if (sc == dc) {
1060*00b67f09SDavid van Moolenbroek 				*s++ = '\0';
1061*00b67f09SDavid van Moolenbroek 				*stringp = s;
1062*00b67f09SDavid van Moolenbroek 				return (string);
1063*00b67f09SDavid van Moolenbroek 			}
1064*00b67f09SDavid van Moolenbroek 	}
1065*00b67f09SDavid van Moolenbroek 	*stringp = NULL;
1066*00b67f09SDavid van Moolenbroek 	return (string);
1067*00b67f09SDavid van Moolenbroek }
1068*00b67f09SDavid van Moolenbroek 
1069*00b67f09SDavid van Moolenbroek static void
set_order(int family,int (** net_order)(const char *,int,struct addrinfo **,int,int))1070*00b67f09SDavid van Moolenbroek set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
1071*00b67f09SDavid van Moolenbroek 					int, int))
1072*00b67f09SDavid van Moolenbroek {
1073*00b67f09SDavid van Moolenbroek 	char *order, *tok;
1074*00b67f09SDavid van Moolenbroek 	int found;
1075*00b67f09SDavid van Moolenbroek 
1076*00b67f09SDavid van Moolenbroek 	if (family) {
1077*00b67f09SDavid van Moolenbroek 		switch (family) {
1078*00b67f09SDavid van Moolenbroek 		case AF_INET:
1079*00b67f09SDavid van Moolenbroek 			*net_order++ = add_ipv4;
1080*00b67f09SDavid van Moolenbroek 			break;
1081*00b67f09SDavid van Moolenbroek 		case AF_INET6:
1082*00b67f09SDavid van Moolenbroek 			*net_order++ = add_ipv6;
1083*00b67f09SDavid van Moolenbroek 			break;
1084*00b67f09SDavid van Moolenbroek 		}
1085*00b67f09SDavid van Moolenbroek 	} else {
1086*00b67f09SDavid van Moolenbroek 		order = getenv("NET_ORDER");
1087*00b67f09SDavid van Moolenbroek 		found = 0;
1088*00b67f09SDavid van Moolenbroek 		while (order != NULL) {
1089*00b67f09SDavid van Moolenbroek 			/*
1090*00b67f09SDavid van Moolenbroek 			 * We ignore any unknown names.
1091*00b67f09SDavid van Moolenbroek 			 */
1092*00b67f09SDavid van Moolenbroek 			tok = irs_strsep(&order, ":");
1093*00b67f09SDavid van Moolenbroek 			if (strcasecmp(tok, "inet6") == 0) {
1094*00b67f09SDavid van Moolenbroek 				if ((found & FOUND_IPV6) == 0)
1095*00b67f09SDavid van Moolenbroek 					*net_order++ = add_ipv6;
1096*00b67f09SDavid van Moolenbroek 				found |= FOUND_IPV6;
1097*00b67f09SDavid van Moolenbroek 			} else if (strcasecmp(tok, "inet") == 0 ||
1098*00b67f09SDavid van Moolenbroek 			    strcasecmp(tok, "inet4") == 0) {
1099*00b67f09SDavid van Moolenbroek 				if ((found & FOUND_IPV4) == 0)
1100*00b67f09SDavid van Moolenbroek 					*net_order++ = add_ipv4;
1101*00b67f09SDavid van Moolenbroek 				found |= FOUND_IPV4;
1102*00b67f09SDavid van Moolenbroek 			}
1103*00b67f09SDavid van Moolenbroek 		}
1104*00b67f09SDavid van Moolenbroek 
1105*00b67f09SDavid van Moolenbroek 		/*
1106*00b67f09SDavid van Moolenbroek 		 * Add in anything that we didn't find.
1107*00b67f09SDavid van Moolenbroek 		 */
1108*00b67f09SDavid van Moolenbroek 		if ((found & FOUND_IPV4) == 0)
1109*00b67f09SDavid van Moolenbroek 			*net_order++ = add_ipv4;
1110*00b67f09SDavid van Moolenbroek 		if ((found & FOUND_IPV6) == 0)
1111*00b67f09SDavid van Moolenbroek 			*net_order++ = add_ipv6;
1112*00b67f09SDavid van Moolenbroek 	}
1113*00b67f09SDavid van Moolenbroek 	*net_order = NULL;
1114*00b67f09SDavid van Moolenbroek 	return;
1115*00b67f09SDavid van Moolenbroek }
1116*00b67f09SDavid van Moolenbroek 
1117*00b67f09SDavid van Moolenbroek static char v4_loop[4] = { 127, 0, 0, 1 };
1118*00b67f09SDavid van Moolenbroek 
1119*00b67f09SDavid van Moolenbroek static int
add_ipv4(const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)1120*00b67f09SDavid van Moolenbroek add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
1121*00b67f09SDavid van Moolenbroek 	 int socktype, int port)
1122*00b67f09SDavid van Moolenbroek {
1123*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai;
1124*00b67f09SDavid van Moolenbroek 
1125*00b67f09SDavid van Moolenbroek 	UNUSED(hostname);
1126*00b67f09SDavid van Moolenbroek 	UNUSED(flags);
1127*00b67f09SDavid van Moolenbroek 
1128*00b67f09SDavid van Moolenbroek 	ai = ai_clone(*aip, AF_INET); /* don't use ai_clone() */
1129*00b67f09SDavid van Moolenbroek 	if (ai == NULL) {
1130*00b67f09SDavid van Moolenbroek 		_freeaddrinfo(*aip);
1131*00b67f09SDavid van Moolenbroek 		return (EAI_MEMORY);
1132*00b67f09SDavid van Moolenbroek 	}
1133*00b67f09SDavid van Moolenbroek 
1134*00b67f09SDavid van Moolenbroek 	*aip = ai;
1135*00b67f09SDavid van Moolenbroek 	ai->ai_socktype = socktype;
1136*00b67f09SDavid van Moolenbroek 	SIN(ai->ai_addr)->sin_port = port;
1137*00b67f09SDavid van Moolenbroek 	memmove(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
1138*00b67f09SDavid van Moolenbroek 
1139*00b67f09SDavid van Moolenbroek 	return (0);
1140*00b67f09SDavid van Moolenbroek }
1141*00b67f09SDavid van Moolenbroek 
1142*00b67f09SDavid van Moolenbroek static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1143*00b67f09SDavid van Moolenbroek 
1144*00b67f09SDavid van Moolenbroek static int
add_ipv6(const char * hostname,int flags,struct addrinfo ** aip,int socktype,int port)1145*00b67f09SDavid van Moolenbroek add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
1146*00b67f09SDavid van Moolenbroek 	 int socktype, int port)
1147*00b67f09SDavid van Moolenbroek {
1148*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai;
1149*00b67f09SDavid van Moolenbroek 
1150*00b67f09SDavid van Moolenbroek 	UNUSED(hostname);
1151*00b67f09SDavid van Moolenbroek 	UNUSED(flags);
1152*00b67f09SDavid van Moolenbroek 
1153*00b67f09SDavid van Moolenbroek 	ai = ai_clone(*aip, AF_INET6); /* don't use ai_clone() */
1154*00b67f09SDavid van Moolenbroek 	if (ai == NULL)
1155*00b67f09SDavid van Moolenbroek 		return (EAI_MEMORY);
1156*00b67f09SDavid van Moolenbroek 
1157*00b67f09SDavid van Moolenbroek 	*aip = ai;
1158*00b67f09SDavid van Moolenbroek 	ai->ai_socktype = socktype;
1159*00b67f09SDavid van Moolenbroek 	SIN6(ai->ai_addr)->sin6_port = port;
1160*00b67f09SDavid van Moolenbroek 	memmove(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
1161*00b67f09SDavid van Moolenbroek 
1162*00b67f09SDavid van Moolenbroek 	return (0);
1163*00b67f09SDavid van Moolenbroek }
1164*00b67f09SDavid van Moolenbroek 
1165*00b67f09SDavid van Moolenbroek /*% Free address info. */
1166*00b67f09SDavid van Moolenbroek void
freeaddrinfo(struct addrinfo * ai)1167*00b67f09SDavid van Moolenbroek freeaddrinfo(struct addrinfo *ai) {
1168*00b67f09SDavid van Moolenbroek 	_freeaddrinfo(ai);
1169*00b67f09SDavid van Moolenbroek }
1170*00b67f09SDavid van Moolenbroek 
1171*00b67f09SDavid van Moolenbroek static void
_freeaddrinfo(struct addrinfo * ai)1172*00b67f09SDavid van Moolenbroek _freeaddrinfo(struct addrinfo *ai) {
1173*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai_next;
1174*00b67f09SDavid van Moolenbroek 
1175*00b67f09SDavid van Moolenbroek 	while (ai != NULL) {
1176*00b67f09SDavid van Moolenbroek 		ai_next = ai->ai_next;
1177*00b67f09SDavid van Moolenbroek 		if (ai->ai_addr != NULL)
1178*00b67f09SDavid van Moolenbroek 			free(ai->ai_addr);
1179*00b67f09SDavid van Moolenbroek 		if (ai->ai_canonname)
1180*00b67f09SDavid van Moolenbroek 			free(ai->ai_canonname);
1181*00b67f09SDavid van Moolenbroek 		free(ai);
1182*00b67f09SDavid van Moolenbroek 		ai = ai_next;
1183*00b67f09SDavid van Moolenbroek 	}
1184*00b67f09SDavid van Moolenbroek }
1185*00b67f09SDavid van Moolenbroek 
1186*00b67f09SDavid van Moolenbroek #ifdef AF_LOCAL
1187*00b67f09SDavid van Moolenbroek static int
get_local(const char * name,int socktype,struct addrinfo ** res)1188*00b67f09SDavid van Moolenbroek get_local(const char *name, int socktype, struct addrinfo **res) {
1189*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai;
1190*00b67f09SDavid van Moolenbroek 	struct sockaddr_un *slocal;
1191*00b67f09SDavid van Moolenbroek 
1192*00b67f09SDavid van Moolenbroek 	if (socktype == 0)
1193*00b67f09SDavid van Moolenbroek 		return (EAI_SOCKTYPE);
1194*00b67f09SDavid van Moolenbroek 
1195*00b67f09SDavid van Moolenbroek 	ai = ai_alloc(AF_LOCAL, sizeof(*slocal));
1196*00b67f09SDavid van Moolenbroek 	if (ai == NULL)
1197*00b67f09SDavid van Moolenbroek 		return (EAI_MEMORY);
1198*00b67f09SDavid van Moolenbroek 
1199*00b67f09SDavid van Moolenbroek 	slocal = SLOCAL(ai->ai_addr);
1200*00b67f09SDavid van Moolenbroek 	strlcpy(slocal->sun_path, name, sizeof(slocal->sun_path));
1201*00b67f09SDavid van Moolenbroek 
1202*00b67f09SDavid van Moolenbroek 	ai->ai_socktype = socktype;
1203*00b67f09SDavid van Moolenbroek 	/*
1204*00b67f09SDavid van Moolenbroek 	 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
1205*00b67f09SDavid van Moolenbroek 	 * and ai->ai_next were initialized to zero.
1206*00b67f09SDavid van Moolenbroek 	 */
1207*00b67f09SDavid van Moolenbroek 
1208*00b67f09SDavid van Moolenbroek 	*res = ai;
1209*00b67f09SDavid van Moolenbroek 	return (0);
1210*00b67f09SDavid van Moolenbroek }
1211*00b67f09SDavid van Moolenbroek #endif
1212*00b67f09SDavid van Moolenbroek 
1213*00b67f09SDavid van Moolenbroek /*!
1214*00b67f09SDavid van Moolenbroek  * Allocate an addrinfo structure, and a sockaddr structure
1215*00b67f09SDavid van Moolenbroek  * of the specificed length.  We initialize:
1216*00b67f09SDavid van Moolenbroek  *	ai_addrlen
1217*00b67f09SDavid van Moolenbroek  *	ai_family
1218*00b67f09SDavid van Moolenbroek  *	ai_addr
1219*00b67f09SDavid van Moolenbroek  *	ai_addr->sa_family
1220*00b67f09SDavid van Moolenbroek  *	ai_addr->sa_len	(IRS_PLATFORM_HAVESALEN)
1221*00b67f09SDavid van Moolenbroek  * and everything else is initialized to zero.
1222*00b67f09SDavid van Moolenbroek  */
1223*00b67f09SDavid van Moolenbroek static struct addrinfo *
ai_alloc(int family,int addrlen)1224*00b67f09SDavid van Moolenbroek ai_alloc(int family, int addrlen) {
1225*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai;
1226*00b67f09SDavid van Moolenbroek 
1227*00b67f09SDavid van Moolenbroek 	ai = (struct addrinfo *)calloc(1, sizeof(*ai));
1228*00b67f09SDavid van Moolenbroek 	if (ai == NULL)
1229*00b67f09SDavid van Moolenbroek 		return (NULL);
1230*00b67f09SDavid van Moolenbroek 
1231*00b67f09SDavid van Moolenbroek 	ai->ai_addr = SA(calloc(1, addrlen));
1232*00b67f09SDavid van Moolenbroek 	if (ai->ai_addr == NULL) {
1233*00b67f09SDavid van Moolenbroek 		free(ai);
1234*00b67f09SDavid van Moolenbroek 		return (NULL);
1235*00b67f09SDavid van Moolenbroek 	}
1236*00b67f09SDavid van Moolenbroek 	ai->ai_addrlen = addrlen;
1237*00b67f09SDavid van Moolenbroek 	ai->ai_family = family;
1238*00b67f09SDavid van Moolenbroek 	ai->ai_addr->sa_family = family;
1239*00b67f09SDavid van Moolenbroek #ifdef IRS_PLATFORM_HAVESALEN
1240*00b67f09SDavid van Moolenbroek 	ai->ai_addr->sa_len = addrlen;
1241*00b67f09SDavid van Moolenbroek #endif
1242*00b67f09SDavid van Moolenbroek 	return (ai);
1243*00b67f09SDavid van Moolenbroek }
1244*00b67f09SDavid van Moolenbroek 
1245*00b67f09SDavid van Moolenbroek static struct addrinfo *
ai_clone(struct addrinfo * oai,int family)1246*00b67f09SDavid van Moolenbroek ai_clone(struct addrinfo *oai, int family) {
1247*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai;
1248*00b67f09SDavid van Moolenbroek 
1249*00b67f09SDavid van Moolenbroek 	ai = ai_alloc(family, ((family == AF_INET6) ?
1250*00b67f09SDavid van Moolenbroek 	    sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
1251*00b67f09SDavid van Moolenbroek 
1252*00b67f09SDavid van Moolenbroek 	if (ai == NULL) {
1253*00b67f09SDavid van Moolenbroek 		if (oai != NULL)
1254*00b67f09SDavid van Moolenbroek 			freeaddrinfo(oai);
1255*00b67f09SDavid van Moolenbroek 		return (NULL);
1256*00b67f09SDavid van Moolenbroek 	}
1257*00b67f09SDavid van Moolenbroek 	if (oai == NULL)
1258*00b67f09SDavid van Moolenbroek 		return (ai);
1259*00b67f09SDavid van Moolenbroek 
1260*00b67f09SDavid van Moolenbroek 	ai->ai_flags = oai->ai_flags;
1261*00b67f09SDavid van Moolenbroek 	ai->ai_socktype = oai->ai_socktype;
1262*00b67f09SDavid van Moolenbroek 	ai->ai_protocol = oai->ai_protocol;
1263*00b67f09SDavid van Moolenbroek 	ai->ai_canonname = NULL;
1264*00b67f09SDavid van Moolenbroek 	ai->ai_next = oai;
1265*00b67f09SDavid van Moolenbroek 	return (ai);
1266*00b67f09SDavid van Moolenbroek }
1267*00b67f09SDavid van Moolenbroek 
1268*00b67f09SDavid van Moolenbroek static struct addrinfo *
ai_reverse(struct addrinfo * oai)1269*00b67f09SDavid van Moolenbroek ai_reverse(struct addrinfo *oai) {
1270*00b67f09SDavid van Moolenbroek 	struct addrinfo *nai, *tai;
1271*00b67f09SDavid van Moolenbroek 
1272*00b67f09SDavid van Moolenbroek 	nai = NULL;
1273*00b67f09SDavid van Moolenbroek 
1274*00b67f09SDavid van Moolenbroek 	while (oai != NULL) {
1275*00b67f09SDavid van Moolenbroek 		/*
1276*00b67f09SDavid van Moolenbroek 		 * Grab one off the old list.
1277*00b67f09SDavid van Moolenbroek 		 */
1278*00b67f09SDavid van Moolenbroek 		tai = oai;
1279*00b67f09SDavid van Moolenbroek 		oai = oai->ai_next;
1280*00b67f09SDavid van Moolenbroek 		/*
1281*00b67f09SDavid van Moolenbroek 		 * Put it on the front of the new list.
1282*00b67f09SDavid van Moolenbroek 		 */
1283*00b67f09SDavid van Moolenbroek 		tai->ai_next = nai;
1284*00b67f09SDavid van Moolenbroek 		nai = tai;
1285*00b67f09SDavid van Moolenbroek 	}
1286*00b67f09SDavid van Moolenbroek 	return (nai);
1287*00b67f09SDavid van Moolenbroek }
1288*00b67f09SDavid van Moolenbroek 
1289*00b67f09SDavid van Moolenbroek 
1290*00b67f09SDavid van Moolenbroek static struct addrinfo *
ai_concat(struct addrinfo * ai1,struct addrinfo * ai2)1291*00b67f09SDavid van Moolenbroek ai_concat(struct addrinfo *ai1, struct addrinfo *ai2) {
1292*00b67f09SDavid van Moolenbroek 	struct addrinfo *ai_tmp;
1293*00b67f09SDavid van Moolenbroek 
1294*00b67f09SDavid van Moolenbroek 	if (ai1 == NULL)
1295*00b67f09SDavid van Moolenbroek 		return (ai2);
1296*00b67f09SDavid van Moolenbroek 	else if (ai2 == NULL)
1297*00b67f09SDavid van Moolenbroek 		return (ai1);
1298*00b67f09SDavid van Moolenbroek 
1299*00b67f09SDavid van Moolenbroek 	for (ai_tmp = ai1; ai_tmp != NULL && ai_tmp->ai_next != NULL;
1300*00b67f09SDavid van Moolenbroek 	     ai_tmp = ai_tmp->ai_next)
1301*00b67f09SDavid van Moolenbroek 		;
1302*00b67f09SDavid van Moolenbroek 
1303*00b67f09SDavid van Moolenbroek 	ai_tmp->ai_next = ai2;
1304*00b67f09SDavid van Moolenbroek 
1305*00b67f09SDavid van Moolenbroek 	return (ai1);
1306*00b67f09SDavid van Moolenbroek }
1307