diff --git a/ares.h b/ares.h
index 368c73a..3b4ff13 100644
--- a/ares.h
+++ b/ares.h
@@ -313,6 +313,20 @@ CARES_EXTERN void ares_destroy(ares_channel channel);
 
 CARES_EXTERN void ares_cancel(ares_channel channel);
 
+/* These next 3 configure local binding for the out-going socket
+ * connection.  Use these to specify source IP and/or network device
+ * on multi-homed systems.
+ */
+CARES_EXTERN void ares_set_local_ip4(ares_channel channel, uint32_t local_ip);
+
+/* local_ip6 should be 16 bytes in length */
+CARES_EXTERN void ares_set_local_ip6(ares_channel channel,
+                                     const unsigned char* local_ip6);
+
+/* local_dev_name should be null terminated. */
+CARES_EXTERN void ares_set_local_dev(ares_channel channel,
+                                     const char* local_dev_name);
+
 CARES_EXTERN void ares_set_socket_callback(ares_channel channel,
                                            ares_sock_create_callback callback,
                                            void *user_data);
@@ -496,6 +510,7 @@ CARES_EXTERN void ares_free_data(void *dataptr);
 
 CARES_EXTERN const char *ares_strerror(int code);
 
+/* TODO:  Hold port here as well. */
 struct ares_addr_node {
   struct ares_addr_node *next;
   int family;
@@ -508,6 +523,10 @@ struct ares_addr_node {
 CARES_EXTERN int ares_set_servers(ares_channel channel,
                                   struct ares_addr_node *servers);
 
+/* Incomming string format: host[:port][,host[:port]]... */
+CARES_EXTERN int ares_set_servers_csv(ares_channel channel,
+                                      const char* servers);
+
 CARES_EXTERN int ares_get_servers(ares_channel channel,
                                   struct ares_addr_node **servers);
 
diff --git a/ares_init.c b/ares_init.c
index 1f561aa..efb74b2 100644
--- a/ares_init.c
+++ b/ares_init.c
@@ -106,6 +106,9 @@ static char *try_config(char *s, const char *opt);
                              x->ndots > -1 && x->timeout > -1 && \
                              x->tries > -1)
 
+unsigned char ARES_ZERO_IPV6_ADDR[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+
+
 int ares_init(ares_channel *channelptr)
 {
   return ares_init_options(channelptr, NULL, 0);
@@ -168,6 +171,10 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->last_server = 0;
   channel->last_timeout_processed = (time_t)now.tv_sec;
 
+  memset(&channel->local_dev_name, 0, sizeof(channel->local_dev_name));
+  channel->local_ip4 = 0;
+  memset(&channel->local_ip6, 0, sizeof(channel->local_ip6));
+  
   /* Initialize our lists of queries */
   ares__init_list_head(&(channel->all_queries));
   for (i = 0; i < ARES_QID_TABLE_SIZE; i++)
@@ -1594,6 +1601,26 @@ unsigned short ares__generate_new_id(rc4_key* key)
   return r;
 }
 
+void ares_set_local_ip4(ares_channel channel, uint32_t local_ip)
+{
+  channel->local_ip4 = local_ip;
+}
+
+/* local_ip6 should be 16 bytes in length */
+void ares_set_local_ip6(ares_channel channel,
+                        const unsigned char* local_ip6) {
+  memcpy(&channel->local_ip6, local_ip6, sizeof(channel->local_ip6));
+}
+
+/* local_dev_name should be null terminated. */
+void ares_set_local_dev(ares_channel channel,
+                        const char* local_dev_name) {
+  strncpy(channel->local_dev_name, local_dev_name,
+          sizeof(channel->local_dev_name));
+  channel->local_dev_name[sizeof(channel->local_dev_name) - 1] = 0;
+}
+
+
 void ares_set_socket_callback(ares_channel channel,
                               ares_sock_create_callback cb,
                               void *data)
diff --git a/ares_options.c b/ares_options.c
index d00368a..26cb6ba 100644
--- a/ares_options.c
+++ b/ares_options.c
@@ -78,7 +78,6 @@ int ares_get_servers(ares_channel channel,
   return status;
 }
 
-
 int ares_set_servers(ares_channel channel,
                      struct ares_addr_node *servers)
 {
@@ -125,3 +124,128 @@ int ares_set_servers(ares_channel channel,
 
   return ARES_SUCCESS;
 }
+
+/* Incomming string format: host[:port][,host[:port]]... */
+int ares_set_servers_csv(ares_channel channel,
+                         const char* _csv)
+{
+  struct ares_addr_node *srvr;
+  int num_srvrs = 0;
+  int i;
+  char* csv = NULL;
+  char* ptr;
+  char* start_host;
+  int port;
+  bool found_port;
+  int rv = ARES_SUCCESS;
+  struct ares_addr_node *servers = NULL;
+  struct ares_addr_node *last = NULL;
+  
+  if (ares_library_initialized() != ARES_SUCCESS)
+    return ARES_ENOTINITIALIZED;
+
+  if (!channel)
+    return ARES_ENODATA;
+
+  ares__destroy_servers_state(channel);
+
+  i = strlen(_csv);
+  if (i == 0)
+     return ARES_SUCCESS; /* blank all servers */
+  
+  csv = malloc(i + 2);
+  strcpy(csv, _csv);
+  if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */
+     csv[i] = ',';
+     csv[i+1] = 0;
+  }
+      
+  ptr = csv;
+  start_host = csv;
+  found_port = false;
+  for (ptr; *ptr; ptr++) {
+     if (*ptr == ',') {
+        char* pp = ptr - 1;
+        struct in_addr in4;
+        struct in6_addr in6;
+        struct ares_addr_node *s = NULL;
+        
+        *ptr = 0; /* null terminate host:port string */
+        /* Got an entry..see if port was specified. */
+        while (pp > start_host) {
+           if (*pp == ':')
+              break; /* yes */
+           if (!isdigit(*pp)) {
+              /* Found end of digits before we found :, so wasn't a port */
+              pp = ptr;
+              break;
+           }
+           pp--;
+        }
+        if ((pp != start_host) && ((pp + 1) < ptr)) {
+           /* Found it. */
+           found_port = true;
+           port = atoi(pp + 1);
+           *pp = 0; /* null terminate host */
+        }
+        /* resolve host, try ipv4 first, rslt is in network byte order */
+        rv = inet_pton(AF_INET, start_host, &in4);
+        if (!rv) {
+           /* Ok, try IPv6 then */
+           rv = inet_pton(AF_INET6, start_host, &in6);
+           if (!rv) {
+              rv = ARES_EBADSTR;
+              goto out;
+           }
+           /* was ipv6, add new server */
+           s = malloc(sizeof(*s));
+           if (!s) {
+              rv = ARES_ENOMEM;
+              goto out;
+           }
+           s->family = AF_INET6;
+           memcpy(&s->addr, &in6, sizeof(struct ares_in6_addr));
+        }
+        else {
+           /* was ipv4, add new server */
+           s = malloc(sizeof(*s));
+           if (!s) {
+              rv = ARES_ENOMEM;
+              goto out;
+           }
+           s->family = AF_INET;
+           memcpy(&s->addr, &in4, sizeof(struct in_addr));           
+        }
+        if (s) {
+           /* TODO:  Add port to ares_addr_node and assign it here. */
+           
+           s->next = NULL;
+           if (last) {
+              last->next = s;
+           }
+           else {
+              servers = s;
+              last = s;
+           }
+        }
+
+        /* Set up for next one */
+        found_port = false;
+        start_host = ptr + 1;
+     }
+  }
+
+  rv = ares_set_servers(channel, servers);
+  
+  out:
+  if (csv)
+     free(csv);
+  while (servers) {
+     struct ares_addr_node *s = servers;
+     servers = servers->next;
+     free(s);
+  }
+  
+  return rv;
+}
+ 
diff --git a/ares_private.h b/ares_private.h
index 0df5cb7..a904fb4 100644
--- a/ares_private.h
+++ b/ares_private.h
@@ -240,6 +240,9 @@ typedef struct rc4_key
   unsigned char y;
 } rc4_key;
 
+
+extern unsigned char ARES_ZERO_IPV6_ADDR[16];
+
 struct ares_channeldata {
   /* Configuration data */
   int flags;
@@ -257,6 +260,13 @@ struct ares_channeldata {
   int nsort;
   char *lookups;
 
+  /* For binding to local devices and/or IP addresses.  Leave
+   * them null/zero for no binding.
+   */
+  char local_dev_name[32];
+  uint32_t local_ip4;
+  unsigned char local_ip6[16];
+
   int optmask; /* the option bitfield passed in at init time */
 
   /* Server addresses and communications state */
diff --git a/ares_process.c b/ares_process.c
index 3ef1ddb..43721d5 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -91,7 +91,6 @@ static void skip_server(ares_channel channel, struct query *query,
                         int whichserver);
 static void next_server(ares_channel channel, struct query *query,
                         struct timeval *now);
-static int configure_socket(ares_socket_t s, ares_channel channel);
 static int open_tcp_socket(ares_channel channel, struct server_state *server);
 static int open_udp_socket(ares_channel channel, struct server_state *server);
 static int same_questions(const unsigned char *qbuf, int qlen,
@@ -869,7 +868,7 @@ static int setsocknonblock(ares_socket_t sockfd,    /* operate on this */
 #endif
 }
 
-static int configure_socket(ares_socket_t s, ares_channel channel)
+static int configure_socket(ares_socket_t s, int family, ares_channel channel)
 {
   setsocknonblock(s, TRUE);
 
@@ -892,6 +891,37 @@ static int configure_socket(ares_socket_t s, ares_channel channel)
                  sizeof(channel->socket_receive_buffer_size)) == -1)
     return -1;
 
+#ifdef SO_BINDTODEVICE
+  if (channel->local_dev_name[0]) {
+     if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
+                    channel->local_dev_name, sizeof(channel->local_dev_name))) {
+        // Only root can do this, and usually not fatal if it doesn't work, so
+        // just continue on.
+     }
+  }
+#endif
+  
+  if (family == AF_INET) {
+     if (channel->local_ip4) {
+        struct sockaddr_in sa;
+        memset(&sa, 0, sizeof(sa));
+        sa.sin_family = AF_INET;
+        sa.sin_addr.s_addr = htonl(channel->local_ip4);
+        if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0)
+           return -1;
+     }
+  }
+  else if (family == AF_INET6) {
+     if (memcmp(channel->local_ip6, ARES_ZERO_IPV6_ADDR, sizeof(channel->local_ip6)) != 0) {
+        struct sockaddr_in6 sa;
+        memset(&sa, 0, sizeof(sa));
+        sa.sin6_family = AF_INET6;
+        memcpy(&sa.sin6_addr, channel->local_ip6, sizeof(channel->local_ip6));
+        if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0)
+           return -1;
+     }
+  }
+  
   return 0;
  }
 
@@ -936,7 +966,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
     return -1;
 
   /* Configure it. */
-  if (configure_socket(s, channel) < 0)
+  if (configure_socket(s, server->addr.family, channel) < 0)
     {
        sclose(s);
        return -1;
@@ -1028,7 +1058,7 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
     return -1;
 
   /* Set the socket non-blocking. */
-  if (configure_socket(s, channel) < 0)
+  if (configure_socket(s, server->addr.family, channel) < 0)
     {
        sclose(s);
        return -1;

