BIND: update vendor tree to 9.5.2-P2
[dragonfly.git] / contrib / bind / lib / lwres / getaddrinfo.c
1 /*
2  * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001  Internet Software Consortium.
4  *
5  * This code is derived from software contributed to ISC by
6  * Berkeley Software Design, Inc.
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC.
13  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
15  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
18  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 /* $Id: getaddrinfo.c,v 1.52.60.2 2008/11/25 23:46:36 tbox Exp $ */
22
23 /*! \file */
24
25 /**
26  *    lwres_getaddrinfo() is used to get a list of IP addresses and port
27  *    numbers for host hostname and service servname. The function is the
28  *    lightweight resolver's implementation of getaddrinfo() as defined in
29  *    RFC2133. hostname and servname are pointers to null-terminated strings
30  *    or NULL. hostname is either a host name or a numeric host address
31  *    string: a dotted decimal IPv4 address or an IPv6 address. servname is
32  *    either a decimal port number or a service name as listed in
33  *    /etc/services.
34  *
35  *    If the operating system does not provide a struct addrinfo, the
36  *    following structure is used:
37  *
38  * \code
39  * struct  addrinfo {
40  *         int             ai_flags;       // AI_PASSIVE, AI_CANONNAME
41  *         int             ai_family;      // PF_xxx
42  *         int             ai_socktype;    // SOCK_xxx
43  *         int             ai_protocol;    // 0 or IPPROTO_xxx for IPv4 and IPv6
44  *         size_t          ai_addrlen;     // length of ai_addr
45  *         char            *ai_canonname;  // canonical name for hostname
46  *         struct sockaddr *ai_addr;       // binary address
47  *         struct addrinfo *ai_next;       // next structure in linked list
48  * };
49  * \endcode
50  *
51  *
52  *    hints is an optional pointer to a struct addrinfo. This structure can
53  *    be used to provide hints concerning the type of socket that the caller
54  *    supports or wishes to use. The caller can supply the following
55  *    structure elements in *hints:
56  *
57  * <ul>
58  *    <li>ai_family:
59  *           The protocol family that should be used. When ai_family is set
60  *           to PF_UNSPEC, it means the caller will accept any protocol
61  *           family supported by the operating system.</li>
62  *
63  *    <li>ai_socktype:
64  *           denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
65  *           SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
66  *           will accept any socket type.</li>
67  *
68  *    <li>ai_protocol:
69  *           indicates which transport protocol is wanted: IPPROTO_UDP or
70  *           IPPROTO_TCP. If ai_protocol is zero the caller will accept any
71  *           protocol.</li>
72  *
73  *    <li>ai_flags:
74  *           Flag bits. If the AI_CANONNAME bit is set, a successful call to
75  *           lwres_getaddrinfo() will return a null-terminated string
76  *           containing the canonical name of the specified hostname in
77  *           ai_canonname of the first addrinfo structure returned. Setting
78  *           the AI_PASSIVE bit indicates that the returned socket address
79  *           structure is intended for used in a call to bind(2). In this
80  *           case, if the hostname argument is a NULL pointer, then the IP
81  *           address portion of the socket address structure will be set to
82  *           INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
83  *           address.<br /><br />
84  *
85  *           When ai_flags does not set the AI_PASSIVE bit, the returned
86  *           socket address structure will be ready for use in a call to
87  *           connect(2) for a connection-oriented protocol or connect(2),
88  *           sendto(2), or sendmsg(2) if a connectionless protocol was
89  *           chosen. The IP address portion of the socket address structure
90  *           will be set to the loopback address if hostname is a NULL
91  *           pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
92  *
93  *           If ai_flags is set to AI_NUMERICHOST it indicates that hostname
94  *           should be treated as a numeric string defining an IPv4 or IPv6
95  *           address and no name resolution should be attempted.
96  * </li></ul>
97  *
98  *    All other elements of the struct addrinfo passed via hints must be
99  *    zero.
100  *
101  *    A hints of NULL is treated as if the caller provided a struct addrinfo
102  *    initialized to zero with ai_familyset to PF_UNSPEC.
103  *
104  *    After a successful call to lwres_getaddrinfo(), *res is a pointer to a
105  *    linked list of one or more addrinfo structures. Each struct addrinfo
106  *    in this list cn be processed by following the ai_next pointer, until a
107  *    NULL pointer is encountered. The three members ai_family, ai_socktype,
108  *    and ai_protocol in each returned addrinfo structure contain the
109  *    corresponding arguments for a call to socket(2). For each addrinfo
110  *    structure in the list, the ai_addr member points to a filled-in socket
111  *    address structure of length ai_addrlen.
112  *
113  *    All of the information returned by lwres_getaddrinfo() is dynamically
114  *    allocated: the addrinfo structures, and the socket address structures
115  *    and canonical host name strings pointed to by the addrinfostructures.
116  *    Memory allocated for the dynamically allocated structures created by a
117  *    successful call to lwres_getaddrinfo() is released by
118  *    lwres_freeaddrinfo(). ai is a pointer to a struct addrinfo created by
119  *    a call to lwres_getaddrinfo().
120  *
121  * \section lwresreturn RETURN VALUES
122  *
123  *    lwres_getaddrinfo() returns zero on success or one of the error codes
124  *    listed in gai_strerror() if an error occurs. If both hostname and
125  *    servname are NULL lwres_getaddrinfo() returns #EAI_NONAME.
126  *
127  * \section lwressee SEE ALSO
128  *
129  *    lwres(3), lwres_getaddrinfo(), lwres_freeaddrinfo(),
130  *    lwres_gai_strerror(), RFC2133, getservbyname(3), connect(2),
131  *    sendto(2), sendmsg(2), socket(2).
132  */
133
134 #include <config.h>
135
136 #include <errno.h>
137
138 #include <isc/string.h>
139
140 #include <lwres/lwres.h>
141 #include <lwres/net.h>
142 #include <lwres/netdb.h>
143 #include <lwres/stdlib.h>
144
145 #define SA(addr)        ((struct sockaddr *)(addr))
146 #define SIN(addr)       ((struct sockaddr_in *)(addr))
147 #define SIN6(addr)      ((struct sockaddr_in6 *)(addr))
148 #define SLOCAL(addr)    ((struct sockaddr_un *)(addr))
149
150 /*! \struct addrinfo
151  */
152 static struct addrinfo
153         *ai_reverse(struct addrinfo *oai),
154         *ai_clone(struct addrinfo *oai, int family),
155         *ai_alloc(int family, int addrlen);
156 #ifdef AF_LOCAL
157 static int get_local(const char *name, int socktype, struct addrinfo **res);
158 #endif
159
160 static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
161     int socktype, int port);
162 static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
163     int socktype, int port);
164 static void set_order(int, int (**)(const char *, int, struct addrinfo **,
165          int, int));
166
167 #define FOUND_IPV4      0x1
168 #define FOUND_IPV6      0x2
169 #define FOUND_MAX       2
170
171 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
172 /*% Get a list of IP addresses and port numbers for host hostname and service servname. */
173 int
174 lwres_getaddrinfo(const char *hostname, const char *servname,
175         const struct addrinfo *hints, struct addrinfo **res)
176 {
177         struct servent *sp;
178         const char *proto;
179         int family, socktype, flags, protocol;
180         struct addrinfo *ai, *ai_list;
181         int port, err, i;
182         int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
183                  int, int);
184
185         if (hostname == NULL && servname == NULL)
186                 return (EAI_NONAME);
187
188         proto = NULL;
189         if (hints != NULL) {
190                 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
191                         return (EAI_BADFLAGS);
192                 if (hints->ai_addrlen || hints->ai_canonname ||
193                     hints->ai_addr || hints->ai_next) {
194                         errno = EINVAL;
195                         return (EAI_SYSTEM);
196                 }
197                 family = hints->ai_family;
198                 socktype = hints->ai_socktype;
199                 protocol = hints->ai_protocol;
200                 flags = hints->ai_flags;
201                 switch (family) {
202                 case AF_UNSPEC:
203                         switch (hints->ai_socktype) {
204                         case SOCK_STREAM:
205                                 proto = "tcp";
206                                 break;
207                         case SOCK_DGRAM:
208                                 proto = "udp";
209                                 break;
210                         }
211                         break;
212                 case AF_INET:
213                 case AF_INET6:
214                         switch (hints->ai_socktype) {
215                         case 0:
216                                 break;
217                         case SOCK_STREAM:
218                                 proto = "tcp";
219                                 break;
220                         case SOCK_DGRAM:
221                                 proto = "udp";
222                                 break;
223                         case SOCK_RAW:
224                                 break;
225                         default:
226                                 return (EAI_SOCKTYPE);
227                         }
228                         break;
229 #ifdef  AF_LOCAL
230                 case AF_LOCAL:
231                         switch (hints->ai_socktype) {
232                         case 0:
233                                 break;
234                         case SOCK_STREAM:
235                                 break;
236                         case SOCK_DGRAM:
237                                 break;
238                         default:
239                                 return (EAI_SOCKTYPE);
240                         }
241                         break;
242 #endif
243                 default:
244                         return (EAI_FAMILY);
245                 }
246         } else {
247                 protocol = 0;
248                 family = 0;
249                 socktype = 0;
250                 flags = 0;
251         }
252
253 #ifdef  AF_LOCAL
254         /*!
255          * First, deal with AF_LOCAL.  If the family was not set,
256          * then assume AF_LOCAL if the first character of the
257          * hostname/servname is '/'.
258          */
259
260         if (hostname != NULL &&
261             (family == AF_LOCAL || (family == 0 && *hostname == '/')))
262                 return (get_local(hostname, socktype, res));
263
264         if (servname != NULL &&
265             (family == AF_LOCAL || (family == 0 && *servname == '/')))
266                 return (get_local(servname, socktype, res));
267 #endif
268
269         /*
270          * Ok, only AF_INET and AF_INET6 left.
271          */
272         ai_list = NULL;
273
274         /*
275          * First, look up the service name (port) if it was
276          * requested.  If the socket type wasn't specified, then
277          * try and figure it out.
278          */
279         if (servname != NULL) {
280                 char *e;
281
282                 port = strtol(servname, &e, 10);
283                 if (*e == '\0') {
284                         if (socktype == 0)
285                                 return (EAI_SOCKTYPE);
286                         if (port < 0 || port > 65535)
287                                 return (EAI_SERVICE);
288                         port = htons((unsigned short) port);
289                 } else {
290                         sp = getservbyname(servname, proto);
291                         if (sp == NULL)
292                                 return (EAI_SERVICE);
293                         port = sp->s_port;
294                         if (socktype == 0) {
295                                 if (strcmp(sp->s_proto, "tcp") == 0)
296                                         socktype = SOCK_STREAM;
297                                 else if (strcmp(sp->s_proto, "udp") == 0)
298                                         socktype = SOCK_DGRAM;
299                         }
300                 }
301         } else
302                 port = 0;
303
304         /*
305          * Next, deal with just a service name, and no hostname.
306          * (we verified that one of them was non-null up above).
307          */
308         if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
309                 if (family == AF_INET || family == 0) {
310                         ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
311                         if (ai == NULL)
312                                 return (EAI_MEMORY);
313                         ai->ai_socktype = socktype;
314                         ai->ai_protocol = protocol;
315                         SIN(ai->ai_addr)->sin_port = port;
316                         ai->ai_next = ai_list;
317                         ai_list = ai;
318                 }
319
320                 if (family == AF_INET6 || family == 0) {
321                         ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
322                         if (ai == NULL) {
323                                 lwres_freeaddrinfo(ai_list);
324                                 return (EAI_MEMORY);
325                         }
326                         ai->ai_socktype = socktype;
327                         ai->ai_protocol = protocol;
328                         SIN6(ai->ai_addr)->sin6_port = port;
329                         ai->ai_next = ai_list;
330                         ai_list = ai;
331                 }
332
333                 *res = ai_list;
334                 return (0);
335         }
336
337         /*
338          * If the family isn't specified or AI_NUMERICHOST specified,
339          * check first to see if it is a numeric address.
340          * Though the gethostbyname2() routine
341          * will recognize numeric addresses, it will only recognize
342          * the format that it is being called for.  Thus, a numeric
343          * AF_INET address will be treated by the AF_INET6 call as
344          * a domain name, and vice versa.  Checking for both numerics
345          * here avoids that.
346          */
347         if (hostname != NULL &&
348             (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
349                 char abuf[sizeof(struct in6_addr)];
350                 char nbuf[NI_MAXHOST];
351                 int addrsize, addroff;
352 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
353                 char *p, *ep;
354                 char ntmp[NI_MAXHOST];
355                 lwres_uint32_t scopeid;
356 #endif
357
358 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
359                 /*
360                  * Scope identifier portion.
361                  */
362                 ntmp[0] = '\0';
363                 if (strchr(hostname, '%') != NULL) {
364                         strncpy(ntmp, hostname, sizeof(ntmp) - 1);
365                         ntmp[sizeof(ntmp) - 1] = '\0';
366                         p = strchr(ntmp, '%');
367                         ep = NULL;
368
369                         /*
370                          * Vendors may want to support non-numeric
371                          * scopeid around here.
372                          */
373
374                         if (p != NULL)
375                                 scopeid = (lwres_uint32_t)strtoul(p + 1,
376                                                                   &ep, 10);
377                         if (p != NULL && ep != NULL && ep[0] == '\0')
378                                 *p = '\0';
379                         else {
380                                 ntmp[0] = '\0';
381                                 scopeid = 0;
382                         }
383                 } else
384                         scopeid = 0;
385 #endif
386
387                if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
388                    == 1)
389                {
390                         if (family == AF_INET6) {
391                                 /*
392                                  * Convert to a V4 mapped address.
393                                  */
394                                 struct in6_addr *a6 = (struct in6_addr *)abuf;
395                                 memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
396                                 memset(&a6->s6_addr[10], 0xff, 2);
397                                 memset(&a6->s6_addr[0], 0, 10);
398                                 goto inet6_addr;
399                         }
400                         addrsize = sizeof(struct in_addr);
401                         addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
402                         family = AF_INET;
403                         goto common;
404 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
405                 } else if (ntmp[0] != '\0' &&
406                            lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
407                 {
408                         if (family && family != AF_INET6)
409                                 return (EAI_NONAME);
410                         addrsize = sizeof(struct in6_addr);
411                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
412                         family = AF_INET6;
413                         goto common;
414 #endif
415                 } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
416                         if (family != 0 && family != AF_INET6)
417                                 return (EAI_NONAME);
418                 inet6_addr:
419                         addrsize = sizeof(struct in6_addr);
420                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
421                         family = AF_INET6;
422
423                 common:
424                         ai = ai_clone(ai_list, family);
425                         if (ai == NULL)
426                                 return (EAI_MEMORY);
427                         ai_list = ai;
428                         ai->ai_socktype = socktype;
429                         SIN(ai->ai_addr)->sin_port = port;
430                         memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
431                         if (flags & AI_CANONNAME) {
432 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
433                                 if (ai->ai_family == AF_INET6)
434                                         SIN6(ai->ai_addr)->sin6_scope_id =
435                                                                         scopeid;
436 #endif
437                                 if (lwres_getnameinfo(ai->ai_addr,
438                                     ai->ai_addrlen, nbuf, sizeof(nbuf),
439                                                       NULL, 0,
440                                                       NI_NUMERICHOST) == 0) {
441                                         ai->ai_canonname = strdup(nbuf);
442                                         if (ai->ai_canonname == NULL) {
443                                                 lwres_freeaddrinfo(ai_list);
444                                                 return (EAI_MEMORY);
445                                         }
446                                 } else {
447                                         /* XXX raise error? */
448                                         ai->ai_canonname = NULL;
449                                 }
450                         }
451                         goto done;
452                 } else if ((flags & AI_NUMERICHOST) != 0) {
453                         return (EAI_NONAME);
454                 }
455         }
456
457         set_order(family, net_order);
458         for (i = 0; i < FOUND_MAX; i++) {
459                 if (net_order[i] == NULL)
460                         break;
461                 err = (net_order[i])(hostname, flags, &ai_list,
462                                      socktype, port);
463                 if (err != 0)
464                         return (err);
465         }
466
467         if (ai_list == NULL)
468                 return (EAI_NODATA);
469
470 done:
471         ai_list = ai_reverse(ai_list);
472
473         *res = ai_list;
474         return (0);
475 }
476
477 static char *
478 lwres_strsep(char **stringp, const char *delim) {
479         char *string = *stringp;
480         char *s;
481         const char *d;
482         char sc, dc;
483
484         if (string == NULL)
485                 return (NULL);
486
487         for (s = string; *s != '\0'; s++) {
488                 sc = *s;
489                 for (d = delim; (dc = *d) != '\0'; d++)
490                         if (sc == dc) {
491                                 *s++ = '\0';
492                                 *stringp = s;
493                                 return (string);
494                         }
495         }
496         *stringp = NULL;
497         return (string);
498 }
499
500 static void
501 set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
502                                         int, int))
503 {
504         char *order, *tok;
505         int found;
506
507         if (family) {
508                 switch (family) {
509                 case AF_INET:
510                         *net_order++ = add_ipv4;
511                         break;
512                 case AF_INET6:
513                         *net_order++ = add_ipv6;
514                         break;
515                 }
516         } else {
517                 order = getenv("NET_ORDER");
518                 found = 0;
519                 while (order != NULL) {
520                         /*
521                          * We ignore any unknown names.
522                          */
523                         tok = lwres_strsep(&order, ":");
524                         if (strcasecmp(tok, "inet6") == 0) {
525                                 if ((found & FOUND_IPV6) == 0)
526                                         *net_order++ = add_ipv6;
527                                 found |= FOUND_IPV6;
528                         } else if (strcasecmp(tok, "inet") == 0 ||
529                             strcasecmp(tok, "inet4") == 0) {
530                                 if ((found & FOUND_IPV4) == 0)
531                                         *net_order++ = add_ipv4;
532                                 found |= FOUND_IPV4;
533                         }
534                 }
535
536                 /*
537                  * Add in anything that we didn't find.
538                  */
539                 if ((found & FOUND_IPV4) == 0)
540                         *net_order++ = add_ipv4;
541                 if ((found & FOUND_IPV6) == 0)
542                         *net_order++ = add_ipv6;
543         }
544         *net_order = NULL;
545         return;
546 }
547
548 static char v4_loop[4] = { 127, 0, 0, 1 };
549
550 /*
551  * The test against 0 is there to keep the Solaris compiler
552  * from complaining about "end-of-loop code not reached".
553  */
554 #define SETERROR(code) \
555         do { result = (code);                   \
556                 if (result != 0) goto cleanup;  \
557         } while (0)
558
559 static int
560 add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
561         int socktype, int port)
562 {
563         struct addrinfo *ai;
564         lwres_context_t *lwrctx = NULL;
565         lwres_gabnresponse_t *by = NULL;
566         lwres_addr_t *addr;
567         lwres_result_t lwres;
568         int result = 0;
569
570         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
571         if (lwres != LWRES_R_SUCCESS)
572                 SETERROR(EAI_FAIL);
573         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
574         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
575                 ai = ai_clone(*aip, AF_INET);
576                 if (ai == NULL) {
577                         lwres_freeaddrinfo(*aip);
578                         SETERROR(EAI_MEMORY);
579                 }
580
581                 *aip = ai;
582                 ai->ai_socktype = socktype;
583                 SIN(ai->ai_addr)->sin_port = port;
584                 memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
585         } else {
586                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
587                                              LWRES_ADDRTYPE_V4, &by);
588                 if (lwres != LWRES_R_SUCCESS) {
589                         if (lwres == LWRES_R_NOTFOUND)
590                                 goto cleanup;
591                         else
592                                 SETERROR(EAI_FAIL);
593                 }
594                 addr = LWRES_LIST_HEAD(by->addrs);
595                 while (addr != NULL) {
596                         ai = ai_clone(*aip, AF_INET);
597                         if (ai == NULL) {
598                                 lwres_freeaddrinfo(*aip);
599                                 SETERROR(EAI_MEMORY);
600                         }
601                         *aip = ai;
602                         ai->ai_socktype = socktype;
603                         SIN(ai->ai_addr)->sin_port = port;
604                         memcpy(&SIN(ai->ai_addr)->sin_addr,
605                                addr->address, 4);
606                         if (flags & AI_CANONNAME) {
607                                 ai->ai_canonname = strdup(by->realname);
608                                 if (ai->ai_canonname == NULL)
609                                         SETERROR(EAI_MEMORY);
610                         }
611                         addr = LWRES_LIST_NEXT(addr, link);
612                 }
613         }
614  cleanup:
615         if (by != NULL)
616                 lwres_gabnresponse_free(lwrctx, &by);
617         if (lwrctx != NULL) {
618                 lwres_conf_clear(lwrctx);
619                 lwres_context_destroy(&lwrctx);
620         }
621         return (result);
622 }
623
624 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
625
626 static int
627 add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
628          int socktype, int port)
629 {
630         struct addrinfo *ai;
631         lwres_context_t *lwrctx = NULL;
632         lwres_gabnresponse_t *by = NULL;
633         lwres_addr_t *addr;
634         lwres_result_t lwres;
635         int result = 0;
636
637         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
638         if (lwres != LWRES_R_SUCCESS)
639                 SETERROR(EAI_FAIL);
640         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
641
642         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
643                 ai = ai_clone(*aip, AF_INET6);
644                 if (ai == NULL) {
645                         lwres_freeaddrinfo(*aip);
646                         SETERROR(EAI_MEMORY);
647                 }
648
649                 *aip = ai;
650                 ai->ai_socktype = socktype;
651                 SIN6(ai->ai_addr)->sin6_port = port;
652                 memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
653         } else {
654                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
655                                              LWRES_ADDRTYPE_V6, &by);
656                 if (lwres != LWRES_R_SUCCESS) {
657                         if (lwres == LWRES_R_NOTFOUND)
658                                 goto cleanup;
659                         else
660                                 SETERROR(EAI_FAIL);
661                 }
662                 addr = LWRES_LIST_HEAD(by->addrs);
663                 while (addr != NULL) {
664                         ai = ai_clone(*aip, AF_INET6);
665                         if (ai == NULL) {
666                                 lwres_freeaddrinfo(*aip);
667                                 SETERROR(EAI_MEMORY);
668                         }
669                         *aip = ai;
670                         ai->ai_socktype = socktype;
671                         SIN6(ai->ai_addr)->sin6_port = port;
672                         memcpy(&SIN6(ai->ai_addr)->sin6_addr,
673                                addr->address, 16);
674                         if (flags & AI_CANONNAME) {
675                                 ai->ai_canonname = strdup(by->realname);
676                                 if (ai->ai_canonname == NULL)
677                                         SETERROR(EAI_MEMORY);
678                         }
679                         addr = LWRES_LIST_NEXT(addr, link);
680                 }
681         }
682  cleanup:
683         if (by != NULL)
684                 lwres_gabnresponse_free(lwrctx, &by);
685         if (lwrctx != NULL) {
686                 lwres_conf_clear(lwrctx);
687                 lwres_context_destroy(&lwrctx);
688         }
689         return (result);
690 }
691
692 /*% Free address info. */
693 void
694 lwres_freeaddrinfo(struct addrinfo *ai) {
695         struct addrinfo *ai_next;
696
697         while (ai != NULL) {
698                 ai_next = ai->ai_next;
699                 if (ai->ai_addr != NULL)
700                         free(ai->ai_addr);
701                 if (ai->ai_canonname)
702                         free(ai->ai_canonname);
703                 free(ai);
704                 ai = ai_next;
705         }
706 }
707
708 #ifdef AF_LOCAL
709 static int
710 get_local(const char *name, int socktype, struct addrinfo **res) {
711         struct addrinfo *ai;
712         struct sockaddr_un *slocal;
713
714         if (socktype == 0)
715                 return (EAI_SOCKTYPE);
716
717         ai = ai_alloc(AF_LOCAL, sizeof(*slocal));
718         if (ai == NULL)
719                 return (EAI_MEMORY);
720
721         slocal = SLOCAL(ai->ai_addr);
722         strncpy(slocal->sun_path, name, sizeof(slocal->sun_path));
723
724         ai->ai_socktype = socktype;
725         /*
726          * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
727          * and ai->ai_next were initialized to zero.
728          */
729
730         *res = ai;
731         return (0);
732 }
733 #endif
734
735 /*!
736  * Allocate an addrinfo structure, and a sockaddr structure
737  * of the specificed length.  We initialize:
738  *      ai_addrlen
739  *      ai_family
740  *      ai_addr
741  *      ai_addr->sa_family
742  *      ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
743  * and everything else is initialized to zero.
744  */
745 static struct addrinfo *
746 ai_alloc(int family, int addrlen) {
747         struct addrinfo *ai;
748
749         ai = (struct addrinfo *)calloc(1, sizeof(*ai));
750         if (ai == NULL)
751                 return (NULL);
752
753         ai->ai_addr = SA(calloc(1, addrlen));
754         if (ai->ai_addr == NULL) {
755                 free(ai);
756                 return (NULL);
757         }
758         ai->ai_addrlen = addrlen;
759         ai->ai_family = family;
760         ai->ai_addr->sa_family = family;
761 #ifdef LWRES_PLATFORM_HAVESALEN
762         ai->ai_addr->sa_len = addrlen;
763 #endif
764         return (ai);
765 }
766
767 static struct addrinfo *
768 ai_clone(struct addrinfo *oai, int family) {
769         struct addrinfo *ai;
770
771         ai = ai_alloc(family, ((family == AF_INET6) ?
772             sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
773
774         if (ai == NULL) {
775                 lwres_freeaddrinfo(oai);
776                 return (NULL);
777         }
778         if (oai == NULL)
779                 return (ai);
780
781         ai->ai_flags = oai->ai_flags;
782         ai->ai_socktype = oai->ai_socktype;
783         ai->ai_protocol = oai->ai_protocol;
784         ai->ai_canonname = NULL;
785         ai->ai_next = oai;
786         return (ai);
787 }
788
789 static struct addrinfo *
790 ai_reverse(struct addrinfo *oai) {
791         struct addrinfo *nai, *tai;
792
793         nai = NULL;
794
795         while (oai != NULL) {
796                 /*
797                  * Grab one off the old list.
798                  */
799                 tai = oai;
800                 oai = oai->ai_next;
801                 /*
802                  * Put it on the front of the new list.
803                  */
804                 tai->ai_next = nai;
805                 nai = tai;
806         }
807         return (nai);
808 }