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