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