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