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