Home | History | Annotate | Download | only in c-ares
      1 
      2 /* Copyright 1998 by the Massachusetts Institute of Technology.
      3  *
      4  * Permission to use, copy, modify, and distribute this
      5  * software and its documentation for any purpose and without
      6  * fee is hereby granted, provided that the above copyright
      7  * notice appear in all copies and that both that copyright
      8  * notice and this permission notice appear in supporting
      9  * documentation, and that the name of M.I.T. not be used in
     10  * advertising or publicity pertaining to distribution of the
     11  * software without specific, written prior permission.
     12  * M.I.T. makes no representations about the suitability of
     13  * this software for any purpose.  It is provided "as is"
     14  * without express or implied warranty.
     15  */
     16 #include "ares_setup.h"
     17 
     18 #ifdef HAVE_SYS_SOCKET_H
     19 #  include <sys/socket.h>
     20 #endif
     21 #ifdef HAVE_NETINET_IN_H
     22 #  include <netinet/in.h>
     23 #endif
     24 #ifdef HAVE_NETDB_H
     25 #  include <netdb.h>
     26 #endif
     27 #ifdef HAVE_ARPA_INET_H
     28 #  include <arpa/inet.h>
     29 #endif
     30 #ifdef HAVE_ARPA_NAMESER_H
     31 #  include <arpa/nameser.h>
     32 #else
     33 #  include "nameser.h"
     34 #endif
     35 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
     36 #  include <arpa/nameser_compat.h>
     37 #endif
     38 
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 
     43 #include "ares.h"
     44 #include "inet_net_pton.h"
     45 #include "ares_platform.h"
     46 #include "ares_private.h"
     47 
     48 #ifdef WATT32
     49 #undef WIN32
     50 #endif
     51 
     52 struct addr_query {
     53   /* Arguments passed to ares_gethostbyaddr() */
     54   ares_channel channel;
     55   struct ares_addr addr;
     56   ares_host_callback callback;
     57   void *arg;
     58 
     59   const char *remaining_lookups;
     60   int timeouts;
     61 };
     62 
     63 static void next_lookup(struct addr_query *aquery);
     64 static void addr_callback(void *arg, int status, int timeouts,
     65                           unsigned char *abuf, int alen);
     66 static void end_aquery(struct addr_query *aquery, int status,
     67                        struct hostent *host);
     68 static int file_lookup(struct ares_addr *addr, struct hostent **host);
     69 static void ptr_rr_name(char *name, const struct ares_addr *addr);
     70 
     71 void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
     72                         int family, ares_host_callback callback, void *arg)
     73 {
     74   struct addr_query *aquery;
     75 
     76   if (family != AF_INET && family != AF_INET6)
     77     {
     78       callback(arg, ARES_ENOTIMP, 0, NULL);
     79       return;
     80     }
     81 
     82   if ((family == AF_INET && addrlen != sizeof(aquery->addr.addrV4)) ||
     83       (family == AF_INET6 && addrlen != sizeof(aquery->addr.addrV6)))
     84     {
     85       callback(arg, ARES_ENOTIMP, 0, NULL);
     86       return;
     87     }
     88 
     89   aquery = malloc(sizeof(struct addr_query));
     90   if (!aquery)
     91     {
     92       callback(arg, ARES_ENOMEM, 0, NULL);
     93       return;
     94     }
     95   aquery->channel = channel;
     96   if (family == AF_INET)
     97     memcpy(&aquery->addr.addrV4, addr, sizeof(aquery->addr.addrV4));
     98   else
     99     memcpy(&aquery->addr.addrV6, addr, sizeof(aquery->addr.addrV6));
    100   aquery->addr.family = family;
    101   aquery->callback = callback;
    102   aquery->arg = arg;
    103   aquery->remaining_lookups = channel->lookups;
    104   aquery->timeouts = 0;
    105 
    106   next_lookup(aquery);
    107 }
    108 
    109 static void next_lookup(struct addr_query *aquery)
    110 {
    111   const char *p;
    112   char name[128];
    113   int status;
    114   struct hostent *host;
    115 
    116   for (p = aquery->remaining_lookups; *p; p++)
    117     {
    118       switch (*p)
    119         {
    120         case 'b':
    121           ptr_rr_name(name, &aquery->addr);
    122           aquery->remaining_lookups = p + 1;
    123           ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback,
    124                      aquery);
    125           return;
    126         case 'f':
    127           status = file_lookup(&aquery->addr, &host);
    128 
    129           /* this status check below previously checked for !ARES_ENOTFOUND,
    130              but we should not assume that this single error code is the one
    131              that can occur, as that is in fact no longer the case */
    132           if (status == ARES_SUCCESS)
    133             {
    134               end_aquery(aquery, status, host);
    135               return;
    136             }
    137           break;
    138         }
    139     }
    140   end_aquery(aquery, ARES_ENOTFOUND, NULL);
    141 }
    142 
    143 static void addr_callback(void *arg, int status, int timeouts,
    144                           unsigned char *abuf, int alen)
    145 {
    146   struct addr_query *aquery = (struct addr_query *) arg;
    147   struct hostent *host;
    148   size_t addrlen;
    149 
    150   aquery->timeouts += timeouts;
    151   if (status == ARES_SUCCESS)
    152     {
    153       if (aquery->addr.family == AF_INET)
    154         {
    155           addrlen = sizeof(aquery->addr.addrV4);
    156           status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV4,
    157                                         (int)addrlen, AF_INET, &host);
    158         }
    159       else
    160         {
    161           addrlen = sizeof(aquery->addr.addrV6);
    162           status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addrV6,
    163                                         (int)addrlen, AF_INET6, &host);
    164         }
    165       end_aquery(aquery, status, host);
    166     }
    167   else if (status == ARES_EDESTRUCTION)
    168     end_aquery(aquery, status, NULL);
    169   else
    170     next_lookup(aquery);
    171 }
    172 
    173 static void end_aquery(struct addr_query *aquery, int status,
    174                        struct hostent *host)
    175 {
    176   aquery->callback(aquery->arg, status, aquery->timeouts, host);
    177   if (host)
    178     ares_free_hostent(host);
    179   free(aquery);
    180 }
    181 
    182 static int file_lookup(struct ares_addr *addr, struct hostent **host)
    183 {
    184   FILE *fp;
    185   int status;
    186   int error;
    187 
    188 #ifdef WIN32
    189   char PATH_HOSTS[MAX_PATH];
    190   win_platform platform;
    191 
    192   PATH_HOSTS[0] = '\0';
    193 
    194   platform = ares__getplatform();
    195 
    196   if (platform == WIN_NT) {
    197     char tmp[MAX_PATH];
    198     HKEY hkeyHosts;
    199 
    200     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ,
    201                      &hkeyHosts) == ERROR_SUCCESS)
    202     {
    203       DWORD dwLength = MAX_PATH;
    204       RegQueryValueEx(hkeyHosts, DATABASEPATH, NULL, NULL, (LPBYTE)tmp,
    205                       &dwLength);
    206       ExpandEnvironmentStrings(tmp, PATH_HOSTS, MAX_PATH);
    207       RegCloseKey(hkeyHosts);
    208     }
    209   }
    210   else if (platform == WIN_9X)
    211     GetWindowsDirectory(PATH_HOSTS, MAX_PATH);
    212   else
    213     return ARES_ENOTFOUND;
    214 
    215   strcat(PATH_HOSTS, WIN_PATH_HOSTS);
    216 
    217 #elif defined(WATT32)
    218   extern const char *_w32_GetHostsFile (void);
    219   const char *PATH_HOSTS = _w32_GetHostsFile();
    220 
    221   if (!PATH_HOSTS)
    222     return ARES_ENOTFOUND;
    223 #endif
    224 
    225   fp = fopen(PATH_HOSTS, "r");
    226   if (!fp)
    227     {
    228       error = ERRNO;
    229       switch(error)
    230         {
    231         case ENOENT:
    232         case ESRCH:
    233           return ARES_ENOTFOUND;
    234         default:
    235           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
    236                          error, strerror(error)));
    237           DEBUGF(fprintf(stderr, "Error opening file: %s\n",
    238                          PATH_HOSTS));
    239           *host = NULL;
    240           return ARES_EFILE;
    241         }
    242     }
    243   while ((status = ares__get_hostent(fp, addr->family, host)) == ARES_SUCCESS)
    244     {
    245       if (addr->family != (*host)->h_addrtype)
    246         {
    247           ares_free_hostent(*host);
    248           continue;
    249         }
    250       if (addr->family == AF_INET)
    251         {
    252           if (memcmp((*host)->h_addr, &addr->addrV4,
    253                      sizeof(addr->addrV4)) == 0)
    254             break;
    255         }
    256       else if (addr->family == AF_INET6)
    257         {
    258           if (memcmp((*host)->h_addr, &addr->addrV6,
    259                      sizeof(addr->addrV6)) == 0)
    260             break;
    261         }
    262       ares_free_hostent(*host);
    263     }
    264   fclose(fp);
    265   if (status == ARES_EOF)
    266     status = ARES_ENOTFOUND;
    267   if (status != ARES_SUCCESS)
    268     *host = NULL;
    269   return status;
    270 }
    271 
    272 static void ptr_rr_name(char *name, const struct ares_addr *addr)
    273 {
    274   if (addr->family == AF_INET)
    275     {
    276        unsigned long laddr = ntohl(addr->addrV4.s_addr);
    277        unsigned long a1 = (laddr >> 24UL) & 0xFFUL;
    278        unsigned long a2 = (laddr >> 16UL) & 0xFFUL;
    279        unsigned long a3 = (laddr >>  8UL) & 0xFFUL;
    280        unsigned long a4 = laddr & 0xFFUL;
    281        sprintf(name, "%lu.%lu.%lu.%lu.in-addr.arpa", a4, a3, a2, a1);
    282     }
    283   else
    284     {
    285        unsigned char *bytes = (unsigned char *)&addr->addrV6;
    286        /* There are too many arguments to do this in one line using
    287         * minimally C89-compliant compilers */
    288        sprintf(name,
    289                 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.",
    290                 bytes[15]&0xf, bytes[15] >> 4, bytes[14]&0xf, bytes[14] >> 4,
    291                 bytes[13]&0xf, bytes[13] >> 4, bytes[12]&0xf, bytes[12] >> 4,
    292                 bytes[11]&0xf, bytes[11] >> 4, bytes[10]&0xf, bytes[10] >> 4,
    293                 bytes[9]&0xf, bytes[9] >> 4, bytes[8]&0xf, bytes[8] >> 4);
    294        sprintf(name+strlen(name),
    295                 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
    296                 bytes[7]&0xf, bytes[7] >> 4, bytes[6]&0xf, bytes[6] >> 4,
    297                 bytes[5]&0xf, bytes[5] >> 4, bytes[4]&0xf, bytes[4] >> 4,
    298                 bytes[3]&0xf, bytes[3] >> 4, bytes[2]&0xf, bytes[2] >> 4,
    299                 bytes[1]&0xf, bytes[1] >> 4, bytes[0]&0xf, bytes[0] >> 4);
    300     }
    301 }
    302