]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/lwres/getaddrinfo.c
This commit was generated by cvs2svn to compensate for changes in r172665,
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / lwres / getaddrinfo.c
1 /*
2  * Copyright (C) 2004-2006  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 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.43.18.6 2006/11/14 01:07:28 marka 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 <string.h>
137 #include <errno.h>
138
139 #include <lwres/lwres.h>
140 #include <lwres/net.h>
141 #include <lwres/netdb.h>
142 #include <lwres/stdlib.h>
143
144 #define SA(addr)        ((struct sockaddr *)(addr))
145 #define SIN(addr)       ((struct sockaddr_in *)(addr))
146 #define SIN6(addr)      ((struct sockaddr_in6 *)(addr))
147 #define SUN(addr)       ((struct sockaddr_un *)(addr))
148
149 /*! \struct addrinfo
150  */
151 static struct addrinfo
152         *ai_reverse(struct addrinfo *oai),
153         *ai_clone(struct addrinfo *oai, int family),
154         *ai_alloc(int family, int addrlen);
155 #ifdef AF_LOCAL
156 static int get_local(const char *name, int socktype, struct addrinfo **res);
157 #endif
158
159 static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
160     int socktype, int port);
161 static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
162     int socktype, int port);
163 static void set_order(int, int (**)(const char *, int, struct addrinfo **,
164          int, int));
165
166 #define FOUND_IPV4      0x1
167 #define FOUND_IPV6      0x2
168 #define FOUND_MAX       2
169
170 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
171 /*% Get a list of IP addresses and port numbers for host hostname and service servname. */
172 int
173 lwres_getaddrinfo(const char *hostname, const char *servname,
174         const struct addrinfo *hints, struct addrinfo **res)
175 {
176         struct servent *sp;
177         const char *proto;
178         int family, socktype, flags, protocol;
179         struct addrinfo *ai, *ai_list;
180         int port, err, i;
181         int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
182                  int, int);
183
184         if (hostname == NULL && servname == NULL)
185                 return (EAI_NONAME);
186
187         proto = NULL;
188         if (hints != NULL) {
189                 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
190                         return (EAI_BADFLAGS);
191                 if (hints->ai_addrlen || hints->ai_canonname ||
192                     hints->ai_addr || hints->ai_next) {
193                         errno = EINVAL;
194                         return (EAI_SYSTEM);
195                 }
196                 family = hints->ai_family;
197                 socktype = hints->ai_socktype;
198                 protocol = hints->ai_protocol;
199                 flags = hints->ai_flags;
200                 switch (family) {
201                 case AF_UNSPEC:
202                         switch (hints->ai_socktype) {
203                         case SOCK_STREAM:
204                                 proto = "tcp";
205                                 break;
206                         case SOCK_DGRAM:
207                                 proto = "udp";
208                                 break;
209                         }
210                         break;
211                 case AF_INET:
212                 case AF_INET6:
213                         switch (hints->ai_socktype) {
214                         case 0:
215                                 break;
216                         case SOCK_STREAM:
217                                 proto = "tcp";
218                                 break;
219                         case SOCK_DGRAM:
220                                 proto = "udp";
221                                 break;
222                         case SOCK_RAW:
223                                 break;
224                         default:
225                                 return (EAI_SOCKTYPE);
226                         }
227                         break;
228 #ifdef  AF_LOCAL
229                 case AF_LOCAL:
230                         switch (hints->ai_socktype) {
231                         case 0:
232                                 break;
233                         case SOCK_STREAM:
234                                 break;
235                         case SOCK_DGRAM:
236                                 break;
237                         default:
238                                 return (EAI_SOCKTYPE);
239                         }
240                         break;
241 #endif
242                 default:
243                         return (EAI_FAMILY);
244                 }
245         } else {
246                 protocol = 0;
247                 family = 0;
248                 socktype = 0;
249                 flags = 0;
250         }
251
252 #ifdef  AF_LOCAL
253         /*!
254          * First, deal with AF_LOCAL.  If the family was not set,
255          * then assume AF_LOCAL if the first character of the
256          * hostname/servname is '/'.
257          */
258
259         if (hostname != NULL &&
260             (family == AF_LOCAL || (family == 0 && *hostname == '/')))
261                 return (get_local(hostname, socktype, res));
262
263         if (servname != NULL &&
264             (family == AF_LOCAL || (family == 0 && *servname == '/')))
265                 return (get_local(servname, socktype, res));
266 #endif
267
268         /*
269          * Ok, only AF_INET and AF_INET6 left.
270          */
271         ai_list = NULL;
272
273         /*
274          * First, look up the service name (port) if it was
275          * requested.  If the socket type wasn't specified, then
276          * try and figure it out.
277          */
278         if (servname != NULL) {
279                 char *e;
280
281                 port = strtol(servname, &e, 10);
282                 if (*e == '\0') {
283                         if (socktype == 0)
284                                 return (EAI_SOCKTYPE);
285                         if (port < 0 || port > 65535)
286                                 return (EAI_SERVICE);
287                         port = htons((unsigned short) port);
288                 } else {
289                         sp = getservbyname(servname, proto);
290                         if (sp == NULL)
291                                 return (EAI_SERVICE);
292                         port = sp->s_port;
293                         if (socktype == 0) {
294                                 if (strcmp(sp->s_proto, "tcp") == 0)
295                                         socktype = SOCK_STREAM;
296                                 else if (strcmp(sp->s_proto, "udp") == 0)
297                                         socktype = SOCK_DGRAM;
298                         }
299                 }
300         } else
301                 port = 0;
302
303         /*
304          * Next, deal with just a service name, and no hostname.
305          * (we verified that one of them was non-null up above).
306          */
307         if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
308                 if (family == AF_INET || family == 0) {
309                         ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
310                         if (ai == NULL)
311                                 return (EAI_MEMORY);
312                         ai->ai_socktype = socktype;
313                         ai->ai_protocol = protocol;
314                         SIN(ai->ai_addr)->sin_port = port;
315                         ai->ai_next = ai_list;
316                         ai_list = ai;
317                 }
318
319                 if (family == AF_INET6 || family == 0) {
320                         ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
321                         if (ai == NULL) {
322                                 lwres_freeaddrinfo(ai_list);
323                                 return (EAI_MEMORY);
324                         }
325                         ai->ai_socktype = socktype;
326                         ai->ai_protocol = protocol;
327                         SIN6(ai->ai_addr)->sin6_port = port;
328                         ai->ai_next = ai_list;
329                         ai_list = ai;
330                 }
331
332                 *res = ai_list;
333                 return (0);
334         }
335
336         /*
337          * If the family isn't specified or AI_NUMERICHOST specified,
338          * check first to see if it is a numeric address.
339          * Though the gethostbyname2() routine
340          * will recognize numeric addresses, it will only recognize
341          * the format that it is being called for.  Thus, a numeric
342          * AF_INET address will be treated by the AF_INET6 call as
343          * a domain name, and vice versa.  Checking for both numerics
344          * here avoids that.
345          */
346         if (hostname != NULL &&
347             (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
348                 char abuf[sizeof(struct in6_addr)];
349                 char nbuf[NI_MAXHOST];
350                 int addrsize, addroff;
351 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
352                 char *p, *ep;
353                 char ntmp[NI_MAXHOST];
354                 lwres_uint32_t scopeid;
355 #endif
356
357 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
358                 /*
359                  * Scope identifier portion.
360                  */
361                 ntmp[0] = '\0';
362                 if (strchr(hostname, '%') != NULL) {
363                         strncpy(ntmp, hostname, sizeof(ntmp) - 1);
364                         ntmp[sizeof(ntmp) - 1] = '\0';
365                         p = strchr(ntmp, '%');
366                         ep = NULL;
367
368                         /*
369                          * Vendors may want to support non-numeric
370                          * scopeid around here.
371                          */
372
373                         if (p != NULL)
374                                 scopeid = (lwres_uint32_t)strtoul(p + 1,
375                                                                   &ep, 10);
376                         if (p != NULL && ep != NULL && ep[0] == '\0')
377                                 *p = '\0';
378                         else {
379                                 ntmp[0] = '\0';
380                                 scopeid = 0;
381                         }
382                 } else
383                         scopeid = 0;
384 #endif
385
386                if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
387                    == 1)
388                {
389                         if (family == AF_INET6) {
390                                 /*
391                                  * Convert to a V4 mapped address.
392                                  */
393                                 struct in6_addr *a6 = (struct in6_addr *)abuf;
394                                 memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
395                                 memset(&a6->s6_addr[10], 0xff, 2);
396                                 memset(&a6->s6_addr[0], 0, 10);
397                                 goto inet6_addr;
398                         }
399                         addrsize = sizeof(struct in_addr);
400                         addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
401                         family = AF_INET;
402                         goto common;
403 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
404                 } else if (ntmp[0] != '\0' &&
405                            lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
406                 {
407                         if (family && family != AF_INET6)
408                                 return (EAI_NONAME);
409                         addrsize = sizeof(struct in6_addr);
410                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
411                         family = AF_INET6;
412                         goto common;
413 #endif
414                 } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
415                         if (family != 0 && family != AF_INET6)
416                                 return (EAI_NONAME);
417                 inet6_addr:
418                         addrsize = sizeof(struct in6_addr);
419                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
420                         family = AF_INET6;
421
422                 common:
423                         ai = ai_clone(ai_list, family);
424                         if (ai == NULL)
425                                 return (EAI_MEMORY);
426                         ai_list = ai;
427                         ai->ai_socktype = socktype;
428                         SIN(ai->ai_addr)->sin_port = port;
429                         memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
430                         if (flags & AI_CANONNAME) {
431 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
432                                 if (ai->ai_family == AF_INET6)
433                                         SIN6(ai->ai_addr)->sin6_scope_id =
434                                                                         scopeid;
435 #endif
436                                 if (lwres_getnameinfo(ai->ai_addr,
437                                     ai->ai_addrlen, nbuf, sizeof(nbuf),
438                                                       NULL, 0,
439                                                       NI_NUMERICHOST) == 0) {
440                                         ai->ai_canonname = strdup(nbuf);
441                                         if (ai->ai_canonname == NULL) {
442                                                 lwres_freeaddrinfo(ai_list);
443                                                 return (EAI_MEMORY);
444                                         }
445                                 } else {
446                                         /* XXX raise error? */
447                                         ai->ai_canonname = NULL;
448                                 }
449                         }
450                         goto done;
451                 } else if ((flags & AI_NUMERICHOST) != 0) {
452                         return (EAI_NONAME);
453                 }
454         }
455
456         set_order(family, net_order);
457         for (i = 0; i < FOUND_MAX; i++) {
458                 if (net_order[i] == NULL)
459                         break;
460                 err = (net_order[i])(hostname, flags, &ai_list,
461                                      socktype, port);
462                 if (err != 0)
463                         return (err);
464         }
465
466         if (ai_list == NULL)
467                 return (EAI_NODATA);
468
469 done:
470         ai_list = ai_reverse(ai_list);
471
472         *res = ai_list;
473         return (0);
474 }
475
476 static char *
477 lwres_strsep(char **stringp, const char *delim) {
478         char *string = *stringp;
479         char *s;
480         const char *d;
481         char sc, dc;
482
483         if (string == NULL)
484                 return (NULL);
485
486         for (s = string; *s != '\0'; s++) {
487                 sc = *s;
488                 for (d = delim; (dc = *d) != '\0'; d++)
489                         if (sc == dc) {
490                                 *s++ = '\0';
491                                 *stringp = s;
492                                 return (string);
493                         }
494         }
495         *stringp = NULL;
496         return (string);
497 }
498
499 static void
500 set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
501                                         int, int))
502 {
503         char *order, *tok;
504         int found;
505
506         if (family) {
507                 switch (family) {
508                 case AF_INET:
509                         *net_order++ = add_ipv4;
510                         break;
511                 case AF_INET6:
512                         *net_order++ = add_ipv6;
513                         break;
514                 }
515         } else {
516                 order = getenv("NET_ORDER");
517                 found = 0;
518                 while (order != NULL) {
519                         /*
520                          * We ignore any unknown names.
521                          */
522                         tok = lwres_strsep(&order, ":");
523                         if (strcasecmp(tok, "inet6") == 0) {
524                                 if ((found & FOUND_IPV6) == 0)
525                                         *net_order++ = add_ipv6;
526                                 found |= FOUND_IPV6;
527                         } else if (strcasecmp(tok, "inet") == 0 ||
528                             strcasecmp(tok, "inet4") == 0) {
529                                 if ((found & FOUND_IPV4) == 0)
530                                         *net_order++ = add_ipv4;
531                                 found |= FOUND_IPV4;
532                         }
533                 }
534
535                 /*
536                  * Add in anything that we didn't find.
537                  */
538                 if ((found & FOUND_IPV4) == 0)
539                         *net_order++ = add_ipv4;
540                 if ((found & FOUND_IPV6) == 0)
541                         *net_order++ = add_ipv6;
542         }
543         *net_order = NULL;
544         return;
545 }
546
547 static char v4_loop[4] = { 127, 0, 0, 1 };
548
549 /*
550  * The test against 0 is there to keep the Solaris compiler
551  * from complaining about "end-of-loop code not reached".
552  */
553 #define SETERROR(code) \
554         do { result = (code);                   \
555                 if (result != 0) goto cleanup;  \
556         } while (0)
557
558 static int
559 add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
560         int socktype, int port)
561 {
562         struct addrinfo *ai;
563         lwres_context_t *lwrctx = NULL;
564         lwres_gabnresponse_t *by = NULL;
565         lwres_addr_t *addr;
566         lwres_result_t lwres;
567         int result = 0;
568
569         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
570         if (lwres != LWRES_R_SUCCESS)
571                 SETERROR(EAI_FAIL);
572         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
573         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
574                 ai = ai_clone(*aip, AF_INET);
575                 if (ai == NULL) {
576                         lwres_freeaddrinfo(*aip);
577                         SETERROR(EAI_MEMORY);
578                 }
579
580                 *aip = ai;
581                 ai->ai_socktype = socktype;
582                 SIN(ai->ai_addr)->sin_port = port;
583                 memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
584         } else {
585                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
586                                              LWRES_ADDRTYPE_V4, &by);
587                 if (lwres != LWRES_R_SUCCESS) {
588                         if (lwres == LWRES_R_NOTFOUND)
589                                 goto cleanup;
590                         else
591                                 SETERROR(EAI_FAIL);
592                 }
593                 addr = LWRES_LIST_HEAD(by->addrs);
594                 while (addr != NULL) {
595                         ai = ai_clone(*aip, AF_INET);
596                         if (ai == NULL) {
597                                 lwres_freeaddrinfo(*aip);
598                                 SETERROR(EAI_MEMORY);
599                         }
600                         *aip = ai;
601                         ai->ai_socktype = socktype;
602                         SIN(ai->ai_addr)->sin_port = port;
603                         memcpy(&SIN(ai->ai_addr)->sin_addr,
604                                addr->address, 4);
605                         if (flags & AI_CANONNAME) {
606                                 ai->ai_canonname = strdup(by->realname);
607                                 if (ai->ai_canonname == NULL)
608                                         SETERROR(EAI_MEMORY);
609                         }
610                         addr = LWRES_LIST_NEXT(addr, link);
611                 }
612         }
613  cleanup:
614         if (by != NULL)
615                 lwres_gabnresponse_free(lwrctx, &by);
616         if (lwrctx != NULL) {
617                 lwres_conf_clear(lwrctx);
618                 lwres_context_destroy(&lwrctx);
619         }
620         return (result);
621 }
622
623 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
624
625 static int
626 add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
627          int socktype, int port)
628 {
629         struct addrinfo *ai;
630         lwres_context_t *lwrctx = NULL;
631         lwres_gabnresponse_t *by = NULL;
632         lwres_addr_t *addr;
633         lwres_result_t lwres;
634         int result = 0;
635
636         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
637         if (lwres != LWRES_R_SUCCESS)
638                 SETERROR(EAI_FAIL);
639         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
640
641         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
642                 ai = ai_clone(*aip, AF_INET6);
643                 if (ai == NULL) {
644                         lwres_freeaddrinfo(*aip);
645                         SETERROR(EAI_MEMORY);
646                 }
647
648                 *aip = ai;
649                 ai->ai_socktype = socktype;
650                 SIN6(ai->ai_addr)->sin6_port = port;
651                 memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
652         } else {
653                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
654                                              LWRES_ADDRTYPE_V6, &by);
655                 if (lwres != LWRES_R_SUCCESS) {
656                         if (lwres == LWRES_R_NOTFOUND)
657                                 goto cleanup;
658                         else
659                                 SETERROR(EAI_FAIL);
660                 }
661                 addr = LWRES_LIST_HEAD(by->addrs);
662                 while (addr != NULL) {
663                         ai = ai_clone(*aip, AF_INET6);
664                         if (ai == NULL) {
665                                 lwres_freeaddrinfo(*aip);
666                                 SETERROR(EAI_MEMORY);
667                         }
668                         *aip = ai;
669                         ai->ai_socktype = socktype;
670                         SIN6(ai->ai_addr)->sin6_port = port;
671                         memcpy(&SIN6(ai->ai_addr)->sin6_addr,
672                                addr->address, 16);
673                         if (flags & AI_CANONNAME) {
674                                 ai->ai_canonname = strdup(by->realname);
675                                 if (ai->ai_canonname == NULL)
676                                         SETERROR(EAI_MEMORY);
677                         }
678                         addr = LWRES_LIST_NEXT(addr, link);
679                 }
680         }
681  cleanup:
682         if (by != NULL)
683                 lwres_gabnresponse_free(lwrctx, &by);
684         if (lwrctx != NULL) {
685                 lwres_conf_clear(lwrctx);
686                 lwres_context_destroy(&lwrctx);
687         }
688         return (result);
689 }
690
691 /*% Free address info. */
692 void
693 lwres_freeaddrinfo(struct addrinfo *ai) {
694         struct addrinfo *ai_next;
695
696         while (ai != NULL) {
697                 ai_next = ai->ai_next;
698                 if (ai->ai_addr != NULL)
699                         free(ai->ai_addr);
700                 if (ai->ai_canonname)
701                         free(ai->ai_canonname);
702                 free(ai);
703                 ai = ai_next;
704         }
705 }
706
707 #ifdef AF_LOCAL
708 static int
709 get_local(const char *name, int socktype, struct addrinfo **res) {
710         struct addrinfo *ai;
711         struct sockaddr_un *sun;
712
713         if (socktype == 0)
714                 return (EAI_SOCKTYPE);
715
716         ai = ai_alloc(AF_LOCAL, sizeof(*sun));
717         if (ai == NULL)
718                 return (EAI_MEMORY);
719
720         sun = SUN(ai->ai_addr);
721         strncpy(sun->sun_path, name, sizeof(sun->sun_path));
722
723         ai->ai_socktype = socktype;
724         /*
725          * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
726          * and ai->ai_next were initialized to zero.
727          */
728
729         *res = ai;
730         return (0);
731 }
732 #endif
733
734 /*!
735  * Allocate an addrinfo structure, and a sockaddr structure
736  * of the specificed length.  We initialize:
737  *      ai_addrlen
738  *      ai_family
739  *      ai_addr
740  *      ai_addr->sa_family
741  *      ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
742  * and everything else is initialized to zero.
743  */
744 static struct addrinfo *
745 ai_alloc(int family, int addrlen) {
746         struct addrinfo *ai;
747
748         ai = (struct addrinfo *)calloc(1, sizeof(*ai));
749         if (ai == NULL)
750                 return (NULL);
751
752         ai->ai_addr = SA(calloc(1, addrlen));
753         if (ai->ai_addr == NULL) {
754                 free(ai);
755                 return (NULL);
756         }
757         ai->ai_addrlen = addrlen;
758         ai->ai_family = family;
759         ai->ai_addr->sa_family = family;
760 #ifdef LWRES_PLATFORM_HAVESALEN
761         ai->ai_addr->sa_len = addrlen;
762 #endif
763         return (ai);
764 }
765
766 static struct addrinfo *
767 ai_clone(struct addrinfo *oai, int family) {
768         struct addrinfo *ai;
769
770         ai = ai_alloc(family, ((family == AF_INET6) ?
771             sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
772
773         if (ai == NULL) {
774                 lwres_freeaddrinfo(oai);
775                 return (NULL);
776         }
777         if (oai == NULL)
778                 return (ai);
779
780         ai->ai_flags = oai->ai_flags;
781         ai->ai_socktype = oai->ai_socktype;
782         ai->ai_protocol = oai->ai_protocol;
783         ai->ai_canonname = NULL;
784         ai->ai_next = oai;
785         return (ai);
786 }
787
788 static struct addrinfo *
789 ai_reverse(struct addrinfo *oai) {
790         struct addrinfo *nai, *tai;
791
792         nai = NULL;
793
794         while (oai != NULL) {
795                 /*
796                  * Grab one off the old list.
797                  */
798                 tai = oai;
799                 oai = oai->ai_next;
800                 /*
801                  * Put it on the front of the new list.
802                  */
803                 tai->ai_next = nai;
804                 nai = tai;
805         }
806         return (nai);
807 }