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