diff options
-rw-r--r-- | include/curl/curl.h | 3 | ||||
-rw-r--r-- | lib/curl_addrinfo.c | 21 | ||||
-rw-r--r-- | lib/curl_addrinfo.h | 2 | ||||
-rw-r--r-- | lib/hostip.c | 6 | ||||
-rw-r--r-- | lib/transfer.c | 47 | ||||
-rw-r--r-- | lib/url.c | 14 | ||||
-rw-r--r-- | lib/urldata.h | 4 | ||||
-rw-r--r-- | src/main.c | 11 |
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 @@ -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(); |