compiler warning fix
[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 #include <sys/types.h>
19
20 #if defined(WIN32) && !defined(WATT32)
21 #include "nameser.h"
22 #else
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netdb.h>
26 #include <arpa/nameser.h>
27 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
28 #include <arpa/nameser_compat.h>
29 #endif
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "ares.h"
37 #include "ares_private.h"
38 #include "inet_net_pton.h"
39
40 #ifdef WATT32
41 #undef WIN32
42 #endif
43
44 struct addr_query {
45   /* Arguments passed to ares_gethostbyaddr() */
46   ares_channel channel;
47   union ares_addr addr;
48   int family;
49   ares_host_callback callback;
50   void *arg;
51
52   const char *remaining_lookups;
53 };
54
55 static void next_lookup(struct addr_query *aquery);
56 static void addr_callback(void *arg, int status, unsigned char *abuf,
57                           int alen);
58 static void end_aquery(struct addr_query *aquery, int status,
59                        struct hostent *host);
60 static int file_lookup(union ares_addr *addr, int family, struct hostent **host);
61
62 void ares_gethostbyaddr(ares_channel channel, const void *addr, int addrlen,
63                         int family, ares_host_callback callback, void *arg)
64 {
65   struct addr_query *aquery;
66
67   if (family != AF_INET && family != AF_INET6)
68     {
69       callback(arg, ARES_ENOTIMP, NULL);
70       return;
71     }
72
73   if ((family == AF_INET && addrlen != sizeof(struct in_addr)) ||
74       (family == AF_INET6 && addrlen != sizeof(struct in6_addr)))
75     {
76       callback(arg, ARES_ENOTIMP, NULL);
77       return;
78     }
79
80   aquery = malloc(sizeof(struct addr_query));
81   if (!aquery)
82     {
83       callback(arg, ARES_ENOMEM, NULL);
84       return;
85     }
86   aquery->channel = channel;
87   if (family == AF_INET)
88     memcpy(&aquery->addr.addr4, addr, sizeof(struct in_addr));
89   else
90     memcpy(&aquery->addr.addr6, addr, sizeof(struct in6_addr));
91   aquery->family = family;
92   aquery->callback = callback;
93   aquery->arg = arg;
94   aquery->remaining_lookups = channel->lookups;
95
96   next_lookup(aquery);
97 }
98
99 static void next_lookup(struct addr_query *aquery)
100 {
101   const char *p;
102   char name[128];
103   int a1, a2, a3, a4, status;
104   struct hostent *host;
105   unsigned long addr;
106
107   for (p = aquery->remaining_lookups; *p; p++)
108     {
109       switch (*p)
110         {
111         case 'b':
112           if (aquery->family == AF_INET)
113             {
114               addr = ntohl(aquery->addr.addr4.s_addr);
115               a1 = (int)((addr >> 24) & 0xff);
116               a2 = (int)((addr >> 16) & 0xff);
117               a3 = (int)((addr >> 8) & 0xff);
118               a4 = (int)(addr & 0xff);
119               sprintf(name, "%d.%d.%d.%d.in-addr.arpa", a4, a3, a2, a1);
120               aquery->remaining_lookups = p + 1;
121               ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback,
122                          aquery);
123             }
124           else
125             {
126               unsigned char *bytes;
127               bytes = (unsigned char *)&aquery->addr.addr6.s6_addr;
128               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",
129                       bytes[15]&0xf, bytes[15] >> 4, bytes[14]&0xf, bytes[14] >> 4,
130                       bytes[13]&0xf, bytes[13] >> 4, bytes[12]&0xf, bytes[12] >> 4,
131                       bytes[11]&0xf, bytes[11] >> 4, bytes[10]&0xf, bytes[10] >> 4,
132                       bytes[9]&0xf, bytes[9] >> 4, bytes[8]&0xf, bytes[8] >> 4,
133                       bytes[7]&0xf, bytes[7] >> 4, bytes[6]&0xf, bytes[6] >> 4,
134                       bytes[5]&0xf, bytes[5] >> 4, bytes[4]&0xf, bytes[4] >> 4,
135                       bytes[3]&0xf, bytes[3] >> 4, bytes[2]&0xf, bytes[2] >> 4,
136                       bytes[1]&0xf, bytes[1] >> 4, bytes[0]&0xf, bytes[0] >> 4);
137               aquery->remaining_lookups = p + 1;
138               ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback,
139                          aquery);
140             }
141           return;
142         case 'f':
143           status = file_lookup(&aquery->addr, aquery->family, &host);
144           if (status != ARES_ENOTFOUND)
145             {
146               end_aquery(aquery, status, host);
147               return;
148             }
149           break;
150         }
151     }
152   end_aquery(aquery, ARES_ENOTFOUND, NULL);
153 }
154
155 static void addr_callback(void *arg, int status, unsigned char *abuf, int alen)
156 {
157   struct addr_query *aquery = (struct addr_query *) arg;
158   struct hostent *host;
159
160   if (status == ARES_SUCCESS)
161     {
162       if (aquery->family == AF_INET)
163         status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr4,
164                                       sizeof(struct in_addr), AF_INET, &host);
165       else
166         status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr6,
167                                       sizeof(struct in6_addr), AF_INET6, &host);
168       end_aquery(aquery, status, host);
169     }
170   else if (status == ARES_EDESTRUCTION)
171     end_aquery(aquery, status, NULL);
172   else
173     next_lookup(aquery);
174 }
175
176 static void end_aquery(struct addr_query *aquery, int status,
177                        struct hostent *host)
178 {
179   aquery->callback(aquery->arg, status, host);
180   if (host)
181     ares_free_hostent(host);
182   free(aquery);
183 }
184
185 static int file_lookup(union ares_addr *addr, int family, struct hostent **host)
186 {
187   FILE *fp;
188   int status;
189
190 #ifdef WIN32
191   int error;
192   char PATH_HOSTS[MAX_PATH];
193   if (IS_NT()) {
194     char tmp[MAX_PATH];
195     HKEY hkeyHosts;
196
197     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hkeyHosts)
198         == ERROR_SUCCESS)
199     {
200       DWORD dwLength = MAX_PATH;
201       RegQueryValueEx(hkeyHosts, DATABASEPATH, NULL, NULL, (LPBYTE)tmp,
202                       &dwLength);
203       ExpandEnvironmentStrings(tmp, PATH_HOSTS, MAX_PATH);
204       RegCloseKey(hkeyHosts);
205     }
206   }
207   else
208     GetWindowsDirectory(PATH_HOSTS, MAX_PATH);
209
210   strcat(PATH_HOSTS, WIN_PATH_HOSTS);
211
212 #elif defined(WATT32)
213   extern const char *_w32_GetHostsFile (void);
214   const char *PATH_HOSTS = _w32_GetHostsFile();
215
216   if (!PATH_HOSTS)
217     return ARES_ENOTFOUND;
218 #endif
219
220   fp = fopen(PATH_HOSTS, "r");
221   if (!fp)
222     {
223       error = ERRNO;
224       switch(error) 
225         {
226         case ENOENT:
227           return ARES_ENOTFOUND;
228         default:
229           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
230                          error, strerror(error)));
231           DEBUGF(fprintf(stderr, "Error opening file: %s\n", 
232                          PATH_HOSTS));
233           *host = NULL;
234           return ARES_EFILE;
235         }
236     }
237   while ((status = ares__get_hostent(fp, family, host)) == ARES_SUCCESS)
238     {
239       if (family != (*host)->h_addrtype)
240         {
241           ares_free_hostent(*host);
242           continue;
243         }
244       if (family == AF_INET)
245         {
246           if (memcmp((*host)->h_addr, &addr->addr4, sizeof(struct in_addr)) == 0)
247             break;
248         }
249       else if (family == AF_INET6)
250         {
251           if (memcmp((*host)->h_addr, &addr->addr6, sizeof(struct in6_addr)) == 0)
252             break;
253         }
254       ares_free_hostent(*host);
255     }
256   fclose(fp);
257   if (status == ARES_EOF)
258     status = ARES_ENOTFOUND;
259   if (status != ARES_SUCCESS)
260     *host = NULL;
261   return status;
262 }