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