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