Ejemplo n.º 1
0
/*
 * addrinfo_callback() gets called by ares, gethostbyname_thread() or
 * getaddrinfo_thread() when we got the name resolved (or not!).
 *
 * If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the
 * address field since it might be freed when this function returns. This
 * operation stores the resolved data in the DNS cache.
 *
 * NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same
 * pointer it is given as argument!
 *
 * The storage operation locks and unlocks the DNS cache.
 */
static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */
                                  int status,
                                  void *addr)
{
  struct connectdata *conn = (struct connectdata *)arg;
  struct Curl_dns_entry *dns = NULL;
  CURLcode rc = CURLE_OK;

  conn->async.status = status;

  if(CURL_ASYNC_SUCCESS == status) {

    /*
     * IPv4/ares: Curl_addrinfo_copy() copies the address and returns an
     * allocated version.
     *
     * IPv6: Curl_addrinfo_copy() returns the input pointer!
     */
    Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port);
    if(ai) {
      struct SessionHandle *data = conn->data;

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      dns = Curl_cache_addr(data, ai,
                            conn->async.hostname,
                            conn->async.port);
      if(!dns) {
        /* failed to store, cleanup and return error */
        Curl_freeaddrinfo(ai);
        rc = CURLE_OUT_OF_MEMORY;
      }

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
    }
    else
      rc = CURLE_OUT_OF_MEMORY;
  }

  conn->async.dns = dns;

 /* Set async.done TRUE last in this function since it may be used multi-
    threaded and once this is TRUE the other thread may read fields from the
    async struct */
  conn->async.done = TRUE;

  /* ipv4: The input hostent struct will be freed by ares when we return from
     this function */
  return rc;
}
Ejemplo n.º 2
0
/*
 * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
 * or getaddrinfo_thread() when we got the name resolved (or not!).
 *
 * If the status argument is CURL_ASYNC_SUCCESS, this function takes
 * ownership of the Curl_addrinfo passed, storing the resolved data
 * in the DNS cache.
 *
 * The storage operation locks and unlocks the DNS cache.
 */
CURLcode Curl_addrinfo_callback(struct connectdata *conn,
                                int status,
                                struct Curl_addrinfo *ai)
{
    struct Curl_dns_entry *dns = NULL;
    CURLcode result = CURLE_OK;

    conn->async.status = status;

    if(CURL_ASYNC_SUCCESS == status) {
        if(ai) {
            struct SessionHandle *data = conn->data;

            if(data->share)
                Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

            dns = Curl_cache_addr(data, ai,
                                  conn->async.hostname,
                                  conn->async.port);
            if(!dns) {
                /* failed to store, cleanup and return error */
                Curl_freeaddrinfo(ai);
                result = CURLE_OUT_OF_MEMORY;
            }

            if(data->share)
                Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
        }
        else {
            result = CURLE_OUT_OF_MEMORY;
        }
    }

    conn->async.dns = dns;

    /* Set async.done TRUE last in this function since it may be used multi-
       threaded and once this is TRUE the other thread may read fields from the
       async struct */
    conn->async.done = TRUE;

    /* IPv4: The input hostent struct will be freed by ares when we return from
       this function */
    return result;
}
Ejemplo n.º 3
0
CURLcode Curl_doh_is_resolved(struct connectdata *conn,
                              struct Curl_dns_entry **dnsp)
{
  struct Curl_easy *data = conn->data;
  *dnsp = NULL; /* defaults to no response */

  if(!data->req.doh.probe[0].easy && !data->req.doh.probe[1].easy) {
    failf(data, "Could not DOH-resolve: %s", conn->async.hostname);
    return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
      CURLE_COULDNT_RESOLVE_HOST;
  }
  else if(!data->req.doh.pending) {
    DOHcode rc;
    DOHcode rc2;
    struct dohentry de;
    struct Curl_dns_entry *dns;
    struct Curl_addrinfo *ai;
    /* remove DOH handles from multi handle and close them */
    curl_multi_remove_handle(data->multi, data->req.doh.probe[0].easy);
    Curl_close(data->req.doh.probe[0].easy);
    curl_multi_remove_handle(data->multi, data->req.doh.probe[1].easy);
    Curl_close(data->req.doh.probe[1].easy);

    /* parse the responses, create the struct and return it! */
    init_dohentry(&de);
    rc = doh_decode(data->req.doh.probe[0].serverdoh.memory,
                    data->req.doh.probe[0].serverdoh.size,
                    data->req.doh.probe[0].dnstype,
                    &de);
    free(data->req.doh.probe[0].serverdoh.memory);
    if(rc) {
      infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc),
            type2name(data->req.doh.probe[0].dnstype),
            data->req.doh.host);
    }
    rc2 = doh_decode(data->req.doh.probe[1].serverdoh.memory,
                     data->req.doh.probe[1].serverdoh.size,
                     data->req.doh.probe[1].dnstype,
                     &de);
    free(data->req.doh.probe[1].serverdoh.memory);
    if(rc2) {
      infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc2),
            type2name(data->req.doh.probe[1].dnstype),
            data->req.doh.host);
    }
    if(!rc || !rc2) {
      infof(data, "DOH Host name: %s\n", data->req.doh.host);
      showdoh(data, &de);

      ai = doh2ai(&de, data->req.doh.host, data->req.doh.port);
      if(!ai) {
        de_cleanup(&de);
        return CURLE_OUT_OF_MEMORY;
      }

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* we got a response, store it in the cache */
      dns = Curl_cache_addr(data, ai, data->req.doh.host, data->req.doh.port);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      de_cleanup(&de);
      if(!dns)
        /* returned failure, bail out nicely */
        Curl_freeaddrinfo(ai);
      else {
        conn->async.dns = dns;
        *dnsp = dns;
        return CURLE_OK;
      }
    }
    de_cleanup(&de);

    return CURLE_COULDNT_RESOLVE_HOST;
  }

  return CURLE_OK;
}
Ejemplo n.º 4
0
int Curl_resolv(struct connectdata *conn,
                const char *hostname,
                int port,
                struct Curl_dns_entry **entry)
{
  char *entry_id = NULL;
  struct Curl_dns_entry *dns = NULL;
  size_t entry_len;
  struct SessionHandle *data = conn->data;
  CURLcode result;
  int rc = CURLRESOLV_ERROR; /* default to failure */

  *entry = NULL;

  /* Create an entry id, based upon the hostname and port */
  entry_id = create_hostcache_id(hostname, port);
  /* If we can't create the entry id, fail */
  if(!entry_id)
    return rc;

  entry_len = strlen(entry_id);

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

  /* free the allocated entry_id again */
  free(entry_id);

  /* See whether the returned entry is stale. Done before we release lock */
  if( remove_entry_if_stale(data, dns) )
    dns = NULL; /* the memory deallocation is being handled by the hash */

  if(dns) {
    dns->inuse++; /* we use it! */
    rc = CURLRESOLV_RESOLVED;
  }

  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

  if(!dns) {
    /* The entry was not in the cache. Resolve it to IP address */

    Curl_addrinfo *addr;
    int respwait;

    /* Check what IP specifics the app has requested and if we can provide it.
     * If not, bail out. */
    if(!Curl_ipvalid(conn))
      return CURLRESOLV_ERROR;

    /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
       non-zero value indicating that we need to wait for the response to the
       resolve call */
    addr = Curl_getaddrinfo(conn,
#ifdef DEBUGBUILD
                            (data->set.str[STRING_DEVICE]
                             && !strcmp(data->set.str[STRING_DEVICE],
                                        "LocalHost"))?"localhost":
#endif
                            hostname, port, &respwait);

    if(!addr) {
      if(respwait) {
        /* the response to our resolve call will come asynchronously at
           a later time, good or bad */
        /* First, check that we haven't received the info by now */
        result = Curl_is_resolved(conn, &dns);
        if(result) /* error detected */
          return CURLRESOLV_ERROR;
        if(dns)
          rc = CURLRESOLV_RESOLVED; /* pointer provided */
        else
          rc = CURLRESOLV_PENDING; /* no info yet */
      }
    }
    else {
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* we got a response, store it in the cache */
      dns = Curl_cache_addr(data, addr, hostname, port);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns)
        /* returned failure, bail out nicely */
        Curl_freeaddrinfo(addr);
      else
        rc = CURLRESOLV_RESOLVED;
    }
  }

  *entry = dns;

  return rc;
}
Ejemplo n.º 5
0
int Curl_resolv(struct connectdata *conn,
                char *hostname,
                int port,
                struct Curl_dns_entry **entry)
{
  char *entry_id = NULL;
  struct Curl_dns_entry *dns = NULL;
  size_t entry_len;
  int wait;
  struct SessionHandle *data = conn->data;
  CURLcode result;
  int rc;
  *entry = NULL;

#ifdef HAVE_SIGSETJMP
  /* this allows us to time-out from the name resolver, as the timeout
     will generate a signal and we will siglongjmp() from that here */
  if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
    /* this is coming from a siglongjmp() */
    failf(data, "name lookup timed out");
    return CURLRESOLV_ERROR;
  }
#endif

  /* Create an entry id, based upon the hostname and port */
  entry_id = create_hostcache_id(hostname, port);
  /* If we can't create the entry id, fail */
  if (!entry_id)
    return CURLRESOLV_ERROR;

  entry_len = strlen(entry_id);

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  /* See if its already in our dns cache */
  dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);

  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

  /* free the allocated entry_id again */
  free(entry_id);

  /* See whether the returned entry is stale. Deliberately done after the
     locked block */
  if ( remove_entry_if_stale(data,dns) )
    dns = NULL; /* the memory deallocation is being handled by the hash */

  rc = CURLRESOLV_ERROR; /* default to failure */

  if (!dns) {
    /* The entry was not in the cache. Resolve it to IP address */

    Curl_addrinfo *addr;

    /* Check what IP specifics the app has requested and if we can provide it.
     * If not, bail out. */
    if(!Curl_ipvalid(data))
      return CURLRESOLV_ERROR;

    /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
       value indicating that we need to wait for the response to the resolve
       call */
    addr = Curl_getaddrinfo(conn, hostname, port, &wait);

    if (!addr) {
      if(wait) {
        /* the response to our resolve call will come asynchronously at
           a later time, good or bad */
        /* First, check that we haven't received the info by now */
        result = Curl_is_resolved(conn, &dns);
        if(result) /* error detected */
          return CURLRESOLV_ERROR;
        if(dns)
          rc = CURLRESOLV_RESOLVED; /* pointer provided */
        else
          rc = CURLRESOLV_PENDING; /* no info yet */
      }
    }
    else {
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* we got a response, store it in the cache */
      dns = Curl_cache_addr(data, addr, hostname, port);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns)
        /* returned failure, bail out nicely */
        Curl_freeaddrinfo(addr);
      else
        rc = CURLRESOLV_RESOLVED;
    }
  }
  else {
    if(data->share)
      Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
    dns->inuse++; /* we use it! */
    if(data->share)
      Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
    rc = CURLRESOLV_RESOLVED;
  }

  *entry = dns;

  return rc;
}
Ejemplo n.º 6
0
Archivo: hostip.c Proyecto: 54chen/curl
CURLcode Curl_loadhostpairs(struct SessionHandle *data)
{
  struct curl_slist *hostp;
  char hostname[256];
  char address[256];
  int port;

  for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
    if(!hostp->data)
      continue;
    if(hostp->data[0] == '-') {
      char *entry_id;
      size_t entry_len;

      if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
        infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n",
              hostp->data);
        continue;
      }

      /* Create an entry id, based upon the hostname and port */
      entry_id = create_hostcache_id(hostname, port);
      /* If we can't create the entry id, fail */
      if(!entry_id) {
        return CURLE_OUT_OF_MEMORY;
      }

      entry_len = strlen(entry_id);

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* delete entry, ignore if it didn't exist */
      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      /* free the allocated entry_id again */
      free(entry_id);
    }
    else {
      struct Curl_dns_entry *dns;
      Curl_addrinfo *addr;
      char *entry_id;
      size_t entry_len;

      if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
                     address)) {
        infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
              hostp->data);
        continue;
      }

      addr = Curl_str2addr(address, port);
      if(!addr) {
        infof(data, "Address in '%s' found illegal!\n", hostp->data);
        continue;
      }

      /* Create an entry id, based upon the hostname and port */
      entry_id = create_hostcache_id(hostname, port);
      /* If we can't create the entry id, fail */
      if(!entry_id) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }

      entry_len = strlen(entry_id);

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* See if its already in our dns cache */
      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

      /* free the allocated entry_id again */
      free(entry_id);

      if(!dns) {
        /* if not in the cache already, put this host in the cache */
        dns = Curl_cache_addr(data, addr, hostname, port);
        if(dns) {
          dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
          /* release the returned reference; the cache itself will keep the
           * entry alive: */
          dns->inuse--;
        }
      }
      else
        /* this is a duplicate, free it again */
        Curl_freeaddrinfo(addr);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }
      infof(data, "Added %s:%d:%s to DNS cache\n",
            hostname, port, address);
    }
  }
  data->change.resolve = NULL; /* dealt with now */

  return CURLE_OK;
}
Ejemplo n.º 7
0
Archivo: hostip.c Proyecto: 54chen/curl
int Curl_resolv(struct connectdata *conn,
                const char *hostname,
                int port,
                struct Curl_dns_entry **entry)
{
  struct Curl_dns_entry *dns = NULL;
  struct SessionHandle *data = conn->data;
  CURLcode result;
  int rc = CURLRESOLV_ERROR; /* default to failure */

  *entry = NULL;

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  dns = fetch_addr(conn, hostname, port);

  if(dns) {
    infof(data, "Hostname %s was found in DNS cache\n", hostname);
    dns->inuse++; /* we use it! */
    rc = CURLRESOLV_RESOLVED;
  }

  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

  if(!dns) {
    /* The entry was not in the cache. Resolve it to IP address */

    Curl_addrinfo *addr;
    int respwait;

    /* Check what IP specifics the app has requested and if we can provide it.
     * If not, bail out. */
    if(!Curl_ipvalid(conn))
      return CURLRESOLV_ERROR;

    /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
       non-zero value indicating that we need to wait for the response to the
       resolve call */
    addr = Curl_getaddrinfo(conn,
#ifdef DEBUGBUILD
                            (data->set.str[STRING_DEVICE]
                             && !strcmp(data->set.str[STRING_DEVICE],
                                        "LocalHost"))?"localhost":
#endif
                            hostname, port, &respwait);

    if(!addr) {
      if(respwait) {
        /* the response to our resolve call will come asynchronously at
           a later time, good or bad */
        /* First, check that we haven't received the info by now */
        result = Curl_resolver_is_resolved(conn, &dns);
        if(result) /* error detected */
          return CURLRESOLV_ERROR;
        if(dns)
          rc = CURLRESOLV_RESOLVED; /* pointer provided */
        else
          rc = CURLRESOLV_PENDING; /* no info yet */
      }
    }
    else {
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* we got a response, store it in the cache */
      dns = Curl_cache_addr(data, addr, hostname, port);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns)
        /* returned failure, bail out nicely */
        Curl_freeaddrinfo(addr);
      else
        rc = CURLRESOLV_RESOLVED;
    }
  }

  *entry = dns;

  return rc;
}
Ejemplo n.º 8
0
Archivo: hostip.c Proyecto: 4ker/CMake
CURLcode Curl_loadhostpairs(struct SessionHandle *data)
{
  struct curl_slist *hostp;
  char hostname[256];
  char address[256];
  int port;

  for(hostp = data->change.resolve; hostp; hostp = hostp->next ) {
    if(!hostp->data)
      continue;
    if(hostp->data[0] == '-') {
      /* TODO: mark an entry for removal */
    }
    else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
                        address)) {
      struct Curl_dns_entry *dns;
      Curl_addrinfo *addr;
      char *entry_id;
      size_t entry_len;

      addr = Curl_str2addr(address, port);
      if(!addr) {
        infof(data, "Resolve %s found illegal!\n", hostp->data);
        continue;
      }

      /* Create an entry id, based upon the hostname and port */
      entry_id = create_hostcache_id(hostname, port);
      /* If we can't create the entry id, fail */
      if(!entry_id) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }

      entry_len = strlen(entry_id);

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* See if its already in our dns cache */
      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);

      /* free the allocated entry_id again */
      free(entry_id);

      if(!dns)
        /* if not in the cache already, put this host in the cache */
        dns = Curl_cache_addr(data, addr, hostname, port);
      else
        /* this is a duplicate, free it again */
        Curl_freeaddrinfo(addr);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

      if(!dns) {
        Curl_freeaddrinfo(addr);
        return CURLE_OUT_OF_MEMORY;
      }
      infof(data, "Added %s:%d:%s to DNS cache\n",
            hostname, port, address);
    }
  }
  data->change.resolve = NULL; /* dealt with now */

  return CURLE_OK;
}