summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2010-11-05 22:31:40 +0100
committerDaniel Stenberg <daniel@haxx.se>2010-11-08 08:56:21 +0100
commit1b24b89cca3c06e36b69969af8edeeaca659515b (patch)
treebaa8fdb1a290d28e7bf7ca54ca8fd482dc98c3dc
parentdc3e7df1c99c2ee9dae06453adbb94fe9584bf75 (diff)
downloadcurl-1b24b89cca3c06e36b69969af8edeeaca659515b.tar.gz
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.
-rw-r--r--include/curl/curl.h3
-rw-r--r--lib/curl_addrinfo.c21
-rw-r--r--lib/curl_addrinfo.h2
-rw-r--r--lib/hostip.c6
-rw-r--r--lib/transfer.c47
-rw-r--r--lib/url.c14
-rw-r--r--lib/urldata.h4
-rw-r--r--src/main.c11
8 files changed, 103 insertions, 5 deletions
diff --git a/include/curl/curl.h b/include/curl/curl.h
index cb9d0fbfb..e95887fe7 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -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;
diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c
index 5098fa431..cfb858c6b 100644
--- a/lib/curl_addrinfo.c
+++ b/lib/curl_addrinfo.c
@@ -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)
/*
diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h
index 63159cc4a..11c339474 100644
--- a/lib/curl_addrinfo.h
+++ b/lib/curl_addrinfo.h
@@ -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,
diff --git a/lib/hostip.c b/lib/hostip.c
index 8f6a52e4f..8e1494e3f 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -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 */
diff --git a/lib/transfer.c b/lib/transfer.c
index 754f6e621..ead3a4deb 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -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
diff --git a/lib/url.c b/lib/url.c
index b715e998f..4a45256d4 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1750,6 +1750,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/
data->set.quote = va_arg(param, struct curl_slist *);
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:
/*
* Progress callback function
diff --git a/lib/urldata.h b/lib/urldata.h
index 4d6059152..489ab16aa 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1186,6 +1186,8 @@ struct DynamicStatic {
bool referer_alloc; /* referer sting is malloc()ed */
struct curl_slist *cookielist; /* list of cookie files set by
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
the transfer on source host */
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 */
time_t timevalue; /* what time to compare with */
Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
diff --git a/src/main.c b/src/main.c
index 79a2b30a6..91875e311 100644
--- a/src/main.c
+++ b/src/main.c
@@ -581,6 +581,7 @@ struct Configurable {
struct curl_httppost *httppost;
struct curl_httppost *last_post;
struct curl_slist *telnet_options;
+ struct curl_slist *resolve;
HttpReq httpreq;
/* for bandwidth limiting features: */
@@ -869,6 +870,7 @@ static void help(void)
" --remote-name-all Use the remote file name for all URLs",
" -R/--remote-time Set the remote file's time on the local output",
" -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-delay <seconds> When retrying, wait this many seconds between each",
" --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},
{"$D", "proto", TRUE},
{"$E", "proto-redir", TRUE},
+ {"$F", "resolve", TRUE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
{"2", "sslv2", FALSE},
@@ -2442,6 +2445,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
if(proto2num(config, &config->proto_redir, nextarg))
return PARAM_BAD_USE;
break;
+ case 'F': /* --resolve */
+ err = add2list(&config->resolve, nextarg);
+ break;
}
break;
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->telnet_options);
curl_slist_free_all(config->mail_rcpt);
+ curl_slist_free_all(config->resolve);
if(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);
}
+ if(config->resolve)
+ /* new in 7.21.3 */
+ my_setopt(curl, CURLOPT_RESOLVE, config->resolve);
+
retry_numretries = config->req_retry;
retrystart = cutil_tvnow();