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