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