fake_addrinfo.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. #include "fake_addrinfo.h"
  26. #ifdef USE_FAKE_GETADDRINFO
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <ares.h>
  30. /* The last 2 #include files should be in this order */
  31. #include "curl_memory.h"
  32. #include "memdebug.h"
  33. void r_freeaddrinfo(struct addrinfo *cahead)
  34. {
  35. struct addrinfo *canext;
  36. struct addrinfo *ca;
  37. for(ca = cahead; ca; ca = canext) {
  38. canext = ca->ai_next;
  39. free(ca);
  40. }
  41. }
  42. struct context {
  43. struct ares_addrinfo *result;
  44. };
  45. static void async_addrinfo_cb(void *userp, int status, int timeouts,
  46. struct ares_addrinfo *result)
  47. {
  48. struct context *ctx = (struct context *)userp;
  49. (void)timeouts;
  50. if(ARES_SUCCESS == status) {
  51. ctx->result = result;
  52. }
  53. }
  54. /* convert the c-ares version into the "native" version */
  55. static struct addrinfo *mk_getaddrinfo(const struct ares_addrinfo *aihead)
  56. {
  57. const struct ares_addrinfo_node *ai;
  58. struct addrinfo *ca;
  59. struct addrinfo *cafirst = NULL;
  60. struct addrinfo *calast = NULL;
  61. const char *name = aihead->name;
  62. /* traverse the addrinfo list */
  63. for(ai = aihead->nodes; ai != NULL; ai = ai->ai_next) {
  64. size_t ss_size;
  65. size_t namelen = name ? strlen(name) + 1 : 0;
  66. /* ignore elements with unsupported address family, */
  67. /* settle family-specific sockaddr structure size. */
  68. if(ai->ai_family == AF_INET)
  69. ss_size = sizeof(struct sockaddr_in);
  70. else if(ai->ai_family == AF_INET6)
  71. ss_size = sizeof(struct sockaddr_in6);
  72. else
  73. continue;
  74. /* ignore elements without required address info */
  75. if(!ai->ai_addr || !(ai->ai_addrlen > 0))
  76. continue;
  77. /* ignore elements with bogus address size */
  78. if((size_t)ai->ai_addrlen < ss_size)
  79. continue;
  80. ca = malloc(sizeof(struct addrinfo) + ss_size + namelen);
  81. if(!ca) {
  82. r_freeaddrinfo(cafirst);
  83. return NULL;
  84. }
  85. /* copy each structure member individually, member ordering, */
  86. /* size, or padding might be different for each platform. */
  87. ca->ai_flags = ai->ai_flags;
  88. ca->ai_family = ai->ai_family;
  89. ca->ai_socktype = ai->ai_socktype;
  90. ca->ai_protocol = ai->ai_protocol;
  91. ca->ai_addrlen = (curl_socklen_t)ss_size;
  92. ca->ai_addr = NULL;
  93. ca->ai_canonname = NULL;
  94. ca->ai_next = NULL;
  95. ca->ai_addr = (void *)((char *)ca + sizeof(struct addrinfo));
  96. memcpy(ca->ai_addr, ai->ai_addr, ss_size);
  97. if(namelen) {
  98. ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
  99. memcpy(ca->ai_canonname, name, namelen);
  100. /* the name is only pointed to by the first entry in the "real"
  101. addrinfo chain, so stop now */
  102. name = NULL;
  103. }
  104. /* if the return list is empty, this becomes the first element */
  105. if(!cafirst)
  106. cafirst = ca;
  107. /* add this element last in the return list */
  108. if(calast)
  109. calast->ai_next = ca;
  110. calast = ca;
  111. }
  112. return cafirst;
  113. }
  114. /*
  115. RETURN VALUE
  116. getaddrinfo() returns 0 if it succeeds, or one of the following nonzero
  117. error codes:
  118. ...
  119. */
  120. int r_getaddrinfo(const char *node,
  121. const char *service,
  122. const struct addrinfo *hints,
  123. struct addrinfo **res)
  124. {
  125. int status;
  126. struct context ctx;
  127. struct ares_options options;
  128. int optmask = 0;
  129. struct ares_addrinfo_hints ahints;
  130. ares_channel channel;
  131. int rc = 0;
  132. memset(&options, 0, sizeof(options));
  133. optmask |= ARES_OPT_EVENT_THREAD;
  134. options.evsys = ARES_EVSYS_DEFAULT;
  135. memset(&ahints, 0, sizeof(ahints));
  136. memset(&ctx, 0, sizeof(ctx));
  137. if(hints) {
  138. ahints.ai_flags = hints->ai_flags;
  139. ahints.ai_family = hints->ai_family;
  140. ahints.ai_socktype = hints->ai_socktype;
  141. ahints.ai_protocol = hints->ai_protocol;
  142. }
  143. status = ares_init_options(&channel, &options, optmask);
  144. if(status)
  145. return EAI_MEMORY; /* major problem */
  146. else {
  147. const char *env = getenv("CURL_DNS_SERVER");
  148. if(env) {
  149. rc = ares_set_servers_ports_csv(channel, env);
  150. if(rc) {
  151. curl_mfprintf(stderr, "ares_set_servers_ports_csv failed: %d", rc);
  152. /* Cleanup */
  153. ares_destroy(channel);
  154. return EAI_MEMORY; /* we can't run */
  155. }
  156. }
  157. }
  158. ares_getaddrinfo(channel, node, service, &ahints,
  159. async_addrinfo_cb, &ctx);
  160. /* Wait until no more requests are left to be processed */
  161. ares_queue_wait_empty(channel, -1);
  162. if(ctx.result) {
  163. /* convert the c-ares version */
  164. *res = mk_getaddrinfo(ctx.result);
  165. /* free the old */
  166. ares_freeaddrinfo(ctx.result);
  167. }
  168. else
  169. rc = EAI_NONAME; /* got nothing */
  170. /* Cleanup */
  171. ares_destroy(channel);
  172. return rc;
  173. }
  174. #endif /* USE_FAKE_GETADDRINFO */