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