Commit ea03ad3b authored by Dominick Meglio's avatar Dominick Meglio
Browse files

Made sortlist support IPv6 (this can probably use some testing)

parent feec4217
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
+0 −5
Original line number Diff line number Diff line
@@ -39,11 +39,6 @@
#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;
+64 −8
Original line number Diff line number Diff line
@@ -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)
      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;
}
+21 −8
Original line number Diff line number Diff line
@@ -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
+8 −2
Original line number Diff line number Diff line
@@ -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;
};