rpms/c-ares/devel 0001-Allow-the-use-of-IPv6-nameservers.patch, NONE, 1.1 c-ares.spec, 1.18, 1.19

Jakub Hrozek jhrozek at fedoraproject.org
Thu Mar 4 11:05:27 UTC 2010


Author: jhrozek

Update of /cvs/pkgs/rpms/c-ares/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv19293

Modified Files:
	c-ares.spec 
Added Files:
	0001-Allow-the-use-of-IPv6-nameservers.patch 
Log Message:
Allow the user of IPv6 nameservers in c-ares

0001-Allow-the-use-of-IPv6-nameservers.patch:
 Makefile.inc           |    3 
 ares.h                 |   13 +++
 ares_destroy.c         |   10 --
 ares_init.c            |  208 +++++++++++++++++++++++++++++++++++++++----------
 ares_private.h         |   13 +--
 ares_process.c         |   95 ++++++++++++++++------
 ares_set_nameservers.3 |   59 +++++++++++++
 7 files changed, 320 insertions(+), 81 deletions(-)

--- NEW FILE 0001-Allow-the-use-of-IPv6-nameservers.patch ---
>From 1f1893a428376810f2c2887cf51ca7891917b216 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 1 Feb 2010 21:23:59 +0100
Subject: [PATCH 1/2] Allow the use of IPv6 nameservers

This patch allows the use of IPv6 addresses for nameserves in both
/etc/resolv.conf and by using the ares_set_nameservers() API.
---
 Makefile.inc           |    3 +
 ares.h                 |   13 +++
 ares_destroy.c         |   10 +--
 ares_init.c            |  208 ++++++++++++++++++++++++++++++++++++++---------
 ares_private.h         |   13 +--
 ares_process.c         |   95 +++++++++++++++++-----
 ares_set_nameservers.3 |   58 +++++++++++++
 7 files changed, 320 insertions(+), 80 deletions(-)
 create mode 100644 ares_set_nameservers.3

diff --git a/Makefile.inc b/Makefile.inc
index 3227858..8e575fd 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -92,6 +92,7 @@ MANPAGES = ares_cancel.3		\
   ares_search.3				\
   ares_send.3				\
   ares_set_socket_callback.3		\
+  ares_set_nameservers.3		\
   ares_strerror.3			\
   ares_timeout.3			\
   ares_version.3
@@ -128,6 +129,7 @@ HTMLPAGES = ares_cancel.html		\
   ares_search.html			\
   ares_send.html			\
   ares_set_socket_callback.html		\
+  ares_set_nameservers.html		\
   ares_strerror.html			\
   ares_timeout.html			\
   ares_version.html
@@ -164,6 +166,7 @@ PDFPAGES = ares_cancel.pdf		\
   ares_search.pdf			\
   ares_send.pdf				\
   ares_set_socket_callback.pdf		\
+  ares_set_nameservers.pdf		\
   ares_strerror.pdf			\
   ares_timeout.pdf			\
   ares_version.pdf
diff --git a/ares.h b/ares.h
index b1c2c22..57bd445 100644
--- a/ares.h
+++ b/ares.h
@@ -426,6 +426,19 @@ struct ares_addr6ttl {
   int             ttl;
 };
 
+struct ares_addr {
+  int family;
+  union {
+    struct in_addr  addr4;
+    struct in6_addr addr6;
+  } addr;
+};
+
+/* Sets nameservers for the given ares channel handle */
+CARES_EXTERN int ares_set_nameservers(ares_channel channel,
+                                      struct ares_addr *servers,
+                                      int num_servers);
+
 struct ares_srv_reply {
   struct ares_srv_reply  *next;
   char                   *host;
diff --git a/ares_destroy.c b/ares_destroy.c
index 0044a71..4040971 100644
--- a/ares_destroy.c
+++ b/ares_destroy.c
@@ -67,15 +67,7 @@ void ares_destroy(ares_channel channel)
     }
 #endif
 
-  if (channel->servers) {
-    for (i = 0; i < channel->nservers; i++)
-      {
-        struct server_state *server = &channel->servers[i];
-        ares__close_sockets(channel, server);
-        assert(ares__is_list_empty(&(server->queries_to_server)));
-      }
-    free(channel->servers);
-  }
+  ares__free_servers(channel);
 
   if (channel->domains) {
     for (i = 0; i < channel->ndomains; i++)
diff --git a/ares_init.c b/ares_init.c
index cb541af..98e9202 100644
--- a/ares_init.c
+++ b/ares_init.c
@@ -65,6 +65,7 @@
 #include <ctype.h>
 #include <time.h>
 #include <errno.h>
+#include <assert.h>
 #include "ares.h"
 #include "inet_net_pton.h"
 #include "ares_library_init.h"
@@ -88,6 +89,7 @@ static int set_search(ares_channel channel, const char *str);
 static int set_options(ares_channel channel, const char *str);
 static const char *try_option(const char *p, const char *q, const char *opt);
 static int init_id_key(rc4_key* key,int key_data_len);
+static void init_servers(ares_channel channel);
 
 #if !defined(WIN32) && !defined(WATT32)
 static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat);
@@ -118,7 +120,6 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   ares_channel channel;
   int i;
   int status = ARES_SUCCESS;
-  struct server_state *server;
   struct timeval now;
 
 #ifdef CURLDEBUG
@@ -248,20 +249,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
     channel->nservers = 1;
 
   /* Initialize server states. */
-  for (i = 0; i < channel->nservers; i++)
-    {
-      server = &channel->servers[i];
-      server->udp_socket = ARES_SOCKET_BAD;
-      server->tcp_socket = ARES_SOCKET_BAD;
-      server->tcp_connection_generation = ++channel->tcp_connection_generation;
-      server->tcp_lenbuf_pos = 0;
-      server->tcp_buffer = NULL;
-      server->qhead = NULL;
-      server->qtail = NULL;
-      ares__init_list_head(&(server->queries_to_server));
-      server->channel = channel;
-      server->is_broken = 0;
-    }
+  init_servers(channel);
 
   *channelptr = channel;
   return ARES_SUCCESS;
@@ -296,6 +284,29 @@ int ares_dup(ares_channel *dest, ares_channel src)
   (*dest)->sock_create_cb      = src->sock_create_cb;
   (*dest)->sock_create_cb_data = src->sock_create_cb_data;
 
+  /* IPv4 nameservers were copied in ares_save_options, we
+   * can only copy v6 servers */
+  if (src->nservers > (*dest)->nservers)
+    {
+        int i;
+        (*dest)->servers =
+            realloc((*dest)->servers,
+                    src->nservers * sizeof(struct server_state));
+        if (!(*dest)->servers)
+          return ARES_ENOMEM;
+
+        for (i = 0; i < src->nservers; i++)
+        {
+            if (src->servers[i].addr.family == AF_INET6)
+              {
+                  memcpy(&((*dest)->servers[(*dest)->nservers].addr),
+                         &(src->servers[i].addr),
+                         sizeof(struct ares_addr));
+                  (*dest)->nservers++;
+              }
+        }
+        init_servers(*dest);
+    }
 
   return ARES_SUCCESS; /* everything went fine */
 
@@ -334,17 +345,33 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
   options->tcp_port = (unsigned short)channel->tcp_port;
   options->sock_state_cb     = channel->sock_state_cb;
   options->sock_state_cb_data = channel->sock_state_cb_data;
+  options->nservers = 0;
 
   /* Copy servers */
   if (channel->nservers) {
+    int numv4 = 0;
     options->servers =
       malloc(channel->nservers * sizeof(struct server_state));
-    if (!options->servers && channel->nservers != 0)
+    if (!options->servers)
       return ARES_ENOMEM;
     for (i = 0; i < channel->nservers; i++)
-      options->servers[i] = channel->servers[i].addr;
+    {
+      if (channel->servers[i].addr.family == AF_INET)
+        {
+            /* Because struct ares_options should stay the same
+             * only IPv4 nameservers are saved in this patch.
+             * ares_dup() works for both v4 and v6, though
+             */
+            options->servers[numv4++] =
+                channel->servers[i].addr.addrV4;
+        }
+    }
+    options->servers =
+        realloc(options->servers, numv4 * sizeof(struct server_state));
+    if (numv4 && !options->servers)
+      return ARES_ENOMEM;
+    options->nservers = numv4;
   }
-  options->nservers = channel->nservers;
 
   /* copy domains */
   if (channel->ndomains) {
@@ -431,7 +458,15 @@ static int init_by_options(ares_channel channel,
           if (!channel->servers)
             return ARES_ENOMEM;
           for (i = 0; i < options->nservers; i++)
-            channel->servers[i].addr = options->servers[i];
+            {
+                /* This is a rather crude way to allow usage of
+                 * protocol-independent struct addrinfo while not
+                 * breaking the public struct ares_options which is forbidden
+                 * in favor of providing ares_set_XXX() functions
+                 */
+                channel->servers[i].addr.family = AF_INET;
+                channel->servers[i].addr.addrV4 = options->servers[i];
+            }
         }
       channel->nservers = options->nservers;
     }
@@ -1001,7 +1036,9 @@ static int init_by_defaults(ares_channel channel)
       rc = ARES_ENOMEM;
       goto error;
     }
-    channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    channel->servers[0].addr.family = AF_INET;
+    channel->servers[0].addr.addrV4.s_addr = htonl(INADDR_LOOPBACK);
     channel->nservers = 1;
   }
 
@@ -1146,11 +1183,48 @@ static int config_lookup(ares_channel channel, const char *str,
 #endif  /* !WIN32 & !WATT32 */
 
 #ifndef WATT32
+static int set_nameserver(struct server_state **servers, int *nservers,
+                          char *str)
+{
+  struct server_state *newserv;
+  struct in_addr addr;
+  struct in6_addr addr6;
+
+  newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
+  if (!newserv)
+    {
+      return ARES_ENOMEM;
+    }
+
+  addr.s_addr = inet_addr(str);
+  if (addr.s_addr == INADDR_NONE)
+    {
+      /* Not an IPv4 address, try IPv6 */
+      if(ares_inet_pton(AF_INET6, str, (struct in6_addr *) &addr6) == 0)
+      {
+          /* Not IPv6 either, bail out */
+          return ARES_EBADFAMILY;
+      }
+
+      newserv[*nservers].addr.family = AF_INET6;
+      memcpy(&newserv[*nservers].addr.addrV6, &addr6, 16);
+    }
+  else
+    {
+      newserv[*nservers].addr.family = AF_INET;
+      newserv[*nservers].addr.addrV4 = addr;
+    }
+
+  *servers = newserv;
+  (*nservers)++;
+  return ARES_SUCCESS;
+}
+
 static int config_nameserver(struct server_state **servers, int *nservers,
                              char *str)
 {
-  struct in_addr addr;
-  struct server_state *newserv;
+  int ret;
+
   /* On Windows, there may be more than one nameserver specified in the same
    * registry key, so we parse it as a space or comma seperated list.
    */
@@ -1178,15 +1252,9 @@ static int config_nameserver(struct server_state **servers, int *nservers,
     }
 
     /* This is the part that actually sets the nameserver */
-    addr.s_addr = inet_addr(begin);
-    if (addr.s_addr == INADDR_NONE)
-      continue;
-    newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
-    if (!newserv)
-      return ARES_ENOMEM;
-    newserv[*nservers].addr = addr;
-    *servers = newserv;
-    (*nservers)++;
+    ret = set_nameserver(servers, nservers, begin);
+    if (ret)
+      return ret;
 
     if (!more)
       break;
@@ -1194,15 +1262,9 @@ static int config_nameserver(struct server_state **servers, int *nservers,
   }
 #else
   /* Add a nameserver entry, if this is a valid address. */
-  addr.s_addr = inet_addr(str);
-  if (addr.s_addr == INADDR_NONE)
-    return ARES_SUCCESS;
-  newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
-  if (!newserv)
-    return ARES_ENOMEM;
-  newserv[*nservers].addr = addr;
-  *servers = newserv;
-  (*nservers)++;
+  ret = set_nameserver(servers, nservers, str);
+  if (ret)
+    return ret;
 #endif
   return ARES_SUCCESS;
 }
@@ -1580,3 +1642,69 @@ void ares_set_socket_callback(ares_channel channel,
   channel->sock_create_cb = cb;
   channel->sock_create_cb_data = data;
 }
+
+static void init_servers(ares_channel channel)
+{
+  struct server_state *server;
+  int i;
+
+  for (i = 0; i < channel->nservers; i++)
+    {
+      server = &channel->servers[i];
+      server->udp_socket = ARES_SOCKET_BAD;
+      server->tcp_socket = ARES_SOCKET_BAD;
+      server->tcp_connection_generation = ++channel->tcp_connection_generation;
+      server->tcp_lenbuf_pos = 0;
+      server->tcp_buffer = NULL;
+      server->qhead = NULL;
+      server->qtail = NULL;
+      ares__init_list_head(&(server->queries_to_server));
+      server->channel = channel;
+      server->is_broken = 0;
+    }
+}
+
+void ares__free_servers(ares_channel channel)
+{
+  int i;
+
+  if (channel->servers) {
+    for (i = 0; i < channel->nservers; i++)
+      {
+        struct server_state *server = &channel->servers[i];
+        ares__close_sockets(channel, server);
+        assert(ares__is_list_empty(&(server->queries_to_server)));
+      }
+    free(channel->servers);
+  }
+
+  channel->servers = NULL;
+  channel->nservers = -1;
+}
+
+int ares_set_nameservers(ares_channel channel,
+                         struct ares_addr *servers,
+                         int num_servers)
+{
+  int i;
+
+  ares__free_servers(channel);
+
+  channel->nservers = num_servers;
+  channel->servers  =
+    malloc(channel->nservers * sizeof(struct server_state));
+  if (!channel->servers)
+    return ARES_ENOMEM;
+
+  for (i = 0; i < num_servers; i++)
+    {
+      struct server_state *ss = channel->servers + i;
+      memset(ss, 0, sizeof(struct server_state));
+
+      ss->channel = channel;
+      memcpy(&ss->addr, &servers[i], sizeof(struct ares_addr));
+    }
+
+  init_servers(channel);
+  return ARES_SUCCESS;
+}
diff --git a/ares_private.h b/ares_private.h
index 4726d7a..286bf90 100644
--- a/ares_private.h
+++ b/ares_private.h
@@ -110,13 +110,7 @@
 #  define writev(s,ptr,cnt) ares_writev(s,ptr,cnt)
 #endif
 
-struct ares_addr {
-  int family;
-  union {
-    struct in_addr  addr4;
-    struct in6_addr addr6;
-  } addr;
-};
+/* Shortcuts used for accessing the union addr inside struct ares_addr */
 #define addrV4 addr.addr4
 #define addrV6 addr.addr6
 
@@ -137,7 +131,8 @@ struct send_request {
 };
 
 struct server_state {
-  struct in_addr addr;
+  struct ares_addr addr;
+
   ares_socket_t udp_socket;
   ares_socket_t tcp_socket;
 
@@ -319,6 +314,8 @@ struct timeval ares__tvnow(void);
 int ares__expand_name_for_response(const unsigned char *encoded,
                                    const unsigned char *abuf, int alen,
                                    char **s, long *enclen);
+void ares__free_servers(ares_channel channel);
+
 #if 0 /* Not used */
 long ares__tvdiff(struct timeval t1, struct timeval t2);
 #endif
diff --git a/ares_process.c b/ares_process.c
index 71f9394..65b95f4 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -434,7 +434,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
   ssize_t count;
   unsigned char buf[PACKETSZ + 1];
 #ifdef HAVE_RECVFROM
-  struct sockaddr_in from;
+  struct sockaddr_storage from;
   ares_socklen_t fromlen;
 #endif
 
@@ -480,16 +480,29 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
         if (count == -1 && try_again(SOCKERRNO))
           continue;
         else if (count <= 0)
-          handle_error(channel, i, now);
+          {
+            handle_error(channel, i, now);
+            break;
+          }
 #ifdef HAVE_RECVFROM
-        else if (from.sin_addr.s_addr != server->addr.s_addr)
-          /* Address response came from did not match the address
-           * we sent the request to.  Someone may be attempting
-           * to perform a cache poisoning attack */
-          break;
+        /* Check if address response came from did match the address
+         * we sent the request to.  Someone may be attempting
+         * to perform a cache poisoning attack */
+        else if (from.ss_family == AF_INET)
+          {
+              if (((struct sockaddr_in *) &from)->sin_addr.s_addr !=
+                   server->addr.addrV4.s_addr)
+                break;
+          }
+        else if (from.ss_family == AF_INET6)
+          {
+              if (memcmp(((struct sockaddr_in6 *) &from)->sin6_addr.s6_addr,
+                         server->addr.addrV6.s6_addr,
+                         16))
+                break;
+          }
 #endif
-        else
-          process_answer(channel, buf, (int)count, i, 0, now);
+        process_answer(channel, buf, (int)count, i, 0, now);
        } while (count > 0);
     }
 }
@@ -889,14 +902,44 @@ static int configure_socket(ares_socket_t s, ares_channel channel)
   return 0;
  }
 
+static int prepare_addrinfo(struct server_state *server, int port,
+                            struct sockaddr_storage *addr)
+{
+  const unsigned short sh_port = (unsigned short)(port & 0xffff);
+  int rc = ARES_SUCCESS;
+
+  switch (server->addr.family)
+    {
+    case AF_INET:
+      ((struct sockaddr_in *) addr)->sin_family = AF_INET;
+      ((struct sockaddr_in *) addr)->sin_port = sh_port;
+      ((struct sockaddr_in *) addr)->sin_addr.s_addr = server->addr.addrV4.s_addr;
+      break;
+
+    case AF_INET6:
+      ((struct sockaddr_in6 *) addr)->sin6_family = AF_INET6;
+      ((struct sockaddr_in6 *) addr)->sin6_port = sh_port;
+      memcpy(((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr,
+             server->addr.addrV6.s6_addr,
+             16);
+      break;
+
+    default:
+      rc = ARES_EBADFAMILY;
+      break;
+    }
+
+  return rc;
+}
+
 static int open_tcp_socket(ares_channel channel, struct server_state *server)
 {
   ares_socket_t s;
   int opt;
-  struct sockaddr_in sockin;
+  struct sockaddr_storage addr;
 
   /* Acquire a socket. */
-  s = socket(AF_INET, SOCK_STREAM, 0);
+  s = socket(server->addr.family, SOCK_STREAM, 0);
   if (s == ARES_SOCKET_BAD)
     return -1;
 
@@ -923,12 +966,15 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
     }
 #endif
 
+  if (prepare_addrinfo(server, channel->tcp_port, &addr) != ARES_SUCCESS)
+    {
+       sclose(s);
+       return -1;
+    }
+
   /* Connect to the server. */
-  memset(&sockin, 0, sizeof(sockin));
-  sockin.sin_family = AF_INET;
-  sockin.sin_addr = server->addr;
-  sockin.sin_port = (unsigned short)(channel->tcp_port & 0xffff);
-  if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1)
+  if (connect(s, (struct sockaddr *) &addr,
+              sizeof(struct sockaddr_storage)) == -1)
     {
       int err = SOCKERRNO;
 
@@ -960,10 +1006,10 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
 static int open_udp_socket(ares_channel channel, struct server_state *server)
 {
   ares_socket_t s;
-  struct sockaddr_in sockin;
+  struct sockaddr_storage addr;
 
   /* Acquire a socket. */
-  s = socket(AF_INET, SOCK_DGRAM, 0);
+  s = socket(server->addr.family, SOCK_DGRAM, 0);
   if (s == ARES_SOCKET_BAD)
     return -1;
 
@@ -974,12 +1020,15 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
        return -1;
     }
 
+  if (prepare_addrinfo(server, channel->udp_port, &addr) != ARES_SUCCESS)
+    {
+       sclose(s);
+       return -1;
+    }
+
   /* Connect to the server. */
-  memset(&sockin, 0, sizeof(sockin));
-  sockin.sin_family = AF_INET;
-  sockin.sin_addr = server->addr;
-  sockin.sin_port = (unsigned short)(channel->udp_port & 0xffff);
-  if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1)
+  if (connect(s, (struct sockaddr *) &addr,
+              sizeof(struct sockaddr_storage)) == -1)
     {
       int err = SOCKERRNO;
 
diff --git a/ares_set_nameservers.3 b/ares_set_nameservers.3
new file mode 100644
index 0000000..f573790
--- /dev/null
+++ b/ares_set_nameservers.3
@@ -0,0 +1,58 @@
+.TH ARES_SET_NAMESERVERS 3 "12 Feb 2010"
+.SH NAME
+ares_set_nameservers - Set nameservers
+.SH SYNOPSIS
+.nf
+.B #include <ares.h>
+.PP
+.B int ares_set_nameservers(ares_channel \fIchannel\fP,
+                            struct ares_addr *\fIservers\fP,
+                            int \fInum_servers\fP)
+.PP
+.B cc file.c -lcares
+.fi
+.SH DESCRIPTION
+.PP
+This function sets nameservers for the given ares channel handle.
+The array
+.I servers
+contains the addresses of nameservers, the length of the array
+is stored in the 
+.I num_servers
+parameter.
+Contrary to initializing nameservers with
+.B ares_init_options
+this function can be used to set IPv6 nameservers.
+
+The structure 
+.I ares_addr
+contains the following fields:
+.sp
+.in +4n
+.nf
+struct ares_addr {
+  int family;
+  union {
+    struct in_addr  addr4;
+    struct in6_addr addr6;
+  } addr;
+};
+.fi
+.in
+
+.PP
+.SH RETURN VALUES
+.B ares_set_nameservers
+can return any of the following values:
+.TP 15
+.B ARES_SUCCESS
+The response was successfully parsed.
+.TP 15
+.B ARES_ENOMEM
+Memory was exhausted.
+.SH SEE ALSO
+.BR ares_init_options (3)
+.SH AUTHOR
+Written by Jakub Hrozek <jhrozek at redhat.com>,
+on behalf of Red Hat, Inc http://www.redhat.com
+
-- 
1.6.6



Index: c-ares.spec
===================================================================
RCS file: /cvs/pkgs/rpms/c-ares/devel/c-ares.spec,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -p -r1.18 -r1.19
--- c-ares.spec	1 Dec 2009 16:49:12 -0000	1.18
+++ c-ares.spec	4 Mar 2010 11:05:27 -0000	1.19
@@ -1,13 +1,14 @@
 Summary: A library that performs asynchronous DNS operations
 Name: c-ares
 Version: 1.7.0
-Release: 1%{?dist}
+Release: 2%{?dist}
 License: MIT
 Group: System Environment/Libraries
 URL: http://c-ares.haxx.se/
 Source0: http://c-ares.haxx.se/c-ares-%{version}.tar.gz
 Source1: LICENSE
 Patch0: %{name}-1.7.0-optflags.patch
+Patch1: 0001-Allow-the-use-of-IPv6-nameservers.patch
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 %description
@@ -28,6 +29,7 @@ compile applications or shared objects t
 %prep
 %setup -q
 %patch0 -p1 -b .optflags
+%patch1 -p1 -b .ipv6
 cp %{SOURCE1} .
 f=CHANGES ; iconv -f iso-8859-1 -t utf-8 $f -o $f.utf8 ; mv $f.utf8 $f
 
@@ -64,6 +66,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man3/ares_*
 
 %changelog
+* Wed Mar  3 2010 Jakub Hrozek <jhrozek at redhat.com> - 1.7.0-2
+- Add a patch to allow usage of IPv6 nameservers
+
 * Tue Dec  1 2009 Tom "spot" Callaway <tcallawa at redhat.com> - 1.7.0-1
 - update to 1.7.0
 



More information about the scm-commits mailing list