1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) 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.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_NETINET_IN6_H 31 # include <netinet/in6.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 #ifdef HAVE_SYS_UN_H 40 # include <sys/un.h> 41 #endif 42 43 #ifdef __VMS 44 # include <in.h> 45 # include <inet.h> 46 #endif 47 48 #if defined(NETWARE) && defined(__NOVELL_LIBC__) 49 # undef in_addr_t 50 # define in_addr_t unsigned long 51 #endif 52 53 #include <stddef.h> 54 55 #include "curl_addrinfo.h" 56 #include "inet_pton.h" 57 #include "warnless.h" 58 /* The last 3 #include files should be in this order */ 59 #include "curl_printf.h" 60 #include "curl_memory.h" 61 #include "memdebug.h" 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 80 void 81 Curl_freeaddrinfo(Curl_addrinfo *cahead) 82 { 83 Curl_addrinfo *vqualifier canext; 84 Curl_addrinfo *ca; 85 86 for(ca = cahead; ca != NULL; ca = canext) { 87 free(ca->ai_addr); 88 free(ca->ai_canonname); 89 canext = ca->ai_next; 90 91 free(ca); 92 } 93 } 94 95 96 #ifdef HAVE_GETADDRINFO 97 /* 98 * Curl_getaddrinfo_ex() 99 * 100 * This is a wrapper function around system's getaddrinfo(), with 101 * the only difference that instead of returning a linked list of 102 * addrinfo structs this one returns a linked list of Curl_addrinfo 103 * ones. The memory allocated by this function *MUST* be free'd with 104 * Curl_freeaddrinfo(). For each successful call to this function 105 * there must be an associated call later to Curl_freeaddrinfo(). 106 * 107 * There should be no single call to system's getaddrinfo() in the 108 * whole library, any such call should be 'routed' through this one. 109 */ 110 111 int 112 Curl_getaddrinfo_ex(const char *nodename, 113 const char *servname, 114 const struct addrinfo *hints, 115 Curl_addrinfo **result) 116 { 117 const struct addrinfo *ai; 118 struct addrinfo *aihead; 119 Curl_addrinfo *cafirst = NULL; 120 Curl_addrinfo *calast = NULL; 121 Curl_addrinfo *ca; 122 size_t ss_size; 123 int error; 124 125 *result = NULL; /* assume failure */ 126 127 error = getaddrinfo(nodename, servname, hints, &aihead); 128 if(error) 129 return error; 130 131 /* traverse the addrinfo list */ 132 133 for(ai = aihead; ai != NULL; ai = ai->ai_next) { 134 135 /* ignore elements with unsupported address family, */ 136 /* settle family-specific sockaddr structure size. */ 137 if(ai->ai_family == AF_INET) 138 ss_size = sizeof(struct sockaddr_in); 139 #ifdef ENABLE_IPV6 140 else if(ai->ai_family == AF_INET6) 141 ss_size = sizeof(struct sockaddr_in6); 142 #endif 143 else 144 continue; 145 146 /* ignore elements without required address info */ 147 if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0)) 148 continue; 149 150 /* ignore elements with bogus address size */ 151 if((size_t)ai->ai_addrlen < ss_size) 152 continue; 153 154 ca = malloc(sizeof(Curl_addrinfo)); 155 if(!ca) { 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 ca->ai_addr = malloc(ss_size); 173 if(!ca->ai_addr) { 174 error = EAI_MEMORY; 175 free(ca); 176 break; 177 } 178 memcpy(ca->ai_addr, ai->ai_addr, ss_size); 179 180 if(ai->ai_canonname != NULL) { 181 ca->ai_canonname = strdup(ai->ai_canonname); 182 if(!ca->ai_canonname) { 183 error = EAI_MEMORY; 184 free(ca->ai_addr); 185 free(ca); 186 break; 187 } 188 } 189 190 /* if the return list is empty, this becomes the first element */ 191 if(!cafirst) 192 cafirst = ca; 193 194 /* add this element last in the return list */ 195 if(calast) 196 calast->ai_next = ca; 197 calast = ca; 198 199 } 200 201 /* destroy the addrinfo list */ 202 if(aihead) 203 freeaddrinfo(aihead); 204 205 /* if we failed, also destroy the Curl_addrinfo list */ 206 if(error) { 207 Curl_freeaddrinfo(cafirst); 208 cafirst = NULL; 209 } 210 else if(!cafirst) { 211 #ifdef EAI_NONAME 212 /* rfc3493 conformant */ 213 error = EAI_NONAME; 214 #else 215 /* rfc3493 obsoleted */ 216 error = EAI_NODATA; 217 #endif 218 #ifdef USE_WINSOCK 219 SET_SOCKERRNO(error); 220 #endif 221 } 222 223 *result = cafirst; 224 225 /* This is not a CURLcode */ 226 return error; 227 } 228 #endif /* HAVE_GETADDRINFO */ 229 230 231 /* 232 * Curl_he2ai() 233 * 234 * This function returns a pointer to the first element of a newly allocated 235 * Curl_addrinfo struct linked list filled with the data of a given hostent. 236 * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6 237 * stack, but usable also for IPv4, all hosts and environments. 238 * 239 * The memory allocated by this function *MUST* be free'd later on calling 240 * Curl_freeaddrinfo(). For each successful call to this function there 241 * must be an associated call later to Curl_freeaddrinfo(). 242 * 243 * Curl_addrinfo defined in "lib/curl_addrinfo.h" 244 * 245 * struct Curl_addrinfo { 246 * int ai_flags; 247 * int ai_family; 248 * int ai_socktype; 249 * int ai_protocol; 250 * curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo * 251 * char *ai_canonname; 252 * struct sockaddr *ai_addr; 253 * struct Curl_addrinfo *ai_next; 254 * }; 255 * typedef struct Curl_addrinfo Curl_addrinfo; 256 * 257 * hostent defined in <netdb.h> 258 * 259 * struct hostent { 260 * char *h_name; 261 * char **h_aliases; 262 * int h_addrtype; 263 * int h_length; 264 * char **h_addr_list; 265 * }; 266 * 267 * for backward compatibility: 268 * 269 * #define h_addr h_addr_list[0] 270 */ 271 272 Curl_addrinfo * 273 Curl_he2ai(const struct hostent *he, int port) 274 { 275 Curl_addrinfo *ai; 276 Curl_addrinfo *prevai = NULL; 277 Curl_addrinfo *firstai = NULL; 278 struct sockaddr_in *addr; 279 #ifdef ENABLE_IPV6 280 struct sockaddr_in6 *addr6; 281 #endif 282 CURLcode result = CURLE_OK; 283 int i; 284 char *curr; 285 286 if(!he) 287 /* no input == no output! */ 288 return NULL; 289 290 DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL)); 291 292 for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { 293 294 size_t ss_size; 295 #ifdef ENABLE_IPV6 296 if(he->h_addrtype == AF_INET6) 297 ss_size = sizeof(struct sockaddr_in6); 298 else 299 #endif 300 ss_size = sizeof(struct sockaddr_in); 301 302 ai = calloc(1, sizeof(Curl_addrinfo)); 303 if(!ai) { 304 result = CURLE_OUT_OF_MEMORY; 305 break; 306 } 307 ai->ai_canonname = strdup(he->h_name); 308 if(!ai->ai_canonname) { 309 result = CURLE_OUT_OF_MEMORY; 310 free(ai); 311 break; 312 } 313 ai->ai_addr = calloc(1, ss_size); 314 if(!ai->ai_addr) { 315 result = CURLE_OUT_OF_MEMORY; 316 free(ai->ai_canonname); 317 free(ai); 318 break; 319 } 320 321 if(!firstai) 322 /* store the pointer we want to return from this function */ 323 firstai = ai; 324 325 if(prevai) 326 /* make the previous entry point to this */ 327 prevai->ai_next = ai; 328 329 ai->ai_family = he->h_addrtype; 330 331 /* we return all names as STREAM, so when using this address for TFTP 332 the type must be ignored and conn->socktype be used instead! */ 333 ai->ai_socktype = SOCK_STREAM; 334 335 ai->ai_addrlen = (curl_socklen_t)ss_size; 336 337 /* leave the rest of the struct filled with zero */ 338 339 switch(ai->ai_family) { 340 case AF_INET: 341 addr = (void *)ai->ai_addr; /* storage area for this info */ 342 343 memcpy(&addr->sin_addr, curr, sizeof(struct in_addr)); 344 addr->sin_family = (unsigned short)(he->h_addrtype); 345 addr->sin_port = htons((unsigned short)port); 346 break; 347 348 #ifdef ENABLE_IPV6 349 case AF_INET6: 350 addr6 = (void *)ai->ai_addr; /* storage area for this info */ 351 352 memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr)); 353 addr6->sin6_family = (unsigned short)(he->h_addrtype); 354 addr6->sin6_port = htons((unsigned short)port); 355 break; 356 #endif 357 } 358 359 prevai = ai; 360 } 361 362 if(result) { 363 Curl_freeaddrinfo(firstai); 364 firstai = NULL; 365 } 366 367 return firstai; 368 } 369 370 371 struct namebuff { 372 struct hostent hostentry; 373 union { 374 struct in_addr ina4; 375 #ifdef ENABLE_IPV6 376 struct in6_addr ina6; 377 #endif 378 } addrentry; 379 char *h_addr_list[2]; 380 }; 381 382 383 /* 384 * Curl_ip2addr() 385 * 386 * This function takes an internet address, in binary form, as input parameter 387 * along with its address family and the string version of the address, and it 388 * returns a Curl_addrinfo chain filled in correctly with information for the 389 * given address/host 390 */ 391 392 Curl_addrinfo * 393 Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) 394 { 395 Curl_addrinfo *ai; 396 397 #if defined(__VMS) && \ 398 defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) 399 #pragma pointer_size save 400 #pragma pointer_size short 401 #pragma message disable PTRMISMATCH 402 #endif 403 404 struct hostent *h; 405 struct namebuff *buf; 406 char *addrentry; 407 char *hoststr; 408 size_t addrsize; 409 410 DEBUGASSERT(inaddr && hostname); 411 412 buf = malloc(sizeof(struct namebuff)); 413 if(!buf) 414 return NULL; 415 416 hoststr = strdup(hostname); 417 if(!hoststr) { 418 free(buf); 419 return NULL; 420 } 421 422 switch(af) { 423 case AF_INET: 424 addrsize = sizeof(struct in_addr); 425 addrentry = (void *)&buf->addrentry.ina4; 426 memcpy(addrentry, inaddr, sizeof(struct in_addr)); 427 break; 428 #ifdef ENABLE_IPV6 429 case AF_INET6: 430 addrsize = sizeof(struct in6_addr); 431 addrentry = (void *)&buf->addrentry.ina6; 432 memcpy(addrentry, inaddr, sizeof(struct in6_addr)); 433 break; 434 #endif 435 default: 436 free(hoststr); 437 free(buf); 438 return NULL; 439 } 440 441 h = &buf->hostentry; 442 h->h_name = hoststr; 443 h->h_aliases = NULL; 444 h->h_addrtype = (short)af; 445 h->h_length = (short)addrsize; 446 h->h_addr_list = &buf->h_addr_list[0]; 447 h->h_addr_list[0] = addrentry; 448 h->h_addr_list[1] = NULL; /* terminate list of entries */ 449 450 #if defined(__VMS) && \ 451 defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64) 452 #pragma pointer_size restore 453 #pragma message enable PTRMISMATCH 454 #endif 455 456 ai = Curl_he2ai(h, port); 457 458 free(hoststr); 459 free(buf); 460 461 return ai; 462 } 463 464 /* 465 * Given an IPv4 or IPv6 dotted string address, this converts it to a proper 466 * allocated Curl_addrinfo struct and returns it. 467 */ 468 Curl_addrinfo *Curl_str2addr(char *address, int port) 469 { 470 struct in_addr in; 471 if(Curl_inet_pton(AF_INET, address, &in) > 0) 472 /* This is a dotted IP address 123.123.123.123-style */ 473 return Curl_ip2addr(AF_INET, &in, address, port); 474 #ifdef ENABLE_IPV6 475 { 476 struct in6_addr in6; 477 if(Curl_inet_pton(AF_INET6, address, &in6) > 0) 478 /* This is a dotted IPv6 address ::1-style */ 479 return Curl_ip2addr(AF_INET6, &in6, address, port); 480 } 481 #endif 482 return NULL; /* bad input format */ 483 } 484 485 #ifdef USE_UNIX_SOCKETS 486 /** 487 * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo 488 * struct initialized with this path. 489 * Set '*longpath' to TRUE if the error is a too long path. 490 */ 491 Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract) 492 { 493 Curl_addrinfo *ai; 494 struct sockaddr_un *sa_un; 495 size_t path_len; 496 497 *longpath = FALSE; 498 499 ai = calloc(1, sizeof(Curl_addrinfo)); 500 if(!ai) 501 return NULL; 502 ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); 503 if(!ai->ai_addr) { 504 free(ai); 505 return NULL; 506 } 507 508 sa_un = (void *) ai->ai_addr; 509 sa_un->sun_family = AF_UNIX; 510 511 /* sun_path must be able to store the NUL-terminated path */ 512 path_len = strlen(path) + 1; 513 if(path_len > sizeof(sa_un->sun_path)) { 514 free(ai->ai_addr); 515 free(ai); 516 *longpath = TRUE; 517 return NULL; 518 } 519 520 ai->ai_family = AF_UNIX; 521 ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ 522 ai->ai_addrlen = (curl_socklen_t) 523 ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF); 524 525 /* Abstract Unix domain socket have NULL prefix instead of suffix */ 526 if(abstract) 527 memcpy(sa_un->sun_path + 1, path, path_len - 1); 528 else 529 memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */ 530 531 return ai; 532 } 533 #endif 534 535 #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) 536 /* 537 * curl_dofreeaddrinfo() 538 * 539 * This is strictly for memory tracing and are using the same style as the 540 * family otherwise present in memdebug.c. I put these ones here since they 541 * require a bunch of structs I didn't want to include in memdebug.c 542 */ 543 544 void 545 curl_dofreeaddrinfo(struct addrinfo *freethis, 546 int line, const char *source) 547 { 548 #ifdef USE_LWIPSOCK 549 lwip_freeaddrinfo(freethis); 550 #else 551 (freeaddrinfo)(freethis); 552 #endif 553 curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n", 554 source, line, (void *)freethis); 555 } 556 #endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */ 557 558 559 #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) 560 /* 561 * curl_dogetaddrinfo() 562 * 563 * This is strictly for memory tracing and are using the same style as the 564 * family otherwise present in memdebug.c. I put these ones here since they 565 * require a bunch of structs I didn't want to include in memdebug.c 566 */ 567 568 int 569 curl_dogetaddrinfo(const char *hostname, 570 const char *service, 571 const struct addrinfo *hints, 572 struct addrinfo **result, 573 int line, const char *source) 574 { 575 #ifdef USE_LWIPSOCK 576 int res = lwip_getaddrinfo(hostname, service, hints, result); 577 #else 578 int res = (getaddrinfo)(hostname, service, hints, result); 579 #endif 580 if(0 == res) 581 /* success */ 582 curl_memlog("ADDR %s:%d getaddrinfo() = %p\n", 583 source, line, (void *)*result); 584 else 585 curl_memlog("ADDR %s:%d getaddrinfo() failed\n", 586 source, line); 587 return res; 588 } 589 #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ 590 591 #if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS) 592 /* 593 * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X 594 * 10.11.5. 595 */ 596 void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port) 597 { 598 Curl_addrinfo *ca; 599 struct sockaddr_in *addr; 600 #ifdef ENABLE_IPV6 601 struct sockaddr_in6 *addr6; 602 #endif 603 for(ca = addrinfo; ca != NULL; ca = ca->ai_next) { 604 switch(ca->ai_family) { 605 case AF_INET: 606 addr = (void *)ca->ai_addr; /* storage area for this info */ 607 addr->sin_port = htons((unsigned short)port); 608 break; 609 610 #ifdef ENABLE_IPV6 611 case AF_INET6: 612 addr6 = (void *)ca->ai_addr; /* storage area for this info */ 613 addr6->sin6_port = htons((unsigned short)port); 614 break; 615 #endif 616 } 617 } 618 } 619 #endif 620