File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / curl_addrinfo.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>