1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-22 08:08:50 -05:00

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.
This commit is contained in:
Daniel Stenberg 2010-11-05 22:31:40 +01:00
parent dc3e7df1c9
commit 1b24b89cca
8 changed files with 103 additions and 5 deletions

View File

@ -1436,6 +1436,9 @@ typedef enum {
/* FNMATCH_FUNCTION user pointer */ /* FNMATCH_FUNCTION user pointer */
CINIT(FNMATCH_DATA, OBJECTPOINT, 202), CINIT(FNMATCH_DATA, OBJECTPOINT, 202),
/* send linked-list of name:port:address sets */
CINIT(RESOLVE, OBJECTPOINT, 203),
CURLOPT_LASTENTRY /* the last unused */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -49,6 +49,7 @@
#endif #endif
#include "curl_addrinfo.h" #include "curl_addrinfo.h"
#include "inet_pton.h"
#define _MPRINTF_REPLACE /* use our functions only */ #define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h> #include <curl/mprintf.h>
@ -434,6 +435,26 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
return ai; 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) #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
/* /*

View File

@ -80,6 +80,8 @@ Curl_he2ai(const struct hostent *he, int port);
Curl_addrinfo * Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); 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) #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
void void
curl_dofreeaddrinfo(struct addrinfo *freethis, curl_dofreeaddrinfo(struct addrinfo *freethis,

View File

@ -421,6 +421,9 @@ int Curl_resolv(struct connectdata *conn,
/* See if its already in our dns cache */ /* See if its already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); 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 */ /* See whether the returned entry is stale. Done before we release lock */
if( remove_entry_if_stale(data, dns) ) if( remove_entry_if_stale(data, dns) )
dns = NULL; /* the memory deallocation is being handled by the hash */ dns = NULL; /* the memory deallocation is being handled by the hash */
@ -433,9 +436,6 @@ int Curl_resolv(struct connectdata *conn,
if(data->share) if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS); Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
/* free the allocated entry_id again */
free(entry_id);
if(!dns) { if(!dns) {
/* The entry was not in the cache. Resolve it to IP address */ /* The entry was not in the cache. Resolve it to IP address */

View File

@ -1382,6 +1382,46 @@ Transfer(struct connectdata *conn)
return CURLE_OK; 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. * Curl_pretransfer() is called immediately before a transfer starts.
*/ */
@ -1415,9 +1455,12 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
data->info.wouldredirect = NULL; data->info.wouldredirect = NULL;
/* If there is a list of cookie files to read, do it now! */ /* 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); 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 /* 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 * disabled for example when we follow Location: headers to URLs using

View File

@ -1750,6 +1750,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/ */
data->set.quote = va_arg(param, struct curl_slist *); data->set.quote = va_arg(param, struct curl_slist *);
break; break;
case CURLOPT_RESOLVE:
/*
* List of NAME:[address] names to populate the DNS cache with
* Prefix the NAME with dash (-) to _remove_ the name from the cache.
*
* Names added with this API will remain in the cache until explicitly
* removed or the handle is cleaned up.
*
* This API can remove any name from the DNS cache, but only entries
* that aren't actually in use right now will be pruned immediately.
*/
data->set.resolve = va_arg(param, struct curl_slist *);
data->change.resolve = data->set.resolve;
break;
case CURLOPT_PROGRESSFUNCTION: case CURLOPT_PROGRESSFUNCTION:
/* /*
* Progress callback function * Progress callback function

View File

@ -1186,6 +1186,8 @@ struct DynamicStatic {
bool referer_alloc; /* referer sting is malloc()ed */ bool referer_alloc; /* referer sting is malloc()ed */
struct curl_slist *cookielist; /* list of cookie files set by struct curl_slist *cookielist; /* list of cookie files set by
curl_easy_setopt(COOKIEFILE) calls */ curl_easy_setopt(COOKIEFILE) calls */
struct curl_slist *resolve; /* set to point to the set.resolve list when
this should be dealt with in pretransfer */
}; };
/* /*
@ -1332,6 +1334,8 @@ struct UserDefined {
struct curl_slist *source_postquote; /* in 3rd party transfer mode - after struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
the transfer on source host */ the transfer on source host */
struct curl_slist *telnet_options; /* linked list of telnet options */ struct curl_slist *telnet_options; /* linked list of telnet options */
struct curl_slist *resolve; /* list of names to add/remove from
DNS cache */
curl_TimeCond timecondition; /* kind of time/date comparison */ curl_TimeCond timecondition; /* kind of time/date comparison */
time_t timevalue; /* what time to compare with */ time_t timevalue; /* what time to compare with */
Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */

View File

@ -581,6 +581,7 @@ struct Configurable {
struct curl_httppost *httppost; struct curl_httppost *httppost;
struct curl_httppost *last_post; struct curl_httppost *last_post;
struct curl_slist *telnet_options; struct curl_slist *telnet_options;
struct curl_slist *resolve;
HttpReq httpreq; HttpReq httpreq;
/* for bandwidth limiting features: */ /* for bandwidth limiting features: */
@ -869,6 +870,7 @@ static void help(void)
" --remote-name-all Use the remote file name for all URLs", " --remote-name-all Use the remote file name for all URLs",
" -R/--remote-time Set the remote file's time on the local output", " -R/--remote-time Set the remote file's time on the local output",
" -X/--request <command> Specify request command to use", " -X/--request <command> Specify request command to use",
" --resolve <host:port:address> Force resolve of HOST:PORT to ADDRESS",
" --retry <num> Retry request <num> times if transient problems occur", " --retry <num> Retry request <num> times if transient problems occur",
" --retry-delay <seconds> When retrying, wait this many seconds between each", " --retry-delay <seconds> When retrying, wait this many seconds between each",
" --retry-max-time <seconds> Retry only within this period", " --retry-max-time <seconds> Retry only within this period",
@ -1881,6 +1883,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"$C", "ftp-pret", FALSE}, {"$C", "ftp-pret", FALSE},
{"$D", "proto", TRUE}, {"$D", "proto", TRUE},
{"$E", "proto-redir", TRUE}, {"$E", "proto-redir", TRUE},
{"$F", "resolve", TRUE},
{"0", "http1.0", FALSE}, {"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE}, {"1", "tlsv1", FALSE},
{"2", "sslv2", FALSE}, {"2", "sslv2", FALSE},
@ -2442,6 +2445,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
if(proto2num(config, &config->proto_redir, nextarg)) if(proto2num(config, &config->proto_redir, nextarg))
return PARAM_BAD_USE; return PARAM_BAD_USE;
break; break;
case 'F': /* --resolve */
err = add2list(&config->resolve, nextarg);
break;
} }
break; break;
case '#': /* --progress-bar */ case '#': /* --progress-bar */
@ -4043,6 +4049,7 @@ static void free_config_fields(struct Configurable *config)
curl_slist_free_all(config->headers); curl_slist_free_all(config->headers);
curl_slist_free_all(config->telnet_options); curl_slist_free_all(config->telnet_options);
curl_slist_free_all(config->mail_rcpt); curl_slist_free_all(config->mail_rcpt);
curl_slist_free_all(config->resolve);
if(config->easy) if(config->easy)
curl_easy_cleanup(config->easy); curl_easy_cleanup(config->easy);
@ -5438,6 +5445,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
my_setopt(curl, CURLOPT_HEADERDATA, &outs); my_setopt(curl, CURLOPT_HEADERDATA, &outs);
} }
if(config->resolve)
/* new in 7.21.3 */
my_setopt(curl, CURLOPT_RESOLVE, config->resolve);
retry_numretries = config->req_retry; retry_numretries = config->req_retry;
retrystart = cutil_tvnow(); retrystart = cutil_tvnow();