Commit 1b24b89c authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

CURLOPT_RESOLVE: added

CURLOPT_RESOLVE is a new option that sends along a curl_slist with
name:port:address sets that will populate the DNS cache with entries so
that request can be "fooled" to use another host than what otherwise
would've been used. Previously we've encouraged the use of Host: for
that when dealing with HTTP, but this new feature has the added bonus
that it allows the name from the URL to be used for TLS SNI and server
certificate name checks as well.

This is a first change. Surely more will follow to make it decent.
parent dc3e7df1
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1436,6 +1436,9 @@ typedef enum {
  /* FNMATCH_FUNCTION user pointer */
  CINIT(FNMATCH_DATA, OBJECTPOINT, 202),

  /* send linked-list of name:port:address sets */
  CINIT(RESOLVE, OBJECTPOINT, 203),

  CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

+21 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#endif

#include "curl_addrinfo.h"
#include "inet_pton.h"

#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -434,6 +435,26 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
  return ai;
}

/*
 * Given an IPv4 or IPv6 dotted string address, this converts it to a proper
 * allocated Curl_addrinfo struct and returns it.
 */
Curl_addrinfo *Curl_str2addr(char *address, int port)
{
  struct in_addr in;
  if(Curl_inet_pton(AF_INET, address, &in) > 0)
    /* This is a dotted IP address 123.123.123.123-style */
    return Curl_ip2addr(AF_INET, &in, address, port);
#ifdef ENABLE_IPV6
  else {
    struct in6_addr in6;
    if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
      /* This is a dotted IPv6 address ::1-style */
      return Curl_ip2addr(AF_INET6, &in6, address, port);
  }
#endif
  return NULL; /* bad input format */
}

#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
/*
+2 −0
Original line number Diff line number Diff line
@@ -80,6 +80,8 @@ Curl_he2ai(const struct hostent *he, int port);
Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);

Curl_addrinfo *Curl_str2addr(char *dotted, int port);

#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
void
curl_dofreeaddrinfo(struct addrinfo *freethis,
+3 −3
Original line number Diff line number Diff line
@@ -421,6 +421,9 @@ int Curl_resolv(struct connectdata *conn,
  /* 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 */
@@ -433,9 +436,6 @@ int Curl_resolv(struct connectdata *conn,
  if(data->share)
    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

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

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

+45 −2
Original line number Diff line number Diff line
@@ -1382,6 +1382,46 @@ Transfer(struct connectdata *conn)
  return CURLE_OK;
}

static void 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] == '-') {
      /* 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;

      addr = Curl_str2addr(address, port);
      if(!addr) {
        infof(data, "Resolve %s found illegal!\n", hostp->data);
        continue;
      }
      infof(data, "Added %s:%d:%s to DNS cache\n",
            hostname, port, address);

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

      /* put this host in the cache */
      dns = Curl_cache_addr(data, addr, hostname, port);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
    }
  }
  data->change.resolve = NULL; /* dealt with now */
}


/*
 * Curl_pretransfer() is called immediately before a transfer starts.
 */
@@ -1415,9 +1455,12 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
  data->info.wouldredirect = NULL;

  /* If there is a list of cookie files to read, do it now! */
  if(data->change.cookielist) {
  if(data->change.cookielist)
    Curl_cookie_loadfiles(data);
  }

  /* If there is a list of host pairs to deal with */
  if(data->change.resolve)
    loadhostpairs(data);

 /* Allow data->set.use_port to set which port to use. This needs to be
  * disabled for example when we follow Location: headers to URLs using
Loading