aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ares/CHANGES4
-rw-r--r--ares/ares_gethostbyname.c12
-rw-r--r--ares/ares_init.c77
-rw-r--r--ares/ares_private.h10
-rw-r--r--ares/bitncmp.c1
5 files changed, 77 insertions, 27 deletions
diff --git a/ares/CHANGES b/ares/CHANGES
index a435502f9..6f8ce3045 100644
--- a/ares/CHANGES
+++ b/ares/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
diff --git a/ares/ares_gethostbyname.c b/ares/ares_gethostbyname.c
index 92dc0c72d..afd4c715e 100644
--- a/ares/ares_gethostbyname.c
+++ b/ares/ares_gethostbyname.c
@@ -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;
}
diff --git a/ares/ares_init.c b/ares/ares_init.c
index c9d1cd218..980e3d14e 100644
--- a/ares/ares_init.c
+++ b/ares/ares_init.c
@@ -27,6 +27,10 @@
#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
diff --git a/ares/ares_private.h b/ares/ares_private.h
index cf67e192d..723afb387 100644
--- a/ares/ares_private.h
+++ b/ares/ares_private.h
@@ -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 {
diff --git a/ares/bitncmp.c b/ares/bitncmp.c
index 32b70a96a..3986dc6c8 100644
--- a/ares/bitncmp.c
+++ b/ares/bitncmp.c
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <string.h>
+#include <stdlib.h>
#include "bitncmp.h"
/*