Added preliminary IPv6 support to ares_gethostbyname
authorDominick Meglio <dcm5151@esu.edu>
Fri, 8 Apr 2005 19:46:46 +0000 (19:46 +0000)
committerDominick Meglio <dcm5151@esu.edu>
Fri, 8 Apr 2005 19:46:46 +0000 (19:46 +0000)
ares/CHANGES
ares/Makefile.inc
ares/ares_gethostbyaddr.c
ares/ares_gethostbyname.c
ares/bitncmp.c [new file with mode: 0644]
ares/bitncmp.h [new file with mode: 0644]
ares/configure.ac

index c61759c..a435502 100644 (file)
@@ -2,6 +2,11 @@
 
 * April 8
 
+- Added preliminary IPv6 support to ares_gethostbyname. Currently, sortlist
+  does not work with IPv6. Also provided an implementation of bitncmp from
+  BIND for systems that do not supply this function. This will be used to add
+  IPv6 support to sortlist.
+
 - Made ares_gethostbyaddr support IPv6 by specifying AF_INET6 as the family.
   The function can lookup IPv6 addresses both from files (/etc/hosts) and
   DNS lookups.
index 5191cfe..d99d6f3 100644 (file)
@@ -4,7 +4,7 @@ ares_gethostbyaddr.c ares_send.c ares__read_line.c ares_gethostbyname.c    \
 ares_strerror.c ares_cancel.c ares_init.c ares_timeout.c ares_destroy.c           \
 ares_mkquery.c ares_version.c ares_expand_name.c ares_parse_a_reply.c     \
 windows_port.c ares_expand_string.c ares_parse_ptr_reply.c                 \
-ares_parse_aaaa_reply.c inet_net_pton.c
+ares_parse_aaaa_reply.c inet_net_pton.c bitncmp.c
 
 HHEADERS = ares.h ares_private.h setup.h ares_dns.h ares_version.h nameser.h \
            inet_net_pton.h
index 55f7aa9..bd63d1a 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "ares.h"
 #include "ares_private.h"
+#include "inet_net_pton.h"
 
 #ifdef WATT32
 #undef WIN32
index 2950d80..92dc0c7 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>
 
@@ -24,9 +24,6 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <arpa/nameser.h>
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-#include <arpa/nameser_compat.h>
-#endif
 #endif
 
 #include <stdio.h>
@@ -36,6 +33,7 @@
 
 #include "ares.h"
 #include "ares_private.h"
+#include "inet_net_pton.h"
 
 #ifdef WATT32
 #undef WIN32
@@ -47,7 +45,7 @@ struct host_query {
   char *name;
   ares_host_callback callback;
   void *arg;
-
+  int family;
   const char *remaining_lookups;
 };
 
@@ -56,9 +54,9 @@ static void host_callback(void *arg, int status, unsigned char *abuf,
                           int alen);
 static void end_hquery(struct host_query *hquery, int status,
                        struct hostent *host);
-static int fake_hostent(const char *name, ares_host_callback callback,
+static int fake_hostent(const char *name, int family, ares_host_callback callback,
                         void *arg);
-static int file_lookup(const char *name, struct hostent **host);
+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 int get_address_index(struct in_addr *addr, struct apattern *sortlist,
@@ -70,13 +68,13 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
   struct host_query *hquery;
 
   /* Right now we only know how to look up Internet addresses. */
-  if (family != AF_INET)
+  if (family != AF_INET && family != AF_INET6)
     {
       callback(arg, ARES_ENOTIMP, NULL);
       return;
     }
 
-  if (fake_hostent(name, callback, arg))
+  if (fake_hostent(name, family, callback, arg))
     return;
 
   /* Allocate and fill in the host query structure. */
@@ -88,6 +86,7 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
     }
   hquery->channel = channel;
   hquery->name = strdup(name);
+  hquery->family = family;
   if (!hquery->name)
     {
       free(hquery);
@@ -115,13 +114,17 @@ static void next_lookup(struct host_query *hquery)
         case 'b':
           /* DNS lookup */
           hquery->remaining_lookups = p + 1;
-          ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
-                      hquery);
+         if (hquery->family == AF_INET6)
+           ares_search(hquery->channel, hquery->name, C_IN, T_AAAA, host_callback,
+                       hquery);
+         else
+            ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
+                        hquery);
           return;
 
         case 'f':
           /* Host file lookup */
-          status = file_lookup(hquery->name, &host);
+          status = file_lookup(hquery->name, hquery->family, &host);
           if (status != ARES_ENOTFOUND)
             {
               end_hquery(hquery, status, host);
@@ -141,11 +144,29 @@ static void host_callback(void *arg, int status, unsigned char *abuf, int alen)
 
   if (status == ARES_SUCCESS)
     {
-      status = ares_parse_a_reply(abuf, alen, &host);
-      if (host && channel->nsort)
-        sort_addresses(host, channel->sortlist, channel->nsort);
+      if (hquery->family == AF_INET)
+        {
+          status = ares_parse_a_reply(abuf, alen, &host);
+          if (host && channel->nsort)
+            sort_addresses(host, channel->sortlist, channel->nsort);
+        }
+      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
+        }
       end_hquery(hquery, status, host);
     }
+  else if (status == ARES_ENODATA && hquery->family == AF_INET6)
+    {
+      /* There was no AAAA now lookup an A */
+      hquery->family = AF_INET;
+      ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
+                  hquery);
+    }      
   else if (status == ARES_EDESTRUCTION)
     end_hquery(hquery, status, NULL);
   else
@@ -165,36 +186,37 @@ static void end_hquery(struct host_query *hquery, int status,
 /* If the name looks like an IP address, fake up a host entry, end the
  * query immediately, and return true.  Otherwise return false.
  */
-static int fake_hostent(const char *name, ares_host_callback callback,
+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;
+  struct in_addr in;
+  struct in6_addr in6;
 
-  /* It only looks like an IP address if it's all numbers and dots. */
-  for (p = name; *p; p++)
-    {
-      if (!isdigit((unsigned char)*p) && *p != '.')
-        return 0;
-    }
+  if (family == AF_INET)
+    result = ((in.s_addr = inet_addr(name)) == INADDR_NONE ? 0 : 1);
+  else if (family == AF_INET6)
+    result = (ares_inet_pton(AF_INET6, name, &in6) < 1 ? 0 : 1);
 
-  /* It also only looks like an IP address if it's non-zero-length and
-   * doesn't end with a dot.
-   */
-  if (p == name || *(p - 1) == '.')
+  if (!result)
     return 0;
 
-  /* It looks like an IP address.  Figure out what IP address it is. */
-  addr.s_addr = inet_addr(name);
-  if (addr.s_addr == INADDR_NONE)
+  if (family == AF_INET)
     {
-      callback(arg, ARES_EBADNAME, NULL);
-      return 1;
+      hostent.h_length = sizeof(struct in_addr);
+      addrs[0] = (char *)&in;
+    }
+  else if (family == AF_INET6)
+    {
+      hostent.h_length = sizeof(struct in6_addr);
+      addrs[0] = (char *)&in6;
     }
-
   /* Duplicate the name, to avoid a constness violation. */
   hostent.h_name = strdup(name);
   if (!hostent.h_name)
@@ -204,11 +226,9 @@ static int fake_hostent(const char *name, ares_host_callback callback,
     }
 
   /* Fill in the rest of the host structure and terminate the query. */
-  addrs[0] = (char *) &addr;
   addrs[1] = NULL;
   hostent.h_aliases = aliases;
-  hostent.h_addrtype = AF_INET;
-  hostent.h_length = sizeof(struct in_addr);
+  hostent.h_addrtype = family;
   hostent.h_addr_list = addrs;
   callback(arg, ARES_SUCCESS, &hostent);
 
@@ -216,7 +236,7 @@ static int fake_hostent(const char *name, ares_host_callback callback,
   return 1;
 }
 
-static int file_lookup(const char *name, struct hostent **host)
+static int file_lookup(const char *name, int family, struct hostent **host)
 {
   FILE *fp;
   char **alias;
@@ -255,7 +275,7 @@ static int file_lookup(const char *name, struct hostent **host)
   if (!fp)
     return ARES_ENOTFOUND;
 
-  while ((status = ares__get_hostent(fp, AF_INET, host)) == ARES_SUCCESS)
+  while ((status = ares__get_hostent(fp, family, host)) == ARES_SUCCESS)
     {
       if (strcasecmp((*host)->h_name, name) == 0)
         break;
diff --git a/ares/bitncmp.c b/ares/bitncmp.c
new file mode 100644 (file)
index 0000000..32b70a9
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HAVE_BITNCMP
+
+#include <sys/types.h>
+#include <string.h>
+#include "bitncmp.h"
+
+/*
+ * int
+ * bitncmp(l, r, n)
+ *     compare bit masks l and r, for n bits.
+ * return:
+ *     -1, 1, or 0 in the libc tradition.
+ * note:
+ *     network byte order assumed.  this means 192.5.5.240/28 has
+ *     0x11110000 in its fourth octet.
+ * author:
+ *     Paul Vixie (ISC), June 1996
+ */
+int
+ares_bitncmp(const void *l, const void *r, int n) {
+       u_int lb, rb;
+       int x, b;
+
+       b = n / 8;
+       x = memcmp(l, r, b);
+       if (x)
+               return (x);
+
+       lb = ((const u_char *)l)[b];
+       rb = ((const u_char *)r)[b];
+       for (b = n % 8; b > 0; b--) {
+               if ((lb & 0x80) != (rb & 0x80)) {
+                       if (lb & 0x80)
+                               return (1);
+                       return (-1);
+               }
+               lb <<= 1;
+               rb <<= 1;
+       }
+       return (0);
+}
+#endif
diff --git a/ares/bitncmp.h b/ares/bitncmp.h
new file mode 100644 (file)
index 0000000..b527e10
--- /dev/null
@@ -0,0 +1,26 @@
+/* $Id$ */
+
+/*
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#ifndef BITNCMP_H
+#define BITNCMP_H
+
+#ifndef HAVE_BITNCMP
+int ares_bitncmp(const void *l, const void *r, int n);
+#else
+#define ares_bitncmp(x,y,z) bitncmp(x,y,z)
+#endif
+
+#endif /* BITNCMP_H */
index 7e97d60..b4774d9 100644 (file)
@@ -232,5 +232,7 @@ AC_CHECK_SIZEOF(struct in_addr, ,
 ]
 )
 
+AC_CHECK_FUNCS(bitncmp)
+
 
 AC_OUTPUT(Makefile)