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