Made ares_gethostbyaddr support IPv6 by specifying AF_INET6 as the family
authorDominick Meglio <dcm5151@esu.edu>
Fri, 8 Apr 2005 15:41:31 +0000 (15:41 +0000)
committerDominick Meglio <dcm5151@esu.edu>
Fri, 8 Apr 2005 15:41:31 +0000 (15:41 +0000)
CHANGES
ares__get_hostent.c
ares_gethostbyaddr.c
ares_gethostbyname.c
ares_private.h

diff --git a/CHANGES b/CHANGES
index a2207cb..c61759c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,13 @@
   Changelog for the c-ares project
 
+* April 8
+
+- 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.
+
 * April 7
+
 - Tupone Alfredo fixed includes of arpa/nameser_compat.h to build fine on Mac
   OS X.
 
index 0b04342..29df0dd 100644 (file)
 #include "ares.h"
 #include "ares_private.h"
 
-int ares__get_hostent(FILE *fp, struct hostent **host)
+int ares__get_hostent(FILE *fp, int family, struct hostent **host)
 {
   char *line = NULL, *p, *q, *canonical, **alias;
   int status, linesize, end_at_hostname, naliases;
   struct in_addr addr;
+  struct in6_addr addr6;
+  int addrlen = sizeof(struct in_addr);
   struct hostent *hostent = NULL;
 
   while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
@@ -56,6 +58,17 @@ int ares__get_hostent(FILE *fp, struct hostent **host)
       *p = 0;
       addr.s_addr = inet_addr(line);
       if (addr.s_addr == INADDR_NONE)
+       {
+          if (ares_inet_pton(AF_INET6, line, &addr6) > 0)
+            {
+              if (family != AF_INET6)
+                continue;
+              addrlen = sizeof(struct in6_addr);
+            }
+          else
+            continue;
+       }
+      else if (family != AF_INET)
         continue;
 
       /* Get the canonical hostname. */
@@ -100,7 +113,7 @@ int ares__get_hostent(FILE *fp, struct hostent **host)
       hostent->h_addr_list = malloc(2 * sizeof(char *));
       if (!hostent->h_addr_list)
         break;
-      hostent->h_addr_list[0] = malloc(sizeof(struct in_addr));
+      hostent->h_addr_list[0] = malloc(addrlen);
       if (!hostent->h_addr_list[0])
         break;
       hostent->h_aliases = malloc((naliases + 1) * sizeof(char *));
@@ -134,9 +147,12 @@ int ares__get_hostent(FILE *fp, struct hostent **host)
         }
       hostent->h_aliases[naliases] = NULL;
 
-      hostent->h_addrtype = AF_INET;
-      hostent->h_length = sizeof(struct in_addr);
-      memcpy(hostent->h_addr_list[0], &addr, sizeof(struct in_addr));
+      hostent->h_addrtype = family;
+      hostent->h_length = addrlen;
+      if (family == AF_INET)
+        memcpy(hostent->h_addr_list[0], &addr, addrlen);
+      else if (family == AF_INET6)
+        memcpy(hostent->h_addr_list[0], &addr6, addrlen);
       hostent->h_addr_list[1] = NULL;
       *host = hostent;
       free(line);
index 09e0dd3..55f7aa9 100644 (file)
@@ -12,7 +12,6 @@
  * this software for any purpose.  It is provided "as is"
  * without express or implied warranty.
  */
-
 #include "setup.h"
 #include <sys/types.h>
 
 #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;
-  struct in_addr addr;
+  union ares_addr addr;
+  int family;
   ares_host_callback callback;
   void *arg;
 
@@ -54,14 +59,21 @@ static void addr_callback(void *arg, int status, unsigned char *abuf,
                           int alen);
 static void end_aquery(struct addr_query *aquery, int status,
                        struct hostent *host);
-static int file_lookup(struct in_addr *addr, struct hostent **host);
+static int file_lookup(union ares_addr *addr, int family, struct hostent **host);
 
 void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
                         int family, ares_host_callback callback, void *arg)
 {
   struct addr_query *aquery;
 
-  if (family != AF_INET || addrlen != sizeof(struct in_addr))
+  if (family != AF_INET && family != AF_INET6)
+    {
+      callback(arg, ARES_ENOTIMP, NULL);
+      return;
+    }
+
+  if ((family == AF_INET && addrlen != sizeof(struct in_addr)) || 
+      (family == AF_INET6 && addrlen != sizeof(struct in6_addr)))
     {
       callback(arg, ARES_ENOTIMP, NULL);
       return;
@@ -74,7 +86,11 @@ void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
       return;
     }
   aquery->channel = channel;
-  memcpy(&aquery->addr, addr, sizeof(aquery->addr));
+  if (family == AF_INET)
+    memcpy(&aquery->addr.addr4, addr, sizeof(struct in_addr));
+  else
+    memcpy(&aquery->addr.addr6, addr, sizeof(struct in6_addr));
+  aquery->family = family;
   aquery->callback = callback;
   aquery->arg = arg;
   aquery->remaining_lookups = channel->lookups;
@@ -85,7 +101,7 @@ void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
 static void next_lookup(struct addr_query *aquery)
 {
   const char *p;
-  char name[64];
+  char name[128];
   int a1, a2, a3, a4, status;
   struct hostent *host;
   unsigned long addr;
@@ -95,18 +111,38 @@ static void next_lookup(struct addr_query *aquery)
       switch (*p)
         {
         case 'b':
-          addr = ntohl(aquery->addr.s_addr);
-          a1 = (int)((addr >> 24) & 0xff);
-          a2 = (int)((addr >> 16) & 0xff);
-          a3 = (int)((addr >> 8) & 0xff);
-          a4 = (int)(addr & 0xff);
-          sprintf(name, "%d.%d.%d.%d.in-addr.arpa", a4, a3, a2, a1);
-          aquery->remaining_lookups = p + 1;
-          ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback,
-                     aquery);
+         if (aquery->family == AF_INET)
+            {
+              addr = ntohl(aquery->addr.addr4.s_addr);
+              a1 = (int)((addr >> 24) & 0xff);
+              a2 = (int)((addr >> 16) & 0xff);
+              a3 = (int)((addr >> 8) & 0xff);
+              a4 = (int)(addr & 0xff);
+              sprintf(name, "%d.%d.%d.%d.in-addr.arpa", a4, a3, a2, a1);
+              aquery->remaining_lookups = p + 1;
+              ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback,
+                         aquery);
+            }
+          else
+            {
+              unsigned char *bytes;
+              bytes = (unsigned char *)&aquery->addr.addr6.s6_addr;
+              sprintf(name, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
+                      bytes[15]&0xf, bytes[15] >> 4, bytes[14]&0xf, bytes[14] >> 4,
+                      bytes[13]&0xf, bytes[13] >> 4, bytes[12]&0xf, bytes[12] >> 4,
+                      bytes[11]&0xf, bytes[11] >> 4, bytes[10]&0xf, bytes[10] >> 4,
+                      bytes[9]&0xf, bytes[9] >> 4, bytes[8]&0xf, bytes[8] >> 4,
+                      bytes[7]&0xf, bytes[7] >> 4, bytes[6]&0xf, bytes[6] >> 4,
+                      bytes[5]&0xf, bytes[5] >> 4, bytes[4]&0xf, bytes[4] >> 4,
+                      bytes[3]&0xf, bytes[3] >> 4, bytes[2]&0xf, bytes[2] >> 4,
+                      bytes[1]&0xf, bytes[1] >> 4, bytes[0]&0xf, bytes[0] >> 4);
+              aquery->remaining_lookups = p + 1;
+              ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback,
+                         aquery);
+            }
           return;
         case 'f':
-          status = file_lookup(&aquery->addr, &host);
+          status = file_lookup(&aquery->addr, aquery->family, &host);
           if (status != ARES_ENOTFOUND)
             {
               end_aquery(aquery, status, host);
@@ -125,8 +161,12 @@ static void addr_callback(void *arg, int status, unsigned char *abuf, int alen)
 
   if (status == ARES_SUCCESS)
     {
-      status = ares_parse_ptr_reply(abuf, alen, &aquery->addr,
-                                    sizeof(struct in_addr), AF_INET, &host);
+      if (aquery->family == AF_INET)
+        status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr4,
+                                      sizeof(struct in_addr), AF_INET, &host);
+      else
+        status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr6,
+                                      sizeof(struct in6_addr), AF_INET6, &host);
       end_aquery(aquery, status, host);
     }
   else if (status == ARES_EDESTRUCTION)
@@ -144,7 +184,7 @@ static void end_aquery(struct addr_query *aquery, int status,
   free(aquery);
 }
 
-static int file_lookup(struct in_addr *addr, struct hostent **host)
+static int file_lookup(union ares_addr *addr, int family, struct hostent **host)
 {
   FILE *fp;
   int status;
@@ -181,11 +221,23 @@ static int file_lookup(struct in_addr *addr, struct hostent **host)
   fp = fopen(PATH_HOSTS, "r");
   if (!fp)
     return ARES_ENOTFOUND;
-
-  while ((status = ares__get_hostent(fp, host)) == ARES_SUCCESS)
+  while ((status = ares__get_hostent(fp, family, host)) == ARES_SUCCESS)
     {
-      if (memcmp((*host)->h_addr, addr, sizeof(struct in_addr)) == 0)
-        break;
+      if (family != (*host)->h_addrtype)
+        {
+          ares_free_hostent(*host);
+          continue;
+        }
+      if (family == AF_INET)
+        {
+          if (memcmp((*host)->h_addr, &addr->addr4, sizeof(struct in_addr)) == 0)
+            break;
+        }
+      else if (family == AF_INET6)
+        {
+          if (memcmp((*host)->h_addr, &addr->addr6, sizeof(struct in6_addr)) == 0)
+            break;
+        }
       ares_free_hostent(*host);
     }
   fclose(fp);
index 8d77fde..2950d80 100644 (file)
@@ -255,7 +255,7 @@ static int file_lookup(const char *name, struct hostent **host)
   if (!fp)
     return ARES_ENOTFOUND;
 
-  while ((status = ares__get_hostent(fp, host)) == ARES_SUCCESS)
+  while ((status = ares__get_hostent(fp, AF_INET, host)) == ARES_SUCCESS)
     {
       if (strcasecmp((*host)->h_name, name) == 0)
         break;
index 95bba1a..cf67e19 100644 (file)
@@ -156,7 +156,7 @@ struct ares_channeldata {
 
 void ares__send_query(ares_channel channel, struct query *query, time_t now);
 void ares__close_sockets(struct server_state *server);
-int ares__get_hostent(FILE *fp, struct hostent **host);
+int ares__get_hostent(FILE *fp, int family, struct hostent **host);
 int ares__read_line(FILE *fp, char **buf, int *bufsize);
 
 #ifdef CURLDEBUG