1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2012, 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 http://curl.haxx.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 ***************************************************************************/ 22 23#include "curl_setup.h" 24 25#include <curl/curl.h> 26 27#ifdef HAVE_NETINET_IN_H 28# include <netinet/in.h> 29#endif 30#ifdef HAVE_NETDB_H 31# include <netdb.h> 32#endif 33#ifdef HAVE_ARPA_INET_H 34# include <arpa/inet.h> 35#endif 36 37#ifdef __VMS 38# include <in.h> 39# include <inet.h> 40#endif 41 42#if defined(NETWARE) && defined(__NOVELL_LIBC__) 43# undef in_addr_t 44# define in_addr_t unsigned long 45#endif 46 47#include "curl_addrinfo.h" 48#include "inet_pton.h" 49#include "warnless.h" 50 51#define _MPRINTF_REPLACE /* use our functions only */ 52#include <curl/mprintf.h> 53 54#include "curl_memory.h" 55/* The last #include file should be: */ 56#include "memdebug.h" 57 58 59/* 60 * Curl_freeaddrinfo() 61 * 62 * This is used to free a linked list of Curl_addrinfo structs along 63 * with all its associated allocated storage. This function should be 64 * called once for each successful call to Curl_getaddrinfo_ex() or to 65 * any function call which actually allocates a Curl_addrinfo struct. 66 */ 67 68#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ 69 defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) 70 /* workaround icc 9.1 optimizer issue */ 71# define vqualifier volatile 72#else 73# define vqualifier 74#endif 75 76void 77Curl_freeaddrinfo(Curl_addrinfo *cahead) 78{ 79 Curl_addrinfo *vqualifier canext; 80 Curl_addrinfo *ca; 81 82 for(ca = cahead; ca != NULL; ca = canext) { 83 84 if(ca->ai_addr) 85 free(ca->ai_addr); 86 87 if(ca->ai_canonname) 88 free(ca->ai_canonname); 89 90 canext = ca->ai_next; 91 92 free(ca); 93 } 94} 95 96 97#ifdef HAVE_GETADDRINFO 98/* 99 * Curl_getaddrinfo_ex() 100 * 101 * This is a wrapper function around system's getaddrinfo(), with 102 * the only difference that instead of returning a linked list of 103 * addrinfo structs this one returns a linked list of Curl_addrinfo 104 * ones. The memory allocated by this function *MUST* be free'd with 105 * Curl_freeaddrinfo(). For each successful call to this function 106 * there must be an associated call later to Curl_freeaddrinfo(). 107 * 108 * There should be no single call to system's getaddrinfo() in the 109 * whole library, any such call should be 'routed' through this one. 110 */ 111 112int 113Curl_getaddrinfo_ex(const char *nodename, 114 const char *servname, 115 const struct addrinfo *hints, 116 Curl_addrinfo **result) 117{ 118 const struct addrinfo *ai; 119 struct addrinfo *aihead; 120 Curl_addrinfo *cafirst = NULL; 121 Curl_addrinfo *calast = NULL; 122 Curl_addrinfo *ca; 123 size_t ss_size; 124 int error; 125 126 *result = NULL; /* assume failure */ 127 128 error = getaddrinfo(nodename, servname, hints, &aihead); 129 if(error) 130 return error; 131 132 /* traverse the addrinfo list */ 133 134 for(ai = aihead; ai != NULL; ai = ai->ai_next) { 135 136 /* ignore elements with unsupported address family, */ 137 /* settle family-specific sockaddr structure size. */ 138 if(ai->ai_family == AF_INET) 139 ss_size = sizeof(struct sockaddr_in); 140#ifdef ENABLE_IPV6 141 else if(ai->ai_family == AF_INET6) 142 ss_size = sizeof(struct sockaddr_in6); 143#endif 144 else 145 continue; 146 147 /* ignore elements without required address info */ 148 if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0)) 149 continue; 150 151 /* ignore elements with bogus address size */ 152 if((size_t)ai->ai_addrlen < ss_size) 153 continue; 154 155 if((ca = malloc(sizeof(Curl_addrinfo))) == NULL) { 156 error = EAI_MEMORY; 157 break; 158 } 159 160 /* copy each structure member individually, member ordering, */ 161 /* size, or padding might be different for each platform. */ 162 163 ca->ai_flags = ai->ai_flags; 164 ca->ai_family = ai->ai_family; 165 ca->ai_socktype = ai->ai_socktype; 166 ca->ai_protocol = ai->ai_protocol; 167 ca->ai_addrlen = (curl_socklen_t)ss_size; 168 ca->ai_addr = NULL; 169 ca->ai_canonname = NULL; 170 ca->ai_next = NULL; 171 172 if((ca->ai_addr = malloc(ss_size)) == NULL) { 173 error = EAI_MEMORY; 174 free(ca); 175 break; 176 } 177 memcpy(ca->ai_addr, ai->ai_addr, ss_size); 178 179 if(ai->ai_canonname != NULL) { 180 if((ca->ai_canonname = strdup(ai->ai_canonname)) == NULL) { 181 error = EAI_MEMORY; 182 free(ca->ai_addr); 183 free(ca); 184 break; 185 } 186 } 187 188 /* if the return list is empty, this becomes the first element */ 189 if(!cafirst) 190 cafirst = ca; 191 192 /* add this element last in the return list */ 193 if(calast) 194 calast->ai_next = ca; 195 calast = ca; 196 197 } 198 199 /* destroy the addrinfo list */ 200 if(aihead) 201 freeaddrinfo(aihead); 202 203 /* if we failed, also destroy the Curl_addrinfo list */ 204 if(error) { 205 Curl_freeaddrinfo(cafirst); 206 cafirst = NULL; 207 } 208 else if(!cafirst) { 209#ifdef EAI_NONAME 210 /* rfc3493 conformant */ 211 error = EAI_NONAME; 212#else 213 /* rfc3493 obsoleted */ 214 error = EAI_NODATA; 215#endif 216#ifdef USE_WINSOCK 217 SET_SOCKERRNO(error); 218#endif 219 } 220 221 *result = cafirst; 222 223 /* This is not a CURLcode */ 224 return error; 225} 226#endif /* HAVE_GETADDRINFO */ 227 228 229/* 230 * Curl_he2ai() 231 * 232 * This function returns a pointer to the first element of a newly allocated 233 * Curl_addrinfo struct linked list filled with the data of a given hostent. 234 * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6 235 * stack, but usable also for IPv4, all hosts and environments. 236 * 237 * The memory allocated by this function *MUST* be free'd later on calling 238 * Curl_freeaddrinfo(). For each successful call to this function there 239 * must be an associated call later to Curl_freeaddrinfo(). 240 * 241 * Curl_addrinfo defined in "lib/curl_addrinfo.h" 242 * 243 * struct Curl_addrinfo { 244 * int ai_flags; 245 * int ai_family; 246 * int ai_socktype; 247 * int ai_protocol; 248 * curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo * 249 * char *ai_canonname; 250 * struct sockaddr *ai_addr; 251 * struct Curl_addrinfo *ai_next; 252 * }; 253 * typedef struct Curl_addrinfo Curl_addrinfo; 254 * 255 * hostent defined in <netdb.h> 256 * 257 * struct hostent { 258 * char *h_name; 259 * char **h_aliases; 260 * int h_addrtype; 261 * int h_length; 262 * char **h_addr_list; 263 * }; 264 * 265 * for backward compatibility: 266 * 267 * #define h_addr h_addr_list[0] 268 */ 269 270Curl_addrinfo * 271Curl_he2ai(const struct hostent *he, int port) 272{ 273 Curl_addrinfo *ai; 274 Curl_addrinfo *prevai = NULL; 275 Curl_addrinfo *firstai = NULL; 276 struct sockaddr_in *addr; 277#ifdef ENABLE_IPV6 278 struct sockaddr_in6 *addr6; 279#endif 280 CURLcode result = CURLE_OK; 281 int i; 282 char *curr; 283 284 if(!he) 285 /* no input == no output! */ 286 return NULL; 287 288 DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL)); 289 290 for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) { 291 292 size_t ss_size; 293#ifdef ENABLE_IPV6 294 if(he->h_addrtype == AF_INET6) 295 ss_size = sizeof (struct sockaddr_in6); 296 else 297#endif 298 ss_size = sizeof (struct sockaddr_in); 299 300 if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) { 301 result = CURLE_OUT_OF_MEMORY; 302 break; 303 } 304 if((ai->ai_canonname = strdup(he->h_name)) == NULL) { 305 result = CURLE_OUT_OF_MEMORY; 306 free(ai); 307 break; 308 } 309 if((ai->ai_addr = calloc(1, ss_size)) == NULL) { 310 result = CURLE_OUT_OF_MEMORY; 311 free(ai->ai_canonname); 312 free(ai); 313 break; 314 } 315 316 if(!firstai) 317 /* store the pointer we want to return from this function */ 318 firstai = ai; 319 320 if(prevai) 321 /* make the previous entry point to this */ 322 prevai->ai_next = ai; 323 324 ai->ai_family = he->h_addrtype; 325 326 /* we return all names as STREAM, so when using this address for TFTP 327 the type must be ignored and conn->socktype be used instead! */ 328 ai->ai_socktype = SOCK_STREAM; 329 330 ai->ai_addrlen = (curl_socklen_t)ss_size; 331 332 /* leave the rest of the struct filled with zero */ 333 334 switch (ai->ai_family) { 335 case AF_INET: 336 addr = (void *)ai->ai_addr; /* storage area for this info */ 337 338 memcpy(&addr->sin_addr, curr, sizeof(struct in_addr)); 339 addr->sin_family = (unsigned short)(he->h_addrtype); 340 addr->sin_port = htons((unsigned short)port); 341 break; 342 343#ifdef ENABLE_IPV6 344 case AF_INET6: 345 addr6 = (void *)ai->ai_addr; /* storage area for this info */ 346 347 memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr)); 348 addr6->sin6_family = (unsigned short)(he->h_addrtype); 349 addr6->sin6_port = htons((unsigned short)port); 350 break; 351#endif 352 } 353 354 prevai = ai; 355 } 356 357 if(result != CURLE_OK) { 358 Curl_freeaddrinfo(firstai); 359 firstai = NULL; 360 } 361 362 return firstai; 363} 364 365 366struct namebuff { 367 struct hostent hostentry; 368 union { 369 struct in_addr ina4; 370#ifdef ENABLE_IPV6 371 struct in6_addr ina6; 372#endif 373 } addrentry; 374 char *h_addr_list[2]; 375}; 376 377 378/* 379 * Curl_ip2addr() 380 * 381 * This function takes an internet address, in binary form, as input parameter 382 * along with its address family and the string version of the address, and it 383 * returns a Curl_addrinfo chain filled in correctly with information for the 384 * given address/host 385 */ 386 387Curl_addrinfo * 388Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) 389{ 390 Curl_addrinfo *ai; 391 392#if defined(__VMS) && \ 393 defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) 394#pragma pointer_size save 395#pragma pointer_size short 396#pragma message disable PTRMISMATCH 397#endif 398 399 struct hostent *h; 400 struct namebuff *buf; 401 char *addrentry; 402 char *hoststr; 403 size_t addrsize; 404 405 DEBUGASSERT(inaddr && hostname); 406 407 buf = malloc(sizeof(struct namebuff)); 408 if(!buf) 409 return NULL; 410 411 hoststr = strdup(hostname); 412 if(!hoststr) { 413 free(buf); 414 return NULL; 415 } 416 417 switch(af) { 418 case AF_INET: 419 addrsize = sizeof(struct in_addr); 420 addrentry = (void *)&buf->addrentry.ina4; 421 memcpy(addrentry, inaddr, sizeof(struct in_addr)); 422 break; 423#ifdef ENABLE_IPV6 424 case AF_INET6: 425 addrsize = sizeof(struct in6_addr); 426 addrentry = (void *)&buf->addrentry.ina6; 427 memcpy(addrentry, inaddr, sizeof(struct in6_addr)); 428 break; 429#endif 430 default: 431 free(hoststr); 432 free(buf); 433 return NULL; 434 } 435 436 h = &buf->hostentry; 437 h->h_name = hoststr; 438 h->h_aliases = NULL; 439 h->h_addrtype = (short)af; 440 h->h_length = (short)addrsize; 441 h->h_addr_list = &buf->h_addr_list[0]; 442 h->h_addr_list[0] = addrentry; 443 h->h_addr_list[1] = NULL; /* terminate list of entries */ 444 445#if defined(__VMS) && \ 446 defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) 447#pragma pointer_size restore 448#pragma message enable PTRMISMATCH 449#endif 450 451 ai = Curl_he2ai(h, port); 452 453 free(hoststr); 454 free(buf); 455 456 return ai; 457} 458 459/* 460 * Given an IPv4 or IPv6 dotted string address, this converts it to a proper 461 * allocated Curl_addrinfo struct and returns it. 462 */ 463Curl_addrinfo *Curl_str2addr(char *address, int port) 464{ 465 struct in_addr in; 466 if(Curl_inet_pton(AF_INET, address, &in) > 0) 467 /* This is a dotted IP address 123.123.123.123-style */ 468 return Curl_ip2addr(AF_INET, &in, address, port); 469#ifdef ENABLE_IPV6 470 else { 471 struct in6_addr in6; 472 if(Curl_inet_pton(AF_INET6, address, &in6) > 0) 473 /* This is a dotted IPv6 address ::1-style */ 474 return Curl_ip2addr(AF_INET6, &in6, address, port); 475 } 476#endif 477 return NULL; /* bad input format */ 478} 479 480#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) 481/* 482 * curl_dofreeaddrinfo() 483 * 484 * This is strictly for memory tracing and are using the same style as the 485 * family otherwise present in memdebug.c. I put these ones here since they 486 * require a bunch of structs I didn't want to include in memdebug.c 487 */ 488 489void 490curl_dofreeaddrinfo(struct addrinfo *freethis, 491 int line, const char *source) 492{ 493 (freeaddrinfo)(freethis); 494 curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n", 495 source, line, (void *)freethis); 496} 497#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */ 498 499 500#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) 501/* 502 * curl_dogetaddrinfo() 503 * 504 * This is strictly for memory tracing and are using the same style as the 505 * family otherwise present in memdebug.c. I put these ones here since they 506 * require a bunch of structs I didn't want to include in memdebug.c 507 */ 508 509int 510curl_dogetaddrinfo(const char *hostname, 511 const char *service, 512 const struct addrinfo *hints, 513 struct addrinfo **result, 514 int line, const char *source) 515{ 516 int res=(getaddrinfo)(hostname, service, hints, result); 517 if(0 == res) 518 /* success */ 519 curl_memlog("ADDR %s:%d getaddrinfo() = %p\n", 520 source, line, (void *)*result); 521 else 522 curl_memlog("ADDR %s:%d getaddrinfo() failed\n", 523 source, line); 524 return res; 525} 526#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ 527 528