Annotation of embedaddon/curl/lib/curl_addrinfo.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2020, 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 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 = (CURL_SA_FAMILY_T)(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 = (CURL_SA_FAMILY_T)(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_GETADDRINFO) && \
! 536: defined(HAVE_FREEADDRINFO)
! 537: /*
! 538: * curl_dbg_freeaddrinfo()
! 539: *
! 540: * This is strictly for memory tracing and are using the same style as the
! 541: * family otherwise present in memdebug.c. I put these ones here since they
! 542: * require a bunch of structs I didn't want to include in memdebug.c
! 543: */
! 544:
! 545: void
! 546: curl_dbg_freeaddrinfo(struct addrinfo *freethis,
! 547: int line, const char *source)
! 548: {
! 549: curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n",
! 550: source, line, (void *)freethis);
! 551: #ifdef USE_LWIPSOCK
! 552: lwip_freeaddrinfo(freethis);
! 553: #else
! 554: (freeaddrinfo)(freethis);
! 555: #endif
! 556: }
! 557: #endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
! 558:
! 559:
! 560: #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
! 561: /*
! 562: * curl_dbg_getaddrinfo()
! 563: *
! 564: * This is strictly for memory tracing and are using the same style as the
! 565: * family otherwise present in memdebug.c. I put these ones here since they
! 566: * require a bunch of structs I didn't want to include in memdebug.c
! 567: */
! 568:
! 569: int
! 570: curl_dbg_getaddrinfo(const char *hostname,
! 571: const char *service,
! 572: const struct addrinfo *hints,
! 573: struct addrinfo **result,
! 574: int line, const char *source)
! 575: {
! 576: #ifdef USE_LWIPSOCK
! 577: int res = lwip_getaddrinfo(hostname, service, hints, result);
! 578: #else
! 579: int res = (getaddrinfo)(hostname, service, hints, result);
! 580: #endif
! 581: if(0 == res)
! 582: /* success */
! 583: curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n",
! 584: source, line, (void *)*result);
! 585: else
! 586: curl_dbg_log("ADDR %s:%d getaddrinfo() failed\n",
! 587: source, line);
! 588: return res;
! 589: }
! 590: #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
! 591:
! 592: #if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
! 593: /*
! 594: * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
! 595: * 10.11.5.
! 596: */
! 597: void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port)
! 598: {
! 599: Curl_addrinfo *ca;
! 600: struct sockaddr_in *addr;
! 601: #ifdef ENABLE_IPV6
! 602: struct sockaddr_in6 *addr6;
! 603: #endif
! 604: for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
! 605: switch(ca->ai_family) {
! 606: case AF_INET:
! 607: addr = (void *)ca->ai_addr; /* storage area for this info */
! 608: addr->sin_port = htons((unsigned short)port);
! 609: break;
! 610:
! 611: #ifdef ENABLE_IPV6
! 612: case AF_INET6:
! 613: addr6 = (void *)ca->ai_addr; /* storage area for this info */
! 614: addr6->sin6_port = htons((unsigned short)port);
! 615: break;
! 616: #endif
! 617: }
! 618: }
! 619: }
! 620: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>