aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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
6 files changed, 89 insertions, 5 deletions
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 */