diff --git a/include/curl/curl.h b/include/curl/curl.h index f2501cd..0f0aa9c 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1521,6 +1521,9 @@ typedef enum { /* set the SMTP auth originator */ CINIT(MAIL_AUTH, OBJECTPOINT, 217), + /* This points to a linked list of headers, struct curl_slist kind */ + CINIT(INJECT_DNS_CACHE, OBJECTPOINT, 218), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index bae403f..c887157 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -459,6 +459,47 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) return ai; } + +#define MAX_IP_ADDRS 8 +/* + * The same as Curl_ip2addr but takes in multiple IP addresses + */ +Curl_addrinfo * +Curl_ip2addr_ex(int af, const struct curl_slist * sl, const char *hostname, int port) +{ + struct hostent he; + const size_t addrsize = (af == AF_INET ? sizeof(struct in_addr) : (af == AF_INET6 ? sizeof(struct in6_addr) : 0)); + char * h_addr_ptr[MAX_IP_ADDRS+1]; + union { + struct in_addr ip; + struct in6_addr ip6; + } h_addr[MAX_IP_ADDRS]; + int i = 0; + + DEBUGASSERT(ip && hostname); + + he.h_name = (char*)hostname; // no need to copy because hostent struct is local + he.h_aliases = NULL; + he.h_addrtype = (short)af; + he.h_length = (short)addrsize; + he.h_addr_list= &h_addr_ptr[0]; + + for(; sl && i < MAX_IP_ADDRS; sl=sl->next,i++) + { + if(af == AF_INET){ + if(inet_aton(sl->data, &h_addr[i].ip) == 0) + return NULL; + h_addr_ptr[i] = (char*)&h_addr[i]; + } + else if (af == AF_INET6){ + return NULL; // not implemented + } + } + h_addr_ptr[i] = 0; // terminate the list + return Curl_he2ai(&he, port); +} + + /* * Given an IPv4 or IPv6 dotted string address, this converts it to a proper * allocated Curl_addrinfo struct and returns it. diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h index 11c3394..8aeec43 100644 --- a/lib/curl_addrinfo.h +++ b/lib/curl_addrinfo.h @@ -80,6 +80,10 @@ 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_ip2addr_ex(int af, const struct curl_slist * ip, const char *hostname, int port); + + Curl_addrinfo *Curl_str2addr(char *dotted, int port); #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) diff --git a/lib/url.c b/lib/url.c index 01e217c..9f91fb7 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2398,6 +2398,50 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.redir_protocols = va_arg(param, long); break; + case CURLOPT_INJECT_DNS_CACHE: + /* + * Inject DNS record into curl's DNS cache + * slist format: + * item[0] - hostname (char*) - MUST include portnum, like "192.168.0.1:80" + * item[1-n]- ipaddress(s) (char*) + */ + { + struct curl_slist * sl = va_arg(param, struct curl_slist *); + const char * ihostname = sl->data; + const char * ipaddr = sl->next->data; + unsigned port=0; + char hostname[80]; + int narg = sscanf(ihostname, "%79[^\n:]:%d", hostname, &port); + if(narg < 1) + { + result = CURLE_BAD_FUNCTION_ARGUMENT; + break; // couldn't make sense of the input + } + + struct in_addr addr; + if(!ipaddr || inet_aton(ipaddr, &addr) == 0) + { + result = CURLE_BAD_FUNCTION_ARGUMENT; + break; // invalid input + } + /* Create a DNS record */ + Curl_addrinfo * addrinfo = Curl_ip2addr_ex(AF_INET, sl->next, hostname, port); + + /* store record in the cache */ + if(data->share) + Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); + + /* Usually gets created by easy_perform() but here we need to create ahead*/ + data->dns.hostcachetype = HCACHE_PRIVATE; + data->dns.hostcache = Curl_mk_dnscache(); + + struct Curl_dns_entry *dns = Curl_cache_addr(data, addrinfo, hostname, port); + + if(data->share) + Curl_share_unlock(data, CURL_LOCK_DATA_DNS); + } + break; + case CURLOPT_MAIL_FROM: result = setstropt(&data->set.str[STRING_MAIL_FROM], va_arg(param, char *));