curl-library
patch: New Option DNS Cache
Date: Mon, 2 Apr 2012 14:13:04 -0700
Summary:
This patch introduces a new curl option named INJECT_DNS CACHE to manually populate curl's internal DNS cache table. This code has been in production for a couple of years in a very high volume consumer product.
Rationale:
A low-level option like tis comes very handy in cases where your platform has multiple network interfaces. For example consider what you need to do if your platform has 2 interfaces eth0 and eth1 and system default route is set to eth0 BUT you want to execute http fetch over eth1. Without such option you would have to introduce 2 new host routes into your system routing table. One route to reach DNS server over eth1 and another to reach the http server. That can be often cumbersome and/or impossible because of system permissions or other agents managing routing. Here comes INJECT_DNS_CACHE allowing you make curl execute your requests without going out to resolve DNS names.
Note I also attached the diff as an attachment in case email mangles whitespace
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 *));
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
- application/octet-stream attachment: diff