/contrib/bind9/lib/lwres/getaddrinfo.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 808 lines · 540 code · 67 blank · 201 comment · 216 complexity · 2d44a84cd38b5979b08d83709f69b608 MD5 · raw file

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