1 /* MIT License
2 *
3 * Copyright (c) 1998, 2011, 2013 Massachusetts Institute of Technology
4 * Copyright (c) The c-ares project and its contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * SPDX-License-Identifier: MIT
26 */
27
28 #include "ares_setup.h"
29
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
32 #endif
33 #ifdef HAVE_NETDB_H
34 # include <netdb.h>
35 #endif
36 #ifdef HAVE_ARPA_INET_H
37 # include <arpa/inet.h>
38 #endif
39
40 #include "ares_nameser.h"
41
42 #ifdef HAVE_STRINGS_H
43 # include <strings.h>
44 #endif
45
46 #include "ares.h"
47 #include "ares_inet_net_pton.h"
48 #include "ares_platform.h"
49 #include "ares_private.h"
50
51 static void sort_addresses(const struct hostent *host,
52 const struct apattern *sortlist, size_t nsort);
53 static void sort6_addresses(const struct hostent *host,
54 const struct apattern *sortlist, size_t nsort);
55 static size_t get_address_index(const struct in_addr *addr,
56 const struct apattern *sortlist, size_t nsort);
57 static size_t get6_address_index(const struct ares_in6_addr *addr,
58 const struct apattern *sortlist, size_t nsort);
59
60 struct host_query {
61 ares_host_callback callback;
62 void *arg;
63 ares_channel_t *channel;
64 };
65
ares_gethostbyname_callback(void * arg,int status,int timeouts,struct ares_addrinfo * result)66 static void ares_gethostbyname_callback(void *arg, int status, int timeouts,
67 struct ares_addrinfo *result)
68 {
69 struct hostent *hostent = NULL;
70 struct host_query *ghbn_arg = arg;
71
72 if (status == ARES_SUCCESS) {
73 status = (int)ares__addrinfo2hostent(result, AF_UNSPEC, &hostent);
74 }
75
76 /* addrinfo2hostent will only return ENODATA if there are no addresses _and_
77 * no cname/aliases. However, gethostbyname will return ENODATA even if there
78 * is cname/alias data */
79 if (status == ARES_SUCCESS && hostent &&
80 (!hostent->h_addr_list || !hostent->h_addr_list[0])) {
81 status = ARES_ENODATA;
82 }
83
84 if (status == ARES_SUCCESS && ghbn_arg->channel->nsort && hostent) {
85 if (hostent->h_addrtype == AF_INET6) {
86 sort6_addresses(hostent, ghbn_arg->channel->sortlist,
87 ghbn_arg->channel->nsort);
88 }
89 if (hostent->h_addrtype == AF_INET) {
90 sort_addresses(hostent, ghbn_arg->channel->sortlist,
91 ghbn_arg->channel->nsort);
92 }
93 }
94
95 ghbn_arg->callback(ghbn_arg->arg, status, timeouts, hostent);
96
97 ares_freeaddrinfo(result);
98 ares_free(ghbn_arg);
99 ares_free_hostent(hostent);
100 }
101
ares_gethostbyname(ares_channel_t * channel,const char * name,int family,ares_host_callback callback,void * arg)102 void ares_gethostbyname(ares_channel_t *channel, const char *name, int family,
103 ares_host_callback callback, void *arg)
104 {
105 const struct ares_addrinfo_hints hints = { ARES_AI_CANONNAME, family, 0, 0 };
106 struct host_query *ghbn_arg;
107
108 if (!callback) {
109 return;
110 }
111
112 ghbn_arg = ares_malloc(sizeof(*ghbn_arg));
113 if (!ghbn_arg) {
114 callback(arg, ARES_ENOMEM, 0, NULL);
115 return;
116 }
117
118 ghbn_arg->callback = callback;
119 ghbn_arg->arg = arg;
120 ghbn_arg->channel = channel;
121
122 /* NOTE: ares_getaddrinfo() locks the channel, we don't use the channel
123 * outside so no need to lock */
124 ares_getaddrinfo(channel, name, NULL, &hints, ares_gethostbyname_callback,
125 ghbn_arg);
126 }
127
sort_addresses(const struct hostent * host,const struct apattern * sortlist,size_t nsort)128 static void sort_addresses(const struct hostent *host,
129 const struct apattern *sortlist, size_t nsort)
130 {
131 struct in_addr a1;
132 struct in_addr a2;
133 int i1;
134 int i2;
135 size_t ind1;
136 size_t ind2;
137
138 /* This is a simple insertion sort, not optimized at all. i1 walks
139 * through the address list, with the loop invariant that everything
140 * to the left of i1 is sorted. In the loop body, the value at i1 is moved
141 * back through the list (via i2) until it is in sorted order.
142 */
143 for (i1 = 0; host->h_addr_list[i1]; i1++) {
144 memcpy(&a1, host->h_addr_list[i1], sizeof(struct in_addr));
145 ind1 = get_address_index(&a1, sortlist, nsort);
146 for (i2 = i1 - 1; i2 >= 0; i2--) {
147 memcpy(&a2, host->h_addr_list[i2], sizeof(struct in_addr));
148 ind2 = get_address_index(&a2, sortlist, nsort);
149 if (ind2 <= ind1) {
150 break;
151 }
152 memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct in_addr));
153 }
154 memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct in_addr));
155 }
156 }
157
158 /* Find the first entry in sortlist which matches addr. Return nsort
159 * if none of them match.
160 */
get_address_index(const struct in_addr * addr,const struct apattern * sortlist,size_t nsort)161 static size_t get_address_index(const struct in_addr *addr,
162 const struct apattern *sortlist, size_t nsort)
163 {
164 size_t i;
165 struct ares_addr aaddr;
166
167 memset(&aaddr, 0, sizeof(aaddr));
168 aaddr.family = AF_INET;
169 memcpy(&aaddr.addr.addr4, addr, 4);
170
171 for (i = 0; i < nsort; i++) {
172 if (sortlist[i].addr.family != AF_INET) {
173 continue;
174 }
175
176 if (ares__subnet_match(&aaddr, &sortlist[i].addr, sortlist[i].mask)) {
177 break;
178 }
179 }
180
181 return i;
182 }
183
sort6_addresses(const struct hostent * host,const struct apattern * sortlist,size_t nsort)184 static void sort6_addresses(const struct hostent *host,
185 const struct apattern *sortlist, size_t nsort)
186 {
187 struct ares_in6_addr a1;
188 struct ares_in6_addr a2;
189 int i1;
190 int i2;
191 size_t ind1;
192 size_t ind2;
193
194 /* This is a simple insertion sort, not optimized at all. i1 walks
195 * through the address list, with the loop invariant that everything
196 * to the left of i1 is sorted. In the loop body, the value at i1 is moved
197 * back through the list (via i2) until it is in sorted order.
198 */
199 for (i1 = 0; host->h_addr_list[i1]; i1++) {
200 memcpy(&a1, host->h_addr_list[i1], sizeof(struct ares_in6_addr));
201 ind1 = get6_address_index(&a1, sortlist, nsort);
202 for (i2 = i1 - 1; i2 >= 0; i2--) {
203 memcpy(&a2, host->h_addr_list[i2], sizeof(struct ares_in6_addr));
204 ind2 = get6_address_index(&a2, sortlist, nsort);
205 if (ind2 <= ind1) {
206 break;
207 }
208 memcpy(host->h_addr_list[i2 + 1], &a2, sizeof(struct ares_in6_addr));
209 }
210 memcpy(host->h_addr_list[i2 + 1], &a1, sizeof(struct ares_in6_addr));
211 }
212 }
213
214 /* Find the first entry in sortlist which matches addr. Return nsort
215 * if none of them match.
216 */
get6_address_index(const struct ares_in6_addr * addr,const struct apattern * sortlist,size_t nsort)217 static size_t get6_address_index(const struct ares_in6_addr *addr,
218 const struct apattern *sortlist, size_t nsort)
219 {
220 size_t i;
221 struct ares_addr aaddr;
222
223 memset(&aaddr, 0, sizeof(aaddr));
224 aaddr.family = AF_INET6;
225 memcpy(&aaddr.addr.addr6, addr, 16);
226
227 for (i = 0; i < nsort; i++) {
228 if (sortlist[i].addr.family != AF_INET6) {
229 continue;
230 }
231
232 if (ares__subnet_match(&aaddr, &sortlist[i].addr, sortlist[i].mask)) {
233 break;
234 }
235 }
236 return i;
237 }
238
ares__hostent_localhost(const char * name,int family,struct hostent ** host_out)239 static ares_status_t ares__hostent_localhost(const char *name, int family,
240 struct hostent **host_out)
241 {
242 ares_status_t status;
243 struct ares_addrinfo *ai = NULL;
244 struct ares_addrinfo_hints hints;
245
246 memset(&hints, 0, sizeof(hints));
247 hints.ai_family = family;
248
249 ai = ares_malloc_zero(sizeof(*ai));
250 if (ai == NULL) {
251 status = ARES_ENOMEM;
252 goto done;
253 }
254
255 status = ares__addrinfo_localhost(name, 0, &hints, ai);
256 if (status != ARES_SUCCESS) {
257 goto done;
258 }
259
260 status = ares__addrinfo2hostent(ai, family, host_out);
261 if (status != ARES_SUCCESS) {
262 goto done;
263 }
264
265 done:
266 ares_freeaddrinfo(ai);
267 return status;
268 }
269
270 /* I really have no idea why this is exposed as a public function, but since
271 * it is, we can't kill this legacy function. */
ares_gethostbyname_file_int(ares_channel_t * channel,const char * name,int family,struct hostent ** host)272 static ares_status_t ares_gethostbyname_file_int(ares_channel_t *channel,
273 const char *name, int family,
274 struct hostent **host)
275 {
276 const ares_hosts_entry_t *entry;
277 ares_status_t status;
278
279 /* We only take the channel to ensure that ares_init() been called. */
280 if (channel == NULL || name == NULL || host == NULL) {
281 /* Anything will do, really. This seems fine, and is consistent with
282 other error cases. */
283 if (host != NULL) {
284 *host = NULL;
285 }
286 return ARES_ENOTFOUND;
287 }
288
289 /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
290 if (ares__is_onion_domain(name)) {
291 return ARES_ENOTFOUND;
292 }
293
294 status = ares__hosts_search_host(channel, ARES_FALSE, name, &entry);
295 if (status != ARES_SUCCESS) {
296 goto done;
297 }
298
299 status = ares__hosts_entry_to_hostent(entry, family, host);
300 if (status != ARES_SUCCESS) {
301 goto done;
302 }
303
304 done:
305 /* RFC6761 section 6.3 #3 states that "Name resolution APIs and libraries
306 * SHOULD recognize localhost names as special and SHOULD always return the
307 * IP loopback address for address queries".
308 * We will also ignore ALL errors when trying to resolve localhost, such
309 * as permissions errors reading /etc/hosts or a malformed /etc/hosts */
310 if (status != ARES_SUCCESS && status != ARES_ENOMEM &&
311 ares__is_localhost(name)) {
312 return ares__hostent_localhost(name, family, host);
313 }
314
315 return status;
316 }
317
ares_gethostbyname_file(ares_channel_t * channel,const char * name,int family,struct hostent ** host)318 int ares_gethostbyname_file(ares_channel_t *channel, const char *name,
319 int family, struct hostent **host)
320 {
321 ares_status_t status;
322 if (channel == NULL) {
323 return ARES_ENOTFOUND;
324 }
325
326 ares__channel_lock(channel);
327 status = ares_gethostbyname_file_int(channel, name, family, host);
328 ares__channel_unlock(channel);
329 return (int)status;
330 }
331