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 *));

Attachment: diff
Description: diff

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to