Made sortlist support CIDR matching for IPv4
authorDominick Meglio <dcm5151@esu.edu>
Sat, 9 Apr 2005 16:49:47 +0000 (16:49 +0000)
committerDominick Meglio <dcm5151@esu.edu>
Sat, 9 Apr 2005 16:49:47 +0000 (16:49 +0000)
CHANGES
ares_gethostbyname.c
ares_init.c
ares_private.h
bitncmp.c

diff --git a/CHANGES b/CHANGES
index a435502..6f8ce30 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
   Changelog for the c-ares project
 
+* April 9
+
+- Made sortlist support CIDR matching for IPv4.
+
 * April 8
 
 - Added preliminary IPv6 support to ares_gethostbyname. Currently, sortlist
index 92dc0c7..afd4c71 100644 (file)
@@ -34,6 +34,7 @@
 #include "ares.h"
 #include "ares_private.h"
 #include "inet_net_pton.h"
+#include "bitncmp.h"
 
 #ifdef WATT32
 #undef WIN32
@@ -189,10 +190,7 @@ static void end_hquery(struct host_query *hquery, int status,
 static int fake_hostent(const char *name, int family, ares_host_callback callback,
                         void *arg)
 {
-  struct in_addr addr;
-  struct in6_addr addr6;
   struct hostent hostent;
-  const char *p;
   char *aliases[1] = { NULL };
   char *addrs[2];
   int result = 0;
@@ -333,8 +331,12 @@ static int get_address_index(struct in_addr *addr, struct apattern *sortlist,
 
   for (i = 0; i < nsort; i++)
     {
-      if ((addr->s_addr & sortlist[i].mask.s_addr) == sortlist[i].addr.s_addr)
-        break;
+      if (sortlist[i].type = PATTERN_MASK)
+        if ((addr->s_addr & sortlist[i].mask.addr.s_addr) == sortlist[i].addr.s_addr)
+          break;
+      else
+        if (!ares_bitncmp(&addr->s_addr, &sortlist[i].addr.s_addr, sortlist[i].mask.bits))
+          break;
     }
   return i;
 }
index c9d1cd2..980e3d1 100644 (file)
 #include <sys/time.h>
 #endif
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -47,6 +51,7 @@
 #include <errno.h>
 #include "ares.h"
 #include "ares_private.h"
+#include "inet_net_pton.h"
 
 #ifdef WATT32
 #undef WIN32  /* Redefined in MingW/MSVC headers */
@@ -63,6 +68,7 @@ static int config_nameserver(struct server_state **servers, int *nservers,
 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 sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat);
 #ifndef WIN32
 static int ip_addr(const char *s, int len, struct in_addr *addr);
 static void natural_mask(struct apattern *pat);
@@ -830,30 +836,50 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
   /* Add sortlist entries. */
   while (*str && *str != ';')
     {
+      int bits;
+      char ipbuf[16], ipbufpfx[32];
+      /* Find just the IP */
       q = str;
       while (*q && *q != '/' && *q != ';' && !isspace((unsigned char)*q))
         q++;
-      if (ip_addr(str, (int)(q - str), &pat.addr) == 0)
+      memcpy(ipbuf, str, (int)(q-str));
+      ipbuf[(int)(q-str)] = 0;      
+      /* Find the prefix */
+      if (*q == '/')
+        {
+          const char *str2 = q+1;
+          while (*q && *q != ';' && !isspace((unsigned char)*q))
+            q++;
+          memcpy(ipbufpfx, str, (int)(q-str));
+          ipbufpfx[(int)(q-str)] = 0;
+          str = str2;
+        }
+      else
+        ipbufpfx[0] = 0;
+      /* Lets see if it is CIDR */
+      if (ipbufpfx && 
+          (bits = ares_inet_net_pton(AF_INET, ipbufpfx, &pat.addr, sizeof(pat.addr))) > 0)
+        {
+          pat.type = PATTERN_CIDR;
+          pat.mask.bits = bits;
+          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)
         {
-          /* We have a pattern address; now determine the mask. */
-          if (*q == '/')
+          if (ipbufpfx)
             {
-              str = q + 1;
-              while (*q && *q != ';' && !isspace((unsigned char)*q))
-                q++;
-              if (ip_addr(str, (int)(q - str), &pat.mask) != 0)
+              memcpy(ipbuf, str, (int)(q-str));
+              ipbuf[(int)(q-str)] = 0;
+              if (ip_addr(ipbuf, (int)(q - str), &pat.mask.addr) != 0)
                 natural_mask(&pat);
             }
           else
             natural_mask(&pat);
-
-          /* Add this pattern to our list. */
-          newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
-          if (!newsort)
+         pat.type = PATTERN_MASK;
+          if (!sortlist_alloc(sortlist, nsort, &pat))
             return ARES_ENOMEM;
-          newsort[*nsort] = pat;
-          *sortlist = newsort;
-          (*nsort)++;
         }
       else
         {
@@ -971,16 +997,25 @@ static const char *try_option(const char *p, const char *q, const char *opt)
   return ((size_t)(q - p) > len && !strncmp(p, opt, len)) ? &p[len] : NULL;
 }
 
+static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat)
+{
+  struct apattern *newsort;
+  newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
+  if (!newsort)
+    return 0;
+  newsort[*nsort] = *pat;
+  *sortlist = newsort;
+  (*nsort)++;
+  return 1;
+}
+
 #ifndef WIN32
-static int ip_addr(const char *s, int len, struct in_addr *addr)
+static int ip_addr(const char *ipbuf, int len, struct in_addr *addr)
 {
-  char ipbuf[16];
 
   /* Four octets and three periods yields at most 15 characters. */
   if (len > 15)
     return -1;
-  memcpy(ipbuf, s, len);
-  ipbuf[len] = 0;
 
   addr->s_addr = inet_addr(ipbuf);
   if (addr->s_addr == INADDR_NONE && strcmp(ipbuf, "255.255.255.255") != 0)
@@ -1001,10 +1036,10 @@ static void natural_mask(struct apattern *pat)
    * still rely on it.
    */
   if (IN_CLASSA(addr.s_addr))
-    pat->mask.s_addr = htonl(IN_CLASSA_NET);
+    pat->mask.addr.s_addr = htonl(IN_CLASSA_NET);
   else if (IN_CLASSB(addr.s_addr))
-    pat->mask.s_addr = htonl(IN_CLASSB_NET);
+    pat->mask.addr.s_addr = htonl(IN_CLASSB_NET);
   else
-    pat->mask.s_addr = htonl(IN_CLASSC_NET);
+    pat->mask.addr.s_addr = htonl(IN_CLASSC_NET);
 }
 #endif
index cf67e19..723afb3 100644 (file)
@@ -124,9 +124,17 @@ struct query {
 };
 
 /* An IP address pattern; matches an IP address X if X & mask == addr */
+#define PATTERN_MASK 0x1
+#define PATTERN_CIDR 0x2
+
 struct apattern {
   struct in_addr addr;
-  struct in_addr mask;
+  union
+  {
+    struct in_addr addr;
+    unsigned short bits;
+  } mask;
+  unsigned short type;
 };
 
 struct ares_channeldata {
index 32b70a9..3986dc6 100644 (file)
--- a/bitncmp.c
+++ b/bitncmp.c
@@ -19,6 +19,7 @@
 
 #include <sys/types.h>
 #include <string.h>
+#include <stdlib.h>
 #include "bitncmp.h"
 
 /*