• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 1998, 2011, 2013 by the Massachusetts Institute of Technology.
2  *
3  * Permission to use, copy, modify, and distribute this
4  * software and its documentation for any purpose and without
5  * fee is hereby granted, provided that the above copyright
6  * notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting
8  * documentation, and that the name of M.I.T. not be used in
9  * advertising or publicity pertaining to distribution of the
10  * software without specific, written prior permission.
11  * M.I.T. makes no representations about the suitability of
12  * this software for any purpose.  It is provided "as is"
13  * without express or implied warranty.
14  */
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 
28 #include "ares_nameser.h"
29 
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 
34 #include "ares.h"
35 #include "ares_inet_net_pton.h"
36 #include "bitncmp.h"
37 #include "ares_platform.h"
38 #include "ares_nowarn.h"
39 #include "ares_private.h"
40 
41 static void sort_addresses(struct hostent *host,
42                            const struct apattern *sortlist, int nsort);
43 static void sort6_addresses(struct hostent *host,
44                             const struct apattern *sortlist, int nsort);
45 static int get_address_index(const struct in_addr *addr,
46                              const struct apattern *sortlist, int nsort);
47 static int get6_address_index(const struct ares_in6_addr *addr,
48                               const struct apattern *sortlist, int nsort);
49 
50 struct host_query {
51   ares_host_callback callback;
52   void *arg;
53   ares_channel channel;
54 };
55 
ares_gethostbyname_callback(void * arg,int status,int timeouts,struct ares_addrinfo * result)56 static void ares_gethostbyname_callback(void *arg, int status, int timeouts,
57                                         struct ares_addrinfo *result)
58 {
59   struct hostent *hostent = NULL;
60   struct host_query *ghbn_arg = arg;
61 
62   if (status == ARES_SUCCESS)
63     {
64       status = ares__addrinfo2hostent(result, AF_UNSPEC, &hostent);
65     }
66 
67   /* addrinfo2hostent will only return ENODATA if there are no addresses _and_
68    * no cname/aliases.  However, gethostbyname will return ENODATA even if there
69    * is cname/alias data */
70   if (status == ARES_SUCCESS && hostent &&
71       (!hostent->h_addr_list || !hostent->h_addr_list[0]))
72     {
73       status = ARES_ENODATA;
74     }
75 
76   if (status == ARES_SUCCESS && ghbn_arg->channel->nsort && hostent)
77     {
78       if (hostent->h_addrtype == AF_INET6)
79         sort6_addresses(hostent, ghbn_arg->channel->sortlist,
80                         ghbn_arg->channel->nsort);
81       if (hostent->h_addrtype == AF_INET)
82         sort_addresses(hostent, ghbn_arg->channel->sortlist,
83                        ghbn_arg->channel->nsort);
84     }
85 
86   ghbn_arg->callback(ghbn_arg->arg, status, timeouts, hostent);
87 
88   ares_freeaddrinfo(result);
89   ares_free(ghbn_arg);
90   ares_free_hostent(hostent);
91 }
92 
ares_gethostbyname(ares_channel channel,const char * name,int family,ares_host_callback callback,void * arg)93 void ares_gethostbyname(ares_channel channel, const char *name, int family,
94                         ares_host_callback callback, void *arg)
95 {
96   const struct ares_addrinfo_hints hints = { ARES_AI_CANONNAME, family, 0, 0 };
97   struct host_query *ghbn_arg;
98 
99   if (!callback)
100     return;
101 
102   ghbn_arg = ares_malloc(sizeof(*ghbn_arg));
103   if (!ghbn_arg)
104     {
105       callback(arg, ARES_ENOMEM, 0, NULL);
106       return;
107     }
108 
109   ghbn_arg->callback=callback;
110   ghbn_arg->arg=arg;
111   ghbn_arg->channel=channel;
112 
113   ares_getaddrinfo(channel, name, NULL, &hints, ares_gethostbyname_callback,
114                    ghbn_arg);
115 }
116 
117 
sort_addresses(struct hostent * host,const struct apattern * sortlist,int nsort)118 static void sort_addresses(struct hostent *host,
119                            const struct apattern *sortlist, int nsort)
120 {
121   struct in_addr a1, a2;
122   int i1, i2, ind1, ind2;
123 
124   /* This is a simple insertion sort, not optimized at all.  i1 walks
125    * through the address list, with the loop invariant that everything
126    * to the left of i1 is sorted.  In the loop body, the value at i1 is moved
127    * back through the list (via i2) until it is in sorted order.
128    */
129   for (i1 = 0; host->h_addr_list[i1]; i1++)
130     {
131       memcpy(&a1, host->h_addr_list[i1], sizeof(struct in_addr));
132       ind1 = get_address_index(&a1, sortlist, nsort);
133       for (i2 = i1 - 1; i2 >= 0; i2--)
134         {
135           memcpy(&a2, host->h_addr_list[i2], sizeof(struct in_addr));
136           ind2 = get_address_index(&a2, sortlist, nsort);
137           if (ind2 <= ind1)
138             break;
139           memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct in_addr));
140         }
141       memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct in_addr));
142     }
143 }
144 
145 /* Find the first entry in sortlist which matches addr.  Return nsort
146  * if none of them match.
147  */
get_address_index(const struct in_addr * addr,const struct apattern * sortlist,int nsort)148 static int get_address_index(const struct in_addr *addr,
149                              const struct apattern *sortlist,
150                              int nsort)
151 {
152   int i;
153 
154   for (i = 0; i < nsort; i++)
155     {
156       if (sortlist[i].family != AF_INET)
157         continue;
158       if (sortlist[i].type == PATTERN_MASK)
159         {
160           if ((addr->s_addr & sortlist[i].mask.addr4.s_addr)
161               == sortlist[i].addrV4.s_addr)
162             break;
163         }
164       else
165         {
166           if (!ares__bitncmp(&addr->s_addr, &sortlist[i].addrV4.s_addr,
167                              sortlist[i].mask.bits))
168             break;
169         }
170     }
171   return i;
172 }
173 
sort6_addresses(struct hostent * host,const struct apattern * sortlist,int nsort)174 static void sort6_addresses(struct hostent *host,
175                             const struct apattern *sortlist, int nsort)
176 {
177   struct ares_in6_addr a1, a2;
178   int i1, i2, ind1, ind2;
179 
180   /* This is a simple insertion sort, not optimized at all.  i1 walks
181    * through the address list, with the loop invariant that everything
182    * to the left of i1 is sorted.  In the loop body, the value at i1 is moved
183    * back through the list (via i2) until it is in sorted order.
184    */
185   for (i1 = 0; host->h_addr_list[i1]; i1++)
186     {
187       memcpy(&a1, host->h_addr_list[i1], sizeof(struct ares_in6_addr));
188       ind1 = get6_address_index(&a1, sortlist, nsort);
189       for (i2 = i1 - 1; i2 >= 0; i2--)
190         {
191           memcpy(&a2, host->h_addr_list[i2], sizeof(struct ares_in6_addr));
192           ind2 = get6_address_index(&a2, sortlist, nsort);
193           if (ind2 <= ind1)
194             break;
195           memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct ares_in6_addr));
196         }
197       memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct ares_in6_addr));
198     }
199 }
200 
201 /* Find the first entry in sortlist which matches addr.  Return nsort
202  * if none of them match.
203  */
get6_address_index(const struct ares_in6_addr * addr,const struct apattern * sortlist,int nsort)204 static int get6_address_index(const struct ares_in6_addr *addr,
205                               const struct apattern *sortlist,
206                               int nsort)
207 {
208   int i;
209 
210   for (i = 0; i < nsort; i++)
211     {
212       if (sortlist[i].family != AF_INET6)
213         continue;
214       if (!ares__bitncmp(addr, &sortlist[i].addrV6, sortlist[i].mask.bits))
215         break;
216     }
217   return i;
218 }
219 
220 
221 
222 static int file_lookup(const char *name, int family, struct hostent **host);
223 
224 /* I really have no idea why this is exposed as a public function, but since
225  * it is, we can't kill this legacy function. */
ares_gethostbyname_file(ares_channel channel,const char * name,int family,struct hostent ** host)226 int ares_gethostbyname_file(ares_channel channel, const char *name,
227                             int family, struct hostent **host)
228 {
229   int result;
230 
231   /* We only take the channel to ensure that ares_init() been called. */
232   if(channel == NULL)
233     {
234       /* Anything will do, really.  This seems fine, and is consistent with
235          other error cases. */
236       *host = NULL;
237       return ARES_ENOTFOUND;
238     }
239 
240   /* Just chain to the internal implementation we use here; it's exactly
241    * what we want.
242    */
243   result = file_lookup(name, family, host);
244   if(result != ARES_SUCCESS)
245     {
246       /* We guarantee a NULL hostent on failure. */
247       *host = NULL;
248     }
249   return result;
250 }
251 
file_lookup(const char * name,int family,struct hostent ** host)252 static int file_lookup(const char *name, int family, struct hostent **host)
253 {
254   FILE *fp;
255   char **alias;
256   int status;
257   int error;
258 
259 #ifdef WIN32
260   char PATH_HOSTS[MAX_PATH];
261   win_platform platform;
262 
263   PATH_HOSTS[0] = '\0';
264 
265   platform = ares__getplatform();
266 
267   if (platform == WIN_NT) {
268     char tmp[MAX_PATH];
269     HKEY hkeyHosts;
270 
271     if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ,
272                      &hkeyHosts) == ERROR_SUCCESS)
273     {
274       DWORD dwLength = MAX_PATH;
275       RegQueryValueExA(hkeyHosts, DATABASEPATH, NULL, NULL, (LPBYTE)tmp,
276                       &dwLength);
277       ExpandEnvironmentStringsA(tmp, PATH_HOSTS, MAX_PATH);
278       RegCloseKey(hkeyHosts);
279     }
280   }
281   else if (platform == WIN_9X)
282     GetWindowsDirectoryA(PATH_HOSTS, MAX_PATH);
283   else
284     return ARES_ENOTFOUND;
285 
286   strcat(PATH_HOSTS, WIN_PATH_HOSTS);
287 
288 #elif defined(WATT32)
289   const char *PATH_HOSTS = _w32_GetHostsFile();
290 
291   if (!PATH_HOSTS)
292     return ARES_ENOTFOUND;
293 #endif
294 
295   /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
296   if (ares__is_onion_domain(name))
297     return ARES_ENOTFOUND;
298 
299 
300   fp = fopen(PATH_HOSTS, "r");
301   if (!fp)
302     {
303       error = ERRNO;
304       switch(error)
305         {
306         case ENOENT:
307         case ESRCH:
308           return ARES_ENOTFOUND;
309         default:
310           DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
311                          error, strerror(error)));
312           DEBUGF(fprintf(stderr, "Error opening file: %s\n",
313                          PATH_HOSTS));
314           *host = NULL;
315           return ARES_EFILE;
316         }
317     }
318   while ((status = ares__get_hostent(fp, family, host)) == ARES_SUCCESS)
319     {
320       if (strcasecmp((*host)->h_name, name) == 0)
321         break;
322       for (alias = (*host)->h_aliases; *alias; alias++)
323         {
324           if (strcasecmp(*alias, name) == 0)
325             break;
326         }
327       if (*alias)
328         break;
329       ares_free_hostent(*host);
330     }
331   fclose(fp);
332   if (status == ARES_EOF)
333     status = ARES_ENOTFOUND;
334   if (status != ARES_SUCCESS)
335     *host = NULL;
336   return status;
337 }
338 
339