fake_addrinfo.c (5762B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 25 #include "curl_setup.h" 26 #include "fake_addrinfo.h" 27 28 #ifdef USE_FAKE_GETADDRINFO 29 30 #include <string.h> 31 #include <stdlib.h> 32 #include <ares.h> 33 34 /* The last 3 #include files should be in this order */ 35 #include "curl_printf.h" 36 #include "curl_memory.h" 37 #include "memdebug.h" 38 39 void r_freeaddrinfo(struct addrinfo *cahead) 40 { 41 struct addrinfo *canext; 42 struct addrinfo *ca; 43 44 for(ca = cahead; ca; ca = canext) { 45 canext = ca->ai_next; 46 free(ca); 47 } 48 } 49 50 struct context { 51 struct ares_addrinfo *result; 52 }; 53 54 static void async_addrinfo_cb(void *userp, int status, int timeouts, 55 struct ares_addrinfo *result) 56 { 57 struct context *ctx = (struct context *)userp; 58 (void)timeouts; 59 if(ARES_SUCCESS == status) { 60 ctx->result = result; 61 } 62 } 63 64 /* convert the c-ares version into the "native" version */ 65 static struct addrinfo *mk_getaddrinfo(const struct ares_addrinfo *aihead) 66 { 67 const struct ares_addrinfo_node *ai; 68 struct addrinfo *ca; 69 struct addrinfo *cafirst = NULL; 70 struct addrinfo *calast = NULL; 71 const char *name = aihead->name; 72 73 /* traverse the addrinfo list */ 74 for(ai = aihead->nodes; ai != NULL; ai = ai->ai_next) { 75 size_t ss_size; 76 size_t namelen = name ? strlen(name) + 1 : 0; 77 /* ignore elements with unsupported address family, */ 78 /* settle family-specific sockaddr structure size. */ 79 if(ai->ai_family == AF_INET) 80 ss_size = sizeof(struct sockaddr_in); 81 else if(ai->ai_family == AF_INET6) 82 ss_size = sizeof(struct sockaddr_in6); 83 else 84 continue; 85 86 /* ignore elements without required address info */ 87 if(!ai->ai_addr || !(ai->ai_addrlen > 0)) 88 continue; 89 90 /* ignore elements with bogus address size */ 91 if((size_t)ai->ai_addrlen < ss_size) 92 continue; 93 94 ca = malloc(sizeof(struct addrinfo) + ss_size + namelen); 95 if(!ca) { 96 r_freeaddrinfo(cafirst); 97 return NULL; 98 } 99 100 /* copy each structure member individually, member ordering, */ 101 /* size, or padding might be different for each platform. */ 102 103 ca->ai_flags = ai->ai_flags; 104 ca->ai_family = ai->ai_family; 105 ca->ai_socktype = ai->ai_socktype; 106 ca->ai_protocol = ai->ai_protocol; 107 ca->ai_addrlen = (curl_socklen_t)ss_size; 108 ca->ai_addr = NULL; 109 ca->ai_canonname = NULL; 110 ca->ai_next = NULL; 111 112 ca->ai_addr = (void *)((char *)ca + sizeof(struct addrinfo)); 113 memcpy(ca->ai_addr, ai->ai_addr, ss_size); 114 115 if(namelen) { 116 ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size); 117 memcpy(ca->ai_canonname, name, namelen); 118 119 /* the name is only pointed to by the first entry in the "real" 120 addrinfo chain, so stop now */ 121 name = NULL; 122 } 123 124 /* if the return list is empty, this becomes the first element */ 125 if(!cafirst) 126 cafirst = ca; 127 128 /* add this element last in the return list */ 129 if(calast) 130 calast->ai_next = ca; 131 calast = ca; 132 } 133 134 return cafirst; 135 } 136 137 /* 138 RETURN VALUE 139 140 getaddrinfo() returns 0 if it succeeds, or one of the following nonzero 141 error codes: 142 143 ... 144 */ 145 int r_getaddrinfo(const char *node, 146 const char *service, 147 const struct addrinfo *hints, 148 struct addrinfo **res) 149 { 150 int status; 151 struct context ctx; 152 struct ares_options options; 153 int optmask = 0; 154 struct ares_addrinfo_hints ahints; 155 ares_channel channel; 156 int rc = 0; 157 158 memset(&options, 0, sizeof(options)); 159 optmask |= ARES_OPT_EVENT_THREAD; 160 options.evsys = ARES_EVSYS_DEFAULT; 161 162 memset(&ahints, 0, sizeof(ahints)); 163 memset(&ctx, 0, sizeof(ctx)); 164 165 if(hints) { 166 ahints.ai_flags = hints->ai_flags; 167 ahints.ai_family = hints->ai_family; 168 ahints.ai_socktype = hints->ai_socktype; 169 ahints.ai_protocol = hints->ai_protocol; 170 } 171 172 status = ares_init_options(&channel, &options, optmask); 173 if(status) 174 return EAI_MEMORY; /* major problem */ 175 176 else { 177 const char *env = getenv("CURL_DNS_SERVER"); 178 if(env) { 179 rc = ares_set_servers_ports_csv(channel, env); 180 if(rc) { 181 fprintf(stderr, "ares_set_servers_ports_csv failed: %d", rc); 182 /* Cleanup */ 183 ares_destroy(channel); 184 return EAI_MEMORY; /* we can't run */ 185 } 186 } 187 } 188 189 ares_getaddrinfo(channel, node, service, &ahints, 190 async_addrinfo_cb, &ctx); 191 192 /* Wait until no more requests are left to be processed */ 193 ares_queue_wait_empty(channel, -1); 194 195 if(ctx.result) { 196 /* convert the c-ares version */ 197 *res = mk_getaddrinfo(ctx.result); 198 /* free the old */ 199 ares_freeaddrinfo(ctx.result); 200 } 201 else 202 rc = EAI_NONAME; /* got nothing */ 203 204 /* Cleanup */ 205 ares_destroy(channel); 206 207 return rc; 208 } 209 210 #endif /* USE_FAKE_GETADDRINFO */