Commit 0cd8840d authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

- Andreas Schuldei improved Phil Blundell's patch for IPv6 using c-ares, and I

  edited it slightly. Now you should be able to use IPv6 addresses fine even
  with libcurl built to use c-ares.
parent d4b253ba
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -6,6 +6,11 @@

                                  Changelog

Daniel Stenberg (9 Jul 2008)
- Andreas Schuldei improved Phil Blundell's patch for IPv6 using c-ares, and I
  edited it slightly. Now you should be able to use IPv6 addresses fine even
  with libcurl built to use c-ares.

Daniel Fandrich (9 Jul 2008)
- Fixed an OOM handling problem that cause test 11 to fail the torture test.

+2 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ This release includes the following bugfixes:
 o range numbers could be made to wrongly get output as signed
 o unexpected 1xx responses hung transfers
 o FTP transfers segfault when using different CURLOPT_FTP_FILEMETHOD
 o c-ares powered libcurls can resolve/use IPv6 addresses

This release includes the following known bugs:

@@ -50,7 +51,7 @@ advice from friends like these:
 Lenny Rachitsky, Axel Tillequin, Arnaud Ebalard, Yang Tse, Dan Fandrich,
 Rob Crittenden, Dengminwen, Christopher Palow, Hans-Jurgen May,
 Phil Pellouchoud, Eduard Bloch, John Lightsey, Stephen Collyer, Tor Arntsen,
 Rolland Dudemaine, Phil Blundell, Scott Barrett
 Rolland Dudemaine, Phil Blundell, Scott Barrett, Andreas Schuldei


        Thanks! (and sorry if I forgot to mention someone)
+86 −2
Original line number Diff line number Diff line
@@ -297,6 +297,70 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
  return rc;
}

#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
/*
 * Curl_ip2addr6() takes an ipv6 internet address as input parameter
 * together with a pointer to the string version of the address, and it
 * returns a Curl_addrinfo chain filled in correctly with information for this
 * address/host.
 *
 * The input parameters ARE NOT checked for validity but they are expected
 * to have been checked already when this is called.
 */
Curl_addrinfo *Curl_ip2addr6(struct in6_addr *in,
			     const char *hostname, int port)
{
  Curl_addrinfo *ai;

#if defined(VMS) &&  defined(__INITIAL_POINTER_SIZE) && \
  (__INITIAL_POINTER_SIZE == 64)
#pragma pointer_size save
#pragma pointer_size short
#pragma message disable PTRMISMATCH
#endif

  struct hostent *h;
  struct in6_addr *addrentry;
  struct namebuf6 {
    struct hostent hostentry;
    char *h_addr_list[2];
    struct in6_addr addrentry;
    char hostname[1];
  };
  struct namebuf6 *buf = malloc(sizeof (struct namebuf6) + strlen(hostname));

  if(!buf)
    return NULL;

  h = &buf->hostentry;
  h->h_addr_list = &buf->h_addr_list[0];
  addrentry = &buf->addrentry;
  memcpy(addrentry, in, sizeof (*in));
  h->h_addr_list[0] = (char*)addrentry;
  h->h_addr_list[1] = NULL; /* terminate list of entries */
  h->h_name = &buf->hostname[0];
  h->h_aliases = NULL;
  h->h_addrtype = AF_INET6;

  /* Now store the dotted version of the address */
  strcpy (h->h_name, hostname);

#if defined(VMS) && defined(__INITIAL_POINTER_SIZE) && \
  (__INITIAL_POINTER_SIZE == 64)
#pragma pointer_size restore
#pragma message enable PTRMISMATCH
#endif

  ai = Curl_he2ai(h, port);

  free(buf);

  return ai;
}
#endif /* CURLRES_IPV6 */



/*
 * Curl_getaddrinfo() - when using ares
 *
@@ -313,7 +377,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
  char *bufp;
  struct SessionHandle *data = conn->data;
  in_addr_t in = inet_addr(hostname);

  int family = PF_INET;
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
  struct in6_addr in6;
#endif /* CURLRES_IPV6 */
  *waitp = FALSE;

  if(in != CURL_INADDR_NONE) {
@@ -321,6 +388,23 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
    return Curl_ip2addr(in, hostname, port);
  }

#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
  if (inet_pton (AF_INET6, hostname, &in6) > 0) {
    /* This must be an IPv6 address literal.  */
    return Curl_ip2addr6(&in6, hostname, port);
  }

  switch(data->set.ip_version) {
  case CURL_IPRESOLVE_V4:
    family = PF_INET;
    break;
  default: /* by default we try ipv6, as PF_UNSPEC isn't supported by (c-)ares */
  case CURL_IPRESOLVE_V6:
    family = PF_INET6;
    break;
  }
#endif /* CURLRES_IPV6 */

  bufp = strdup(hostname);

  if(bufp) {
@@ -332,7 +416,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
    conn->async.dns = NULL;   /* clear */

    /* areschannel is already setup in the Curl_open() function */
    ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
    ares_gethostbyname(data->state.areschannel, hostname, family,
                       (ares_host_callback)Curl_addrinfo4_callback, conn);

    *waitp = TRUE; /* please wait for the response */
+115 −2
Original line number Diff line number Diff line
@@ -545,7 +545,8 @@ Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
#endif /* CURLRES_ADDRINFO_COPY */

/***********************************************************************
 * Only for plain-ipv4 and c-ares builds
 * Only for plain-ipv4 and c-ares builds (NOTE: c-ares builds can be IPv6
 * enabled)
 **********************************************************************/

#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
@@ -630,6 +631,118 @@ Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)

  return ai;
}
#endif /* CURLRES_IPV4 || CURLRES_ARES */

/*
 * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct.
 * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6
 * stacks, but for all hosts and environments.
 *
 *   Curl_addrinfo defined in "lib/hostip.h"
 *
 *     struct Curl_addrinfo {
 *       int                   ai_flags;
 *       int                   ai_family;
 *       int                   ai_socktype;
 *       int                   ai_protocol;
 *       socklen_t             ai_addrlen;   * Follow rfc3493 struct addrinfo *
 *       char                 *ai_canonname;
 *       struct sockaddr      *ai_addr;
 *       struct Curl_addrinfo *ai_next;
 *     };
 *
 *   hostent defined in <netdb.h>
 *
 *     struct hostent {
 *       char    *h_name;
 *       char    **h_aliases;
 *       int     h_addrtype;
 *       int     h_length;
 *       char    **h_addr_list;
 *     };
 *
 *   for backward compatibility:
 *
 *     #define h_addr  h_addr_list[0]
 */

Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port)
{
  Curl_addrinfo *ai;
  Curl_addrinfo *prevai = NULL;
  Curl_addrinfo *firstai = NULL;
  struct sockaddr_in *addr;
#ifdef CURLRES_IPV6
  struct sockaddr_in6 *addr6;
#endif /* CURLRES_IPV6 */
  int i;
  struct in_addr *curr;

  if(!he)
    /* no input == no output! */
    return NULL;

  for(i=0; (curr = (struct in_addr *)he->h_addr_list[i]) != NULL; i++) {

    int ss_size;
#ifdef CURLRES_IPV6
    if (he->h_addrtype == AF_INET6)
      ss_size = sizeof (struct sockaddr_in6);
    else
#endif /* CURLRES_IPV6 */
      ss_size = sizeof (struct sockaddr_in);

    ai = calloc(1, sizeof(Curl_addrinfo) + ss_size);

    if(!ai)
      break;

    if(!firstai)
      /* store the pointer we want to return from this function */
      firstai = ai;

    if(prevai)
      /* make the previous entry point to this */
      prevai->ai_next = ai;

    ai->ai_family = he->h_addrtype;

    /* we return all names as STREAM, so when using this address for TFTP
       the type must be ignored and conn->socktype be used instead! */
    ai->ai_socktype = SOCK_STREAM;

    ai->ai_addrlen = ss_size;
    /* make the ai_addr point to the address immediately following this struct
       and use that area to store the address */
    ai->ai_addr = (struct sockaddr *) ((char*)ai + sizeof(Curl_addrinfo));

    /* need to free this eventually */
    ai->ai_canonname = strdup(he->h_name);

    /* leave the rest of the struct filled with zero */

    switch (ai->ai_family) {
    case AF_INET:
      addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */

      memcpy((char *)&(addr->sin_addr), curr, sizeof(struct in_addr));
      addr->sin_family = (unsigned short)(he->h_addrtype);
      addr->sin_port = htons((unsigned short)port);
      break;

#ifdef CURLRES_IPV6
    case AF_INET6:
      addr6 = (struct sockaddr_in6 *)ai->ai_addr; /* storage area for this info */

      memcpy((char *)&(addr6->sin6_addr), curr, sizeof(struct in6_addr));
      addr6->sin6_family = (unsigned short)(he->h_addrtype);
      addr6->sin6_port = htons((unsigned short)port);
      break;
#endif /* CURLRES_IPV6 */
    }

    prevai = ai;
  }
  return firstai;
}

#endif /* CURLRES_IPV4 || CURLRES_ARES */
+4 −0
Original line number Diff line number Diff line
@@ -104,6 +104,10 @@
 */
#ifdef CURLRES_IPV6
typedef struct addrinfo Curl_addrinfo;
#ifdef CURLRES_ARES
Curl_addrinfo *Curl_ip2addr6(struct in6_addr *in,
			     const char *hostname, int port);
#endif
#else
/* OK, so some ipv4-only include tree probably have the addrinfo struct, but
   to work even on those that don't, we provide our own look-alike! */
Loading