diff --git a/ares/CHANGES b/ares/CHANGES
index 6f96bf910d4a4289ea95e82655ba01e5a1c51a99..ebb862a10845d7a12a8d91d38ce4439342a51ca3 100644
--- a/ares/CHANGES
+++ b/ares/CHANGES
@@ -1,5 +1,10 @@
   Changelog for the c-ares project
 
+* Dec 4 2008 (Daniel Stenberg)
+
+  Gregor Jasny provided the patch that introduces ares_set_socket_callback(),
+  and I edited it to also get duped by ares_dup().
+
 * Dec 3 2008 (Daniel Stenberg)
 
   API changes:
diff --git a/ares/RELEASE-NOTES b/ares/RELEASE-NOTES
index f46b1ac7e081554cbe1d6986099ad4fddb219d93..3c73d10608fa47acd714977626ba5298f9087f44 100644
--- a/ares/RELEASE-NOTES
+++ b/ares/RELEASE-NOTES
@@ -1,18 +1,25 @@
-This is what's new and changed in the c-ares 1.5.4 release:
+This is what's new and changed in the c-ares 1.6.0 release:
+
+Changed:
+
+ o Added support for the glibc "rotate" resolv.conf option (or ARES_OPT_ROTATE)
+ o Added ares_gethostbyname_file()
+ o Added ares_dup()
+ o Added ares_set_socket_callback()
+
+Fixed:
 
  o improved configure detection of several functions
  o improved source code portability
  o adig supports a regular numerical dotted IP address for the -s option
  o handling of EINPROGRESS for UDP connects
- o supports the glibc "rotate" resolv.conf option (or ARES_OPT_ROTATE)
- o added the new function ares_gethostbyname_file()
- o bugfix in ares_parse_ptr_reply() which would cause a buffer to shrink
-   instead of expand if a reply contained 8 or more records
+ o ares_parse_ptr_reply()would cause a buffer to shrink instead of expand if a
+   reply contained 8 or more records
  o buildconf works on OS X
 
 Thanks go to these friendly people for their efforts and contributions:
 
- Yang Tse, Charles Hardin, Carlo Contavalli, Brad Spencer, Gerald Combs
- and obviously Daniel Stenberg
+ Yang Tse, Charles Hardin, Carlo Contavalli, Brad Spencer, Gerald Combs,
+ Gregor Jasny
 
 Have fun!
diff --git a/ares/ares.h b/ares/ares.h
index 495130d733d5bee0a310b394e4efd430a93fb4f6..919bafb7cbace3033fd2ac93f8c57efb5f72fcc8 100644
--- a/ares/ares.h
+++ b/ares/ares.h
@@ -229,6 +229,8 @@ typedef void (*ares_host_callback)(void *arg, int status, int timeouts,
                                    struct hostent *hostent);
 typedef void (*ares_nameinfo_callback)(void *arg, int status, int timeouts,
                                        char *node, char *service);
+typedef int  (*ares_sock_create_callback)(ares_socket_t socket_fd,
+                                          int type, void *data);
 
 int ares_init(ares_channel *channelptr);
 int ares_init_options(ares_channel *channelptr, struct ares_options *options,
@@ -239,6 +241,9 @@ void ares_destroy_options(struct ares_options *options);
 int ares_dup(ares_channel *dest, ares_channel src);
 void ares_destroy(ares_channel channel);
 void ares_cancel(ares_channel channel);
+void ares_set_socket_callback(ares_channel channel,
+                              ares_sock_create_callback callback,
+                              void *user_data);
 void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
                ares_callback callback, void *arg);
 void ares_query(ares_channel channel, const char *name, int dnsclass,
diff --git a/ares/ares_init.c b/ares/ares_init.c
index faa41581b927af36b74953e3771803167664bc13..e8d9ab1d09c48460b3866ab8dfeef4a56ef15d07 100644
--- a/ares/ares_init.c
+++ b/ares/ares_init.c
@@ -159,6 +159,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->servers = NULL;
   channel->sock_state_cb = NULL;
   channel->sock_state_cb_data = NULL;
+  channel->sock_create_cb = NULL;
+  channel->sock_create_cb_data = NULL;
 
   channel->last_server = 0;
   channel->last_timeout_processed = (time_t)now.tv_sec;
@@ -283,8 +285,9 @@ int ares_dup(ares_channel *dest, ares_channel src)
     return rc;
 
   /* Now clone the options that ares_save_options() doesn't support. */
+  (*dest)->sock_create_cb      = src->sock_create_cb;
+  (*dest)->sock_create_cb_data = src->sock_create_cb_data;
 
-  /* No such options available yet */
 
   return ARES_SUCCESS; /* everything went fine */
 
@@ -1551,3 +1554,11 @@ unsigned short ares__generate_new_id(rc4_key* key)
   ares__rc4(key, (unsigned char *)&r, sizeof(r));
   return r;
 }
+
+void ares_set_socket_callback(ares_channel channel,
+                              ares_sock_create_callback cb,
+                              void *data)
+{
+  channel->sock_create_cb = cb;
+  channel->sock_create_cb_data = data;
+}
diff --git a/ares/ares_private.h b/ares/ares_private.h
index bae0b077d46865b1d2d2cf5de93017981611f2b9..137e155de05d2ef6f98f354ec5ba7748703bd701 100644
--- a/ares/ares_private.h
+++ b/ares/ares_private.h
@@ -296,6 +296,9 @@ struct ares_channeldata {
 
   ares_sock_state_cb sock_state_cb;
   void *sock_state_cb_data;
+
+  ares_sock_create_callback sock_create_cb;
+  void *sock_create_cb_data;
 };
 
 /* return true if now is exactly check time or later */
diff --git a/ares/ares_process.c b/ares/ares_process.c
index 58f072595b6d1a62c3075b058adfada94e66c18a..8c25b11dab8c21d75bb28f7d3412555508612cdb 100644
--- a/ares/ares_process.c
+++ b/ares/ares_process.c
@@ -929,6 +929,17 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
         }
     }
 
+  if (channel->sock_create_cb)
+    {
+      int err = channel->sock_create_cb(s, SOCK_STREAM,
+                                        channel->sock_create_cb_data);
+      if (err < 0)
+        {
+          closesocket(s);
+          return err;
+        }
+    }
+
   SOCK_STATE_CALLBACK(channel, s, 1, 0);
   server->tcp_buffer_pos = 0;
   server->tcp_socket = s;
@@ -969,6 +980,17 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
         }
     }
 
+  if (channel->sock_create_cb)
+    {
+      int err = channel->sock_create_cb(s, SOCK_DGRAM,
+                                        channel->sock_create_cb_data);
+      if (err < 0)
+        {
+          closesocket(s);
+          return err;
+        }
+    }
+
   SOCK_STATE_CALLBACK(channel, s, 1, 0);
 
   server->udp_socket = s;