Made sortlist support IPv6 (this can probably use some testing)
authorDominick Meglio <dcm5151@esu.edu>
Sat, 9 Apr 2005 19:59:59 +0000 (19:59 +0000)
committerDominick Meglio <dcm5151@esu.edu>
Sat, 9 Apr 2005 19:59:59 +0000 (19:59 +0000)
CHANGES
ares_gethostbyaddr.c
ares_gethostbyname.c
ares_init.c
ares_private.h

diff --git a/CHANGES b/CHANGES
index 6f8ce30..8acbf08 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,8 @@
 
 * April 9
 
+- Made sortlist support IPv6 (this can probably use some testing).
+
 - Made sortlist support CIDR matching for IPv4.
 
 * April 8
index bd63d1a..a415e36 100644 (file)
 #undef WIN32
 #endif
 
-union ares_addr {
-  struct in_addr addr4;
-  struct in6_addr addr6;
-};
-
 struct addr_query {
   /* Arguments passed to ares_gethostbyaddr() */
   ares_channel channel;
index afd4c71..daae5db 100644 (file)
@@ -12,7 +12,7 @@
  * this software for any purpose.  It is provided "as is"
  * without express or implied warranty.
  */
-/* TODO: IPv6 sortlist */
+
 #include "setup.h"
 #include <sys/types.h>
 
@@ -60,8 +60,12 @@ static int fake_hostent(const char *name, int family, ares_host_callback callbac
 static int file_lookup(const char *name, int family, struct hostent **host);
 static void sort_addresses(struct hostent *host, struct apattern *sortlist,
                            int nsort);
+static void sort6_addresses(struct hostent *host, struct apattern *sortlist,
+                           int nsort);
 static int get_address_index(struct in_addr *addr, struct apattern *sortlist,
                              int nsort);
+static int get6_address_index(struct in6_addr *addr, struct apattern *sortlist,
+                             int nsort);
 
 void ares_gethostbyname(ares_channel channel, const char *name, int family,
                         ares_host_callback callback, void *arg)
@@ -154,10 +158,8 @@ static void host_callback(void *arg, int status, unsigned char *abuf, int alen)
       else if (hquery->family == AF_INET6)
         {
           status = ares_parse_aaaa_reply(abuf, alen, &host);
-#if 0
           if (host && channel->nsort)
-            sort_addresses(host, channel->sortlist, channel->nsort);
-#endif
+            sort6_addresses(host, channel->sortlist, channel->nsort);
         }
       end_hquery(hquery, status, host);
     }
@@ -331,12 +333,66 @@ static int get_address_index(struct in_addr *addr, struct apattern *sortlist,
 
   for (i = 0; i < nsort; i++)
     {
-      if (sortlist[i].type = PATTERN_MASK)
-        if ((addr->s_addr & sortlist[i].mask.addr.s_addr) == sortlist[i].addr.s_addr)
-          break;
+      if (sortlist[i].family != AF_INET)
+        continue;
+      if (sortlist[i].type == PATTERN_MASK)
+        {
+          if ((addr->s_addr & sortlist[i].mask.addr.addr4.s_addr) 
+              == sortlist[i].addr.addr4.s_addr)
+            break;
+        }
       else
-        if (!ares_bitncmp(&addr->s_addr, &sortlist[i].addr.s_addr, sortlist[i].mask.bits))
+        {
+          if (!ares_bitncmp(&addr->s_addr, &sortlist[i].addr.addr4.s_addr, 
+                            sortlist[i].mask.bits))
+            break;
+        }
+    }
+  return i;
+}
+
+static void sort6_addresses(struct hostent *host, struct apattern *sortlist,
+                           int nsort)
+{
+  struct in6_addr a1, a2;
+  int i1, i2, ind1, ind2;
+
+  /* This is a simple insertion sort, not optimized at all.  i1 walks
+   * through the address list, with the loop invariant that everything
+   * to the left of i1 is sorted.  In the loop body, the value at i1 is moved
+   * back through the list (via i2) until it is in sorted order.
+   */
+  for (i1 = 0; host->h_addr_list[i1]; i1++)
+    {
+      memcpy(&a1, host->h_addr_list[i1], sizeof(struct in6_addr));
+      ind1 = get6_address_index(&a1, sortlist, nsort);
+      for (i2 = i1 - 1; i2 >= 0; i2--)
+        {
+          memcpy(&a2, host->h_addr_list[i2], sizeof(struct in6_addr));
+          ind2 = get6_address_index(&a2, sortlist, nsort);
+          if (ind2 <= ind1)
+            break;
+          memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct in6_addr));
+        }
+      memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct in6_addr));
+    }
+}
+
+/* Find the first entry in sortlist which matches addr.  Return nsort
+ * if none of them match.
+ */
+static int get6_address_index(struct in6_addr *addr, struct apattern *sortlist,
+                             int nsort)
+{
+  int i;
+
+  for (i = 0; i < nsort; i++)
+    {
+      if (sortlist[i].family != AF_INET6)
+        continue;
+        if (!ares_bitncmp(&addr->s6_addr, &sortlist[i].addr.addr6.s6_addr, sortlist[i].mask.bits))
           break;
     }
   return i;
 }
+
index 980e3d1..c72033b 100644 (file)
@@ -830,7 +830,7 @@ static int config_nameserver(struct server_state **servers, int *nservers,
 static int config_sortlist(struct apattern **sortlist, int *nsort,
                            const char *str)
 {
-  struct apattern pat, *newsort;
+  struct apattern pat;
   const char *q;
 
   /* Add sortlist entries. */
@@ -857,26 +857,39 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
       else
         ipbufpfx[0] = 0;
       /* Lets see if it is CIDR */
+      /* First we'll try IPv6 */
+      if ((bits = ares_inet_net_pton(AF_INET6, ipbufpfx ? ipbufpfx : ipbuf, &pat.addr.addr6, 
+                                     sizeof(pat.addr.addr6))) > 0)
+        {
+          pat.type = PATTERN_CIDR;
+          pat.mask.bits = bits;
+          pat.family = AF_INET6;
+          if (!sortlist_alloc(sortlist, nsort, &pat))
+            return ARES_ENOMEM;
+        }
       if (ipbufpfx && 
-          (bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addr, sizeof(pat.addr))) > 0)
+          (bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addr.addr4, 
+                                     sizeof(pat.addr.addr4))) > 0)
         {
           pat.type = PATTERN_CIDR;
           pat.mask.bits = bits;
+          pat.family = AF_INET;
           if (!sortlist_alloc(sortlist, nsort, &pat))
             return ARES_ENOMEM;
         }
       /* See if it is just a regular IP */
-      else if (ip_addr(ipbuf, (int)(q-str), &pat.addr) == 0)
+      else if (ip_addr(ipbuf, (int)(q-str), &pat.addr.addr4) == 0)
         {
           if (ipbufpfx)
             {
               memcpy(ipbuf, str, (int)(q-str));
               ipbuf[(int)(q-str)] = 0;
-              if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr) != 0)
+              if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr.addr4) != 0)
                 natural_mask(&pat);
             }
           else
             natural_mask(&pat);
+          pat.family = AF_INET;
          pat.type = PATTERN_MASK;
           if (!sortlist_alloc(sortlist, nsort, &pat))
             return ARES_ENOMEM;
@@ -1030,16 +1043,16 @@ static void natural_mask(struct apattern *pat)
   /* Store a host-byte-order copy of pat in a struct in_addr.  Icky,
    * but portable.
    */
-  addr.s_addr = ntohl(pat->addr.s_addr);
+  addr.s_addr = ntohl(pat->addr.addr4.s_addr);
 
   /* This is out of date in the CIDR world, but some people might
    * still rely on it.
    */
   if (IN_CLASSA(addr.s_addr))
-    pat->mask.addr.s_addr = htonl(IN_CLASSA_NET);
+    pat->mask.addr.addr4.s_addr = htonl(IN_CLASSA_NET);
   else if (IN_CLASSB(addr.s_addr))
-    pat->mask.addr.s_addr = htonl(IN_CLASSB_NET);
+    pat->mask.addr.addr4.s_addr = htonl(IN_CLASSB_NET);
   else
-    pat->mask.addr.s_addr = htonl(IN_CLASSC_NET);
+    pat->mask.addr.addr4.s_addr = htonl(IN_CLASSC_NET);
 }
 #endif
index 723afb3..bcf2e8e 100644 (file)
@@ -127,13 +127,19 @@ struct query {
 #define PATTERN_MASK 0x1
 #define PATTERN_CIDR 0x2
 
+union ares_addr {
+  struct in_addr addr4;
+  struct in6_addr addr6;
+};
+
 struct apattern {
-  struct in_addr addr;
+  union ares_addr addr;
   union
   {
-    struct in_addr addr;
+    union ares_addr addr;
     unsigned short bits;
   } mask;
+  int family;
   unsigned short type;
 };