diff --git a/ares/CHANGES b/ares/CHANGES
index dd9bac6c9a78d89231a0ce9174340b086075ea3a..c590079b4bb4d995fe73e7a82c4e784a0569c868 100644
--- a/ares/CHANGES
+++ b/ares/CHANGES
@@ -1,5 +1,15 @@
   Changelog for the c-ares project
 
+* Nov 1 2008 (Daniel Stenberg)
+- Carlo Contavalli added support for the glibc "rotate" option, as documented
+  in man resolv.conf: 
+
+  causes round robin selection of nameservers from among those listed.  This
+  has the effect of spreading the query load among all listed servers, rather
+  than having all clients try the first listed server first every time.
+
+  You can enable it with ARES_OPT_ROTATE
+
 * Oct 21 2008 (Yang Tse)
   Charles Hardin added handling of EINPROGRESS for UDP connects.
 
diff --git a/ares/ares.h b/ares/ares.h
index 3609f867647cb4d45a7112594f9ca1aa6f16fd1a..1507f41e9078a9f38ee65acb39c5b77fecd4fc2f 100644
--- a/ares/ares.h
+++ b/ares/ares.h
@@ -114,6 +114,7 @@ extern "C" {
 #define ARES_OPT_SOCK_SNDBUF    (1 << 11)
 #define ARES_OPT_SOCK_RCVBUF    (1 << 12)
 #define ARES_OPT_TIMEOUTMS      (1 << 13)
+#define ARES_OPT_ROTATE         (1 << 14)
 
 /* Nameinfo flag values */
 #define ARES_NI_NOFQDN                  (1 << 0)
@@ -184,6 +185,7 @@ struct ares_options {
   int timeout; /* in seconds or milliseconds, depending on options */
   int tries;
   int ndots;
+  int rotate;
   unsigned short udp_port;
   unsigned short tcp_port;
   int socket_send_buffer_size;
diff --git a/ares/ares_init.c b/ares/ares_init.c
index 4d4ba1ea54ec9c816c9a648a09240c4e898a8723..4a147fc42f6efe4b7b8915ffa641aaa6c1631e2c 100644
--- a/ares/ares_init.c
+++ b/ares/ares_init.c
@@ -144,6 +144,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->timeout = -1;
   channel->tries = -1;
   channel->ndots = -1;
+  channel->rotate = -1;
   channel->udp_port = -1;
   channel->tcp_port = -1;
   channel->socket_send_buffer_size = -1;
@@ -159,6 +160,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->sock_state_cb = NULL;
   channel->sock_state_cb_data = NULL;
 
+  channel->last_server = 0;
   channel->last_timeout_processed = (time_t)now.tv_sec;
 
   /* Initialize our lists of queries */
@@ -352,6 +354,8 @@ static int init_by_options(ares_channel channel,
     channel->tries = options->tries;
   if ((optmask & ARES_OPT_NDOTS) && channel->ndots == -1)
     channel->ndots = options->ndots;
+  if ((optmask & ARES_OPT_ROTATE) && channel->rotate == -1)
+    channel->rotate = options->rotate;
   if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1)
     channel->udp_port = options->udp_port;
   if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
@@ -932,6 +936,8 @@ static int init_by_defaults(ares_channel channel)
     channel->tries = DEFAULT_TRIES;
   if (channel->ndots == -1)
     channel->ndots = 1;
+  if (channel->rotate == -1)
+    channel->rotate = 0;
   if (channel->udp_port == -1)
     channel->udp_port = htons(NAMESERVER_PORT);
   if (channel->tcp_port == -1)
@@ -1302,6 +1308,9 @@ static int set_options(ares_channel channel, const char *str)
       val = try_option(p, q, "retry:");
       if (val && channel->tries == -1)
         channel->tries = atoi(val);
+      val = try_option(p, q, "rotate");
+      if (val && channel->rotate == -1)
+        channel->rotate = 1;
       p = q;
       while (ISSPACE(*p))
         p++;
@@ -1374,7 +1383,7 @@ static char *try_config(char *s, const char *opt)
 static const char *try_option(const char *p, const char *q, const char *opt)
 {
   size_t len = strlen(opt);
-  return ((size_t)(q - p) > len && !strncmp(p, opt, len)) ? &p[len] : NULL;
+  return ((size_t)(q - p) >= len && !strncmp(p, opt, len)) ? &p[len] : NULL;
 }
 
 #ifndef WIN32
diff --git a/ares/ares_private.h b/ares/ares_private.h
index 0b4edf94e413587c45eeb9fce51c89bb0d9791af..976fa9f10b5057ab6c0dc02a4d8465ae393f239f 100644
--- a/ares/ares_private.h
+++ b/ares/ares_private.h
@@ -195,8 +195,8 @@ struct query {
   void *arg;
 
   /* Query status */
-  int try;
-  int server;
+  int try; /* Number of times we tried this query already. */
+  int server; /* Server this query has last been sent to. */
   struct query_server_info *server_info;   /* per-server state */
   int using_tcp;
   int error_status;
@@ -242,6 +242,7 @@ struct ares_channeldata {
   int timeout; /* in milliseconds */
   int tries;
   int ndots;
+  int rotate; /* if true, all servers specified are used */
   int udp_port;
   int tcp_port;
   int socket_send_buffer_size;
@@ -268,6 +269,9 @@ struct ares_channeldata {
      just to draw the line somewhere. */
   time_t last_timeout_processed;
 
+  /* Last server we sent a query to. */
+  int last_server;
+
   /* Circular, doubly-linked list of queries, bucketed various ways.... */
   /* All active queries in a single list: */
   struct list_node all_queries;
diff --git a/ares/ares_process.c b/ares/ares_process.c
index 675af489d81a0369ee97b95450dd27a71d271bbc..b7f375e1922e250027426951586887a805d6458f 100644
--- a/ares/ares_process.c
+++ b/ares/ares_process.c
@@ -670,30 +670,33 @@ static void skip_server(ares_channel channel, struct query *query,
 static void next_server(ares_channel channel, struct query *query,
                         struct timeval *now)
 {
-  /* Advance to the next server or try. */
-  query->server++;
-  for (; query->try < channel->tries; query->try++)
+  /* We need to try each server channel->tries times. We have channel->nservers
+   * servers to try. In total, we need to do channel->nservers * channel->tries
+   * attempts. Use query->try to remember how many times we already attempted
+   * this query. Use modular arithmetic to find the next server to try. */
+  while (++(query->try) < (channel->nservers * channel->tries))
     {
-      for (; query->server < channel->nservers; query->server++)
+      struct server_state *server;
+
+      /* Move on to the next server. */
+      query->server = (query->server + 1) % channel->nservers;
+      server = &channel->servers[query->server];
+
+      /* We don't want to use this server if (1) we decided this
+       * connection is broken, and thus about to be closed, (2)
+       * we've decided to skip this server because of earlier
+       * errors we encountered, or (3) we already sent this query
+       * over this exact connection.
+       */
+      if (!server->is_broken &&
+           !query->server_info[query->server].skip_server &&
+           !(query->using_tcp &&
+             (query->server_info[query->server].tcp_connection_generation ==
+              server->tcp_connection_generation)))
         {
-          struct server_state *server = &channel->servers[query->server];
-          /* We don't want to use this server if (1) we decided this
-           * connection is broken, and thus about to be closed, (2)
-           * we've decided to skip this server because of earlier
-           * errors we encountered, or (3) we already sent this query
-           * over this exact connection.
-           */
-          if (!server->is_broken &&
-               !query->server_info[query->server].skip_server &&
-               !(query->using_tcp &&
-                 (query->server_info[query->server].tcp_connection_generation ==
-                  server->tcp_connection_generation)))
-            {
-               ares__send_query(channel, query, now);
-               return;
-            }
+           ares__send_query(channel, query, now);
+           return;
         }
-      query->server = 0;
 
       /* You might think that with TCP we only need one try. However,
        * even when using TCP, servers can time-out our connection just
@@ -702,6 +705,8 @@ static void next_server(ares_channel channel, struct query *query,
        * tickle a bug that drops our request.
        */
     }
+
+  /* If we are here, all attempts to perform query failed. */
   end_query(channel, query, query->error_status, NULL, 0);
 }
 
@@ -775,8 +780,7 @@ void ares__send_query(ares_channel channel, struct query *query,
     }
     query->timeout = *now;
     ares__timeadd(&query->timeout,
-                  (query->try == 0) ? channel->timeout
-                  : channel->timeout << query->try / channel->nservers);
+                  channel->timeout << (query->try / channel->nservers));
     /* Keep track of queries bucketed by timeout, so we can process
      * timeout events quickly.
      */
diff --git a/ares/ares_send.c b/ares/ares_send.c
index a5811d36d15f5a7d245f2c245c5d463e87fd64c5..be5478df2d4ac6682378821e286f6cbabecfe8b4 100644
--- a/ares/ares_send.c
+++ b/ares/ares_send.c
@@ -95,7 +95,13 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
 
   /* Initialize query status. */
   query->try = 0;
-  query->server = 0;
+
+  /* Choose the server to send the query to. If rotation is enabled, keep track
+   * of the next server we want to use. */
+  query->server = channel->last_server;
+  if (channel->rotate == 1)
+    channel->last_server = (channel->last_server + 1) % channel->nservers;
+
   for (i = 0; i < channel->nservers; i++)
     {
       query->server_info[i].skip_server = 0;