1 /* MIT License
2 *
3 * Copyright (c) 1998, 2011, 2013 Massachusetts Institute of Technology
4 * Copyright (c) 2017 Christian Ammer
5 * Copyright (c) 2019 Andrew Selivanov
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 *
26 * SPDX-License-Identifier: MIT
27 */
28
29 #include "ares_private.h"
30
31 #ifdef HAVE_GETSERVBYNAME_R
32 # if !defined(GETSERVBYNAME_R_ARGS) || (GETSERVBYNAME_R_ARGS < 4) || \
33 (GETSERVBYNAME_R_ARGS > 6)
34 # error "you MUST specify a valid number of arguments for getservbyname_r"
35 # endif
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41 #ifdef HAVE_NETDB_H
42 # include <netdb.h>
43 #endif
44 #ifdef HAVE_ARPA_INET_H
45 # include <arpa/inet.h>
46 #endif
47
48 #include "ares_nameser.h"
49
50 #ifdef HAVE_STRINGS_H
51 # include <strings.h>
52 #endif
53 #include <assert.h>
54
55 #ifdef HAVE_LIMITS_H
56 # include <limits.h>
57 #endif
58
59 #include "ares_dns.h"
60 #include "ares_llist.h"
61
62 struct host_query {
63 ares_channel_t *channel;
64 char *name;
65 unsigned short port; /* in host order */
66 ares_addrinfo_callback callback;
67 void *arg;
68 struct ares_addrinfo_hints hints;
69 int sent_family; /* this family is what was is being used */
70 size_t timeouts; /* number of timeouts we saw for this request */
71 char *lookups; /* Duplicate memory from channel because of ares_reinit() */
72 const char *remaining_lookups; /* types of lookup we need to perform ("fb" by
73 default, file and dns respectively) */
74
75 /* Search order for names */
76 char **names;
77 size_t names_cnt;
78 size_t next_name_idx; /* next name index being attempted */
79
80 struct ares_addrinfo *ai; /* store results between lookups */
81 unsigned short qid_a; /* qid for A request */
82 unsigned short qid_aaaa; /* qid for AAAA request */
83
84 size_t remaining; /* number of DNS answers waiting for */
85
86 /* Track nodata responses to possibly override final result */
87 size_t nodata_cnt;
88 #if OHOS_DNS_PROXY_BY_NETSYS
89 char *src_addr;
90 struct ares_process_info process_info;
91 #endif
92 };
93
94 static const struct ares_addrinfo_hints default_hints = {
95 0, /* ai_flags */
96 AF_UNSPEC, /* ai_family */
97 0, /* ai_socktype */
98 0, /* ai_protocol */
99 };
100
101 /* forward declarations */
102 static ares_bool_t next_dns_lookup(struct host_query *hquery);
103
104 #if OHOS_DNS_PROXY_BY_NETSYS
105 #define MAX_RESULTS 32
106 #define MAX_CANON_NAME 256
107 #define SOURCE_FROM_CARES 2
108
109 typedef union {
110 struct sockaddr sa;
111 struct sockaddr_in6 sin6;
112 struct sockaddr_in sin;
113 } ares_align_sock_addr;
114
115 typedef struct {
116 uint32_t ai_flags;
117 uint32_t ai_family;
118 uint32_t ai_socktype;
119 uint32_t ai_protocol;
120 uint32_t ai_addrlen;
121 ares_align_sock_addr ai_addr;
122 char ai_canonName[MAX_CANON_NAME + 1];
123 } ares_cached_addrinfo;
124
125 typedef struct {
126 char *host;
127 char *serv;
128 struct addrinfo *hint;
129 } ares_cache_key_param_wrapper;
130
131 static const struct ares_family_query_info empty_family_query_info = {
132 -1, /* retCode */
133 NULL, /* serverAddr */
134 1, /* isNoAnswer */
135 0, /* cname */
136 };
137
ares_addrinfo_hints_to_addrinfo(const struct ares_addrinfo_hints * hints,struct addrinfo * out_hints)138 void ares_addrinfo_hints_to_addrinfo(const struct ares_addrinfo_hints *hints, struct addrinfo *out_hints) {
139 if (hints == NULL || out_hints == NULL) {
140 return;
141 }
142 memset(out_hints, 0, sizeof(struct addrinfo));
143 out_hints->ai_flags = hints->ai_flags;
144 out_hints->ai_family = hints->ai_family;
145 out_hints->ai_socktype = hints->ai_socktype;
146 out_hints->ai_protocol = hints->ai_protocol;
147 }
148
ares_get_now_time()149 long long ares_get_now_time()
150 {
151 struct timeval tv;
152 gettimeofday(&tv, NULL);
153 long long timestamp = (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
154 return timestamp;
155 }
156
free_process_info(struct ares_process_info process_info)157 void free_process_info(struct ares_process_info process_info)
158 {
159 struct ares_family_query_info ipv4Info = process_info.ipv4QueryInfo;
160 struct ares_family_query_info ipv6Info = process_info.ipv6QueryInfo;
161 if (ipv4Info.serverAddr) {
162 ares_free(ipv4Info.serverAddr);
163 }
164 if (ipv6Info.serverAddr) {
165 ares_free(ipv6Info.serverAddr);
166 }
167 }
168
ares_free_posix_addrinfo(struct addrinfo * head)169 void ares_free_posix_addrinfo(struct addrinfo *head) {
170 while (head != NULL) {
171 struct addrinfo *current = head;
172 head = head->ai_next;
173 if (current->ai_addr) {
174 ares_free(current->ai_addr);
175 }
176 ares_free(current);
177 }
178 }
179
ares_addrinfo_to_addrinfo(const struct ares_addrinfo * res)180 struct addrinfo *ares_addrinfo_to_addrinfo(const struct ares_addrinfo *res) {
181 if (res == NULL) {
182 return NULL;
183 }
184
185 struct addrinfo *head_res = ares_malloc(sizeof(struct addrinfo));
186 if (head_res == NULL) {
187 return NULL;
188 }
189 memset(head_res, 0, sizeof(struct addrinfo));
190
191 struct addrinfo *now_node = head_res;
192 for (struct ares_addrinfo_node *tmp = res->nodes; tmp != NULL; tmp = tmp->ai_next) {
193 if (tmp->ai_addrlen > sizeof(ares_align_sock_addr)) {
194 continue;
195 }
196 struct addrinfo *next_node = ares_malloc(sizeof(struct addrinfo));
197 if (next_node == NULL) {
198 ares_free_posix_addrinfo(head_res);
199 return NULL;
200 }
201 memset(next_node, 0, sizeof(struct addrinfo));
202 now_node->ai_next = next_node;
203 now_node = next_node;
204
205 next_node->ai_flags = tmp->ai_flags;
206 next_node->ai_family = tmp->ai_family;
207 next_node->ai_socktype = tmp->ai_socktype;
208 next_node->ai_protocol = tmp->ai_protocol;
209 next_node->ai_addrlen = tmp->ai_addrlen;
210 next_node->ai_addr = ares_malloc(sizeof(ares_align_sock_addr));
211 if (next_node->ai_addr == NULL) {
212 ares_free_posix_addrinfo(head_res);
213 return NULL;
214 }
215 memset(next_node->ai_addr, 0, sizeof(ares_align_sock_addr));
216 memcpy(next_node->ai_addr, tmp->ai_addr, tmp->ai_addrlen);
217 }
218 struct addrinfo *out_res = head_res->ai_next;
219 ares_free(head_res);
220 return out_res;
221 }
222
ares_record_process(int status,const char * hostname,long long start_time,const struct ares_addrinfo * addr_info,struct host_query * hquery)223 void ares_record_process(int status, const char *hostname, long long start_time,
224 const struct ares_addrinfo *addr_info, struct host_query *hquery)
225 {
226 if (hostname == NULL) {
227 return;
228 }
229 int cost_time = ares_get_now_time() - start_time;
230 struct ares_process_info process_info;
231 process_info.ipv4QueryInfo = empty_family_query_info;
232 process_info.ipv6QueryInfo = empty_family_query_info;
233 process_info.sourceFrom = SOURCE_FROM_CARES;
234 process_info.hostname = ares_strdup(hostname);
235 if (addr_info) {
236 // read from cache
237 process_info.isFromCache = 1;
238 process_info.queryTime = start_time;
239 process_info.retCode = status;
240 process_info.firstQueryEndDuration = cost_time;
241 process_info.firstReturnType = 0;
242 struct addrinfo *addr = ares_addrinfo_to_addrinfo(addr_info);
243 ares_free_posix_addrinfo(addr);
244 ares_free(process_info.hostname);
245 } else if (!hquery) {
246 // no hquery mean error
247 process_info.isFromCache = 0;
248 process_info.queryTime = start_time;
249 process_info.retCode = status;
250 process_info.firstQueryEndDuration = cost_time;
251 process_info.firstReturnType = 0;
252 ares_free(process_info.hostname);
253 } else if (hquery) {
254 // query complete
255 ares_free(process_info.hostname);
256 process_info = hquery->process_info;
257 process_info.isFromCache = 0;
258 struct addrinfo *addr = ares_addrinfo_to_addrinfo(hquery->ai);
259 ares_free_posix_addrinfo(addr);
260 }
261 }
262
ares_ans_all_cname(const ares_dns_record_t * dnsrec)263 int ares_ans_all_cname(const ares_dns_record_t *dnsrec)
264 {
265 size_t ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
266 if (ancount == 0) {
267 return 0;
268 }
269 for (size_t i = 0; i < ancount; i++) {
270 const ares_dns_rr_t *rr =
271 ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i);
272 ares_dns_rec_type_t rtype = ares_dns_rr_get_type(rr);
273 ares_dns_class_t rclass = ares_dns_rr_get_class(rr);
274 if (rclass != ARES_CLASS_IN || rtype != ARES_REC_TYPE_CNAME) {
275 return 0;
276 }
277 }
278 return 1;
279 }
280
ares_get_addr(struct ares_addr * addr)281 char *ares_get_addr(struct ares_addr *addr)
282 {
283 if (addr == NULL) {
284 return NULL;
285 }
286 char *ip_str = NULL;
287 if (addr->family == AF_INET) {
288 ip_str = ares_malloc(INET_ADDRSTRLEN);
289 if (ip_str == NULL) {
290 return NULL;
291 }
292 if (ares_inet_ntop(AF_INET, &addr->addr.addr4, ip_str, INET_ADDRSTRLEN) == NULL) {
293 ares_free(ip_str);
294 return NULL;
295 }
296 } else if (addr->family == AF_INET6) {
297 ip_str = ares_malloc(INET6_ADDRSTRLEN);
298 if (ip_str == NULL) {
299 return NULL;
300 }
301 if (ares_inet_ntop(AF_INET6, &addr->addr.addr6, ip_str, INET6_ADDRSTRLEN) == NULL) {
302 ares_free(ip_str);
303 return NULL;
304 }
305 }
306 return ip_str;
307 }
308
ares_get_addr_by_sockaddr(struct sockaddr * sa)309 char *ares_get_addr_by_sockaddr(struct sockaddr *sa)
310 {
311 if (sa == NULL) {
312 return NULL;
313 }
314 char *ip_str = NULL;
315 switch (sa->sa_family) {
316 case AF_INET: {
317 ip_str = ares_malloc(INET_ADDRSTRLEN);
318 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
319 if (ares_inet_ntop(AF_INET, &sin->sin_addr, ip_str, INET_ADDRSTRLEN) == NULL) {
320 ares_free(ip_str);
321 }
322 break;
323 }
324 case AF_INET6: {
325 ip_str = ares_malloc(INET6_ADDRSTRLEN);
326 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
327 if (ares_inet_ntop(AF_INET6, &sin6->sin6_addr, ip_str, INET6_ADDRSTRLEN) == NULL) {
328 ares_free(ip_str);
329 }
330 break;
331 }
332 default:
333 break;
334 }
335 return ip_str;
336 }
337
ares_get_src_addr(ares_socket_t sock,struct ares_addr addr,struct sockaddr * src_addr)338 int ares_get_src_addr(ares_socket_t sock, struct ares_addr addr, struct sockaddr *src_addr)
339 {
340 if (sock <= 0) {
341 return -1;
342 }
343 ares_socklen_t len;
344 switch (addr.family)
345 {
346 case AF_INET:
347 len = sizeof(struct sockaddr_in);
348 break;
349 case AF_INET6:
350 len = sizeof(struct sockaddr_in6);
351 break;
352 default:
353 /* No known usable source address for non-INET families. */
354 return -1;
355 }
356 if (getsockname(sock, src_addr, &len) != 0) {
357 return -1;
358 }
359 return 0;
360 }
361
ares_set_hquery_process(ares_dns_rec_type_t qtype,struct host_query * hquery,int status,struct ares_family_query_info info)362 void ares_set_hquery_process(ares_dns_rec_type_t qtype, struct host_query *hquery,
363 int status, struct ares_family_query_info info)
364 {
365 if (hquery->process_info.firstQueryEndDuration == 0) {
366 if (status == ARES_SUCCESS) {
367 hquery->process_info.firstQueryEndDuration =
368 ares_get_now_time() - hquery->process_info.queryTime;
369 }
370 hquery->process_info.firstReturnType = qtype;
371 }
372 if (qtype == ARES_REC_TYPE_A) {
373 hquery->process_info.ipv4QueryInfo = info;
374 }
375 if (qtype == ARES_REC_TYPE_AAAA) {
376 hquery->process_info.ipv6QueryInfo = info;
377 }
378 }
379
ares_parse_query_info(int status,const ares_dns_record_t * dnsrec,struct host_query * hquery)380 void ares_parse_query_info(int status, const ares_dns_record_t *dnsrec, struct host_query *hquery)
381 {
382 if (hquery == NULL || dnsrec == NULL || hquery->channel == NULL) {
383 return;
384 }
385 ares_dns_rec_type_t qtype;
386 const ares_channel_t *channel = hquery->channel;
387 ares_query_t *query = ares_htable_szvp_get_direct(channel->queries_by_qid,
388 ares_dns_record_get_id(dnsrec));
389 if (query == NULL) {
390 return;
391 }
392 if (ares_dns_record_query_get(query->query, 0, NULL, &qtype, NULL) != ARES_SUCCESS) {
393 return;
394 }
395 if (qtype != ARES_REC_TYPE_A && qtype != ARES_REC_TYPE_AAAA) {
396 return;
397 }
398 char *res_addr = NULL;
399 char *server_addr = NULL;
400 ares_conn_t *conn = query->conn;
401 if (conn == NULL) {
402 return;
403 }
404 ares_server_t *server = conn->server;
405 if (server == NULL) {
406 return;
407 }
408 server_addr = ares_get_addr(&server->addr);
409 struct sockaddr *src_addr = NULL;
410 src_addr = ares_malloc(sizeof(struct sockaddr_storage));
411 if (src_addr) {
412 if (ares_get_src_addr(conn->fd, server->addr, src_addr) == 0) {
413 res_addr = ares_get_addr_by_sockaddr(src_addr);
414 }
415 }
416 ares_free(src_addr);
417 hquery->src_addr = res_addr;
418 struct ares_family_query_info info;
419 info.retCode = status;
420 size_t ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
421 info.isNoAnswer = ancount > 0 ? 0 : 1;
422 info.serverAddr = server_addr;
423 info.cname = ares_ans_all_cname(dnsrec);
424 ares_set_hquery_process(qtype, hquery, status, info);
425 }
426
427 struct ares_addrinfo *
ares_cached_addrinfo_to_ares_addrinfo(const ares_cached_addrinfo cached_addrinfo[static MAX_RESULTS],uint32_t num)428 ares_cached_addrinfo_to_ares_addrinfo(const ares_cached_addrinfo cached_addrinfo[static MAX_RESULTS], uint32_t num) {
429 uint32_t real_num = num > MAX_RESULTS ? MAX_RESULTS : num;
430 if (num == 0) {
431 return NULL;
432 }
433
434 struct ares_addrinfo_node *head_res = ares_malloc(sizeof(struct ares_addrinfo_node));
435 if (head_res == NULL) {
436 return NULL;
437 }
438 memset(head_res, 0, sizeof(struct ares_addrinfo_node));
439
440 struct ares_addrinfo_node *now_node = head_res;
441 for (uint32_t i = 0; i < real_num; ++i) {
442 if (cached_addrinfo[i].ai_addrlen > sizeof(ares_align_sock_addr)) {
443 continue;
444 }
445
446 struct ares_addrinfo_node *next_node = ares_malloc(sizeof(struct ares_addrinfo_node));
447 if (next_node == NULL) {
448 ares_freeaddrinfo_nodes(head_res);
449 return NULL;
450 }
451 memset(next_node, 0, sizeof(struct ares_addrinfo_node));
452 now_node->ai_next = next_node;
453 now_node = next_node;
454
455 next_node->ai_flags = (int) cached_addrinfo[i].ai_flags;
456 next_node->ai_family = (int) cached_addrinfo[i].ai_family;
457 next_node->ai_socktype = (int) cached_addrinfo[i].ai_socktype;
458 next_node->ai_protocol = (int) cached_addrinfo[i].ai_protocol;
459 next_node->ai_addrlen = (ares_socklen_t) cached_addrinfo[i].ai_addrlen;
460 next_node->ai_addr = ares_malloc(sizeof(ares_align_sock_addr));
461 if (next_node->ai_addr == NULL) {
462 ares_freeaddrinfo_nodes(head_res);
463 return NULL;
464 }
465 memset(next_node->ai_addr, 0, sizeof(ares_align_sock_addr));
466 memcpy(next_node->ai_addr, &cached_addrinfo[i].ai_addr, cached_addrinfo[i].ai_addrlen);
467 }
468 struct ares_addrinfo *info = ares_malloc(sizeof(struct ares_addrinfo));
469 if (info == NULL) {
470 ares_freeaddrinfo_nodes(head_res);
471 return NULL;
472 }
473 memset(info, 0, sizeof(struct ares_addrinfo));
474
475 info->nodes = head_res->ai_next;
476 ares_free(head_res);
477 return info;
478 }
479
480 struct ares_addrinfo *
ares_get_dns_cache(const char * host,const char * service,const struct ares_addrinfo_hints * hints)481 ares_get_dns_cache(const char *host, const char *service, const struct ares_addrinfo_hints *hints) {
482 ares_cache_key_param_wrapper param = {0};
483 param.host = (char *) host;
484 param.serv = (char *) service;
485 struct addrinfo hint = {0};
486 ares_addrinfo_hints_to_addrinfo(hints, &hint);
487 param.hint = &hint;
488
489 ares_cached_addrinfo cached_addrinfo[MAX_RESULTS] = {0};
490 memset(cached_addrinfo, 0, sizeof(ares_cached_addrinfo) * MAX_RESULTS);
491 uint32_t num = 0;
492 if (num == 0) {
493 return NULL;
494 }
495 return ares_cached_addrinfo_to_ares_addrinfo(cached_addrinfo, num);
496 }
497
ares_set_dns_cache(const char * host,const char * service,const struct ares_addrinfo_hints * hints,const struct ares_addrinfo * res)498 void ares_set_dns_cache(const char *host, const char *service, const struct ares_addrinfo_hints *hints,
499 const struct ares_addrinfo *res) {
500 ares_cache_key_param_wrapper param = {0};
501 param.host = (char *) host;
502 param.serv = (char *) service;
503 struct addrinfo hint = {0};
504 ares_addrinfo_hints_to_addrinfo(hints, &hint);
505 param.hint = &hint;
506
507 struct addrinfo *posix_res = ares_addrinfo_to_addrinfo(res);
508 if (!posix_res) {
509 return;
510 }
511 ares_free_posix_addrinfo(posix_res);
512 }
513 #endif
514
515 struct ares_addrinfo_cname *
ares_append_addrinfo_cname(struct ares_addrinfo_cname ** head)516 ares_append_addrinfo_cname(struct ares_addrinfo_cname **head)
517 {
518 struct ares_addrinfo_cname *tail = ares_malloc_zero(sizeof(*tail));
519 struct ares_addrinfo_cname *last = *head;
520
521 if (tail == NULL) {
522 return NULL; /* LCOV_EXCL_LINE: OutOfMemory */
523 }
524
525 if (!last) {
526 *head = tail;
527 return tail;
528 }
529
530 while (last->next) {
531 last = last->next;
532 }
533
534 last->next = tail;
535 return tail;
536 }
537
ares_addrinfo_cat_cnames(struct ares_addrinfo_cname ** head,struct ares_addrinfo_cname * tail)538 void ares_addrinfo_cat_cnames(struct ares_addrinfo_cname **head,
539 struct ares_addrinfo_cname *tail)
540 {
541 struct ares_addrinfo_cname *last = *head;
542 if (!last) {
543 *head = tail;
544 return;
545 }
546
547 while (last->next) {
548 last = last->next;
549 }
550
551 last->next = tail;
552 }
553
554 /* Allocate new addrinfo and append to the tail. */
555 struct ares_addrinfo_node *
ares_append_addrinfo_node(struct ares_addrinfo_node ** head)556 ares_append_addrinfo_node(struct ares_addrinfo_node **head)
557 {
558 struct ares_addrinfo_node *tail = ares_malloc_zero(sizeof(*tail));
559 struct ares_addrinfo_node *last = *head;
560
561 if (tail == NULL) {
562 return NULL; /* LCOV_EXCL_LINE: OutOfMemory */
563 }
564
565 if (!last) {
566 *head = tail;
567 return tail;
568 }
569
570 while (last->ai_next) {
571 last = last->ai_next;
572 }
573
574 last->ai_next = tail;
575 return tail;
576 }
577
ares_addrinfo_cat_nodes(struct ares_addrinfo_node ** head,struct ares_addrinfo_node * tail)578 void ares_addrinfo_cat_nodes(struct ares_addrinfo_node **head,
579 struct ares_addrinfo_node *tail)
580 {
581 struct ares_addrinfo_node *last = *head;
582 if (!last) {
583 *head = tail;
584 return;
585 }
586
587 while (last->ai_next) {
588 last = last->ai_next;
589 }
590
591 last->ai_next = tail;
592 }
593
594 /* Resolve service name into port number given in host byte order.
595 * If not resolved, return 0.
596 */
lookup_service(const char * service,int flags)597 static unsigned short lookup_service(const char *service, int flags)
598 {
599 const char *proto;
600 struct servent *sep;
601 #ifdef HAVE_GETSERVBYNAME_R
602 struct servent se;
603 char tmpbuf[4096];
604 #endif
605
606 if (service) {
607 if (flags & ARES_NI_UDP) {
608 proto = "udp";
609 } else if (flags & ARES_NI_SCTP) {
610 proto = "sctp";
611 } else if (flags & ARES_NI_DCCP) {
612 proto = "dccp";
613 } else {
614 proto = "tcp";
615 }
616 #ifdef HAVE_GETSERVBYNAME_R
617 memset(&se, 0, sizeof(se));
618 sep = &se;
619 memset(tmpbuf, 0, sizeof(tmpbuf));
620 # if GETSERVBYNAME_R_ARGS == 6
621 if (getservbyname_r(service, proto, &se, (void *)tmpbuf, sizeof(tmpbuf),
622 &sep) != 0) {
623 sep = NULL; /* LCOV_EXCL_LINE: buffer large so this never fails */
624 }
625 # elif GETSERVBYNAME_R_ARGS == 5
626 sep = getservbyname_r(service, proto, &se, (void *)tmpbuf, sizeof(tmpbuf));
627 # elif GETSERVBYNAME_R_ARGS == 4
628 if (getservbyname_r(service, proto, &se, (void *)tmpbuf) != 0) {
629 sep = NULL;
630 }
631 # else
632 /* Lets just hope the OS uses TLS! */
633 sep = getservbyname(service, proto);
634 # endif
635 #else
636 /* Lets just hope the OS uses TLS! */
637 # if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
638 sep = getservbyname(service, (char *)proto);
639 # else
640 sep = getservbyname(service, proto);
641 # endif
642 #endif
643 return (sep ? ntohs((unsigned short)sep->s_port) : 0);
644 }
645 return 0;
646 }
647
648 /* If the name looks like an IP address or an error occurred,
649 * fake up a host entry, end the query immediately, and return true.
650 * Otherwise return false.
651 */
fake_addrinfo(const char * name,unsigned short port,const struct ares_addrinfo_hints * hints,struct ares_addrinfo * ai,ares_addrinfo_callback callback,void * arg)652 static ares_bool_t fake_addrinfo(const char *name, unsigned short port,
653 const struct ares_addrinfo_hints *hints,
654 struct ares_addrinfo *ai,
655 ares_addrinfo_callback callback, void *arg)
656 {
657 struct ares_addrinfo_cname *cname;
658 ares_status_t status = ARES_SUCCESS;
659 ares_bool_t result = ARES_FALSE;
660 int family = hints->ai_family;
661 if (family == AF_INET || family == AF_INET6 || family == AF_UNSPEC) {
662 /* It only looks like an IP address if it's all numbers and dots. */
663 size_t numdots = 0;
664 ares_bool_t valid = ARES_TRUE;
665 const char *p;
666 for (p = name; *p; p++) {
667 if (!ares_isdigit(*p) && *p != '.') {
668 valid = ARES_FALSE;
669 break;
670 } else if (*p == '.') {
671 numdots++;
672 }
673 }
674
675 /* if we don't have 3 dots, it is illegal
676 * (although inet_pton doesn't think so).
677 */
678 if (numdots != 3 || !valid) {
679 result = ARES_FALSE;
680 } else {
681 struct in_addr addr4;
682 result =
683 ares_inet_pton(AF_INET, name, &addr4) < 1 ? ARES_FALSE : ARES_TRUE;
684 if (result) {
685 status = ares_append_ai_node(AF_INET, port, 0, &addr4, &ai->nodes);
686 if (status != ARES_SUCCESS) {
687 callback(arg, (int)status, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */
688 return ARES_TRUE; /* LCOV_EXCL_LINE: OutOfMemory */
689 }
690 }
691 }
692 }
693
694 if (!result && (family == AF_INET6 || family == AF_UNSPEC)) {
695 struct ares_in6_addr addr6;
696 result =
697 ares_inet_pton(AF_INET6, name, &addr6) < 1 ? ARES_FALSE : ARES_TRUE;
698 if (result) {
699 status = ares_append_ai_node(AF_INET6, port, 0, &addr6, &ai->nodes);
700 if (status != ARES_SUCCESS) {
701 callback(arg, (int)status, 0, NULL); /* LCOV_EXCL_LINE: OutOfMemory */
702 return ARES_TRUE; /* LCOV_EXCL_LINE: OutOfMemory */
703 }
704 }
705 }
706
707 if (!result) {
708 return ARES_FALSE;
709 }
710
711 if (hints->ai_flags & ARES_AI_CANONNAME) {
712 cname = ares_append_addrinfo_cname(&ai->cnames);
713 if (!cname) {
714 /* LCOV_EXCL_START: OutOfMemory */
715 ares_freeaddrinfo(ai);
716 callback(arg, ARES_ENOMEM, 0, NULL);
717 return ARES_TRUE;
718 /* LCOV_EXCL_STOP */
719 }
720
721 /* Duplicate the name, to avoid a constness violation. */
722 cname->name = ares_strdup(name);
723 if (!cname->name) {
724 ares_freeaddrinfo(ai);
725 callback(arg, ARES_ENOMEM, 0, NULL);
726 return ARES_TRUE;
727 }
728 }
729
730 ai->nodes->ai_socktype = hints->ai_socktype;
731 ai->nodes->ai_protocol = hints->ai_protocol;
732
733 callback(arg, ARES_SUCCESS, 0, ai);
734 return ARES_TRUE;
735 }
736
hquery_free(struct host_query * hquery,ares_bool_t cleanup_ai)737 static void hquery_free(struct host_query *hquery, ares_bool_t cleanup_ai)
738 {
739 if (cleanup_ai) {
740 ares_freeaddrinfo(hquery->ai);
741 }
742 ares_strsplit_free(hquery->names, hquery->names_cnt);
743 ares_free(hquery->name);
744 ares_free(hquery->lookups);
745 #if OHOS_DNS_PROXY_BY_NETSYS
746 ares_free(hquery->src_addr);
747 free_process_info(hquery->process_info);
748 #endif
749 ares_free(hquery);
750 }
751
end_hquery(struct host_query * hquery,ares_status_t status)752 static void end_hquery(struct host_query *hquery, ares_status_t status)
753 {
754 struct ares_addrinfo_node sentinel;
755 struct ares_addrinfo_node *next;
756
757 if (status == ARES_SUCCESS) {
758 if (!(hquery->hints.ai_flags & ARES_AI_NOSORT) && hquery->ai->nodes) {
759 sentinel.ai_next = hquery->ai->nodes;
760 ares_sortaddrinfo(hquery->channel, &sentinel);
761 hquery->ai->nodes = sentinel.ai_next;
762 }
763 next = hquery->ai->nodes;
764
765 while (next) {
766 next->ai_socktype = hquery->hints.ai_socktype;
767 next->ai_protocol = hquery->hints.ai_protocol;
768 next = next->ai_next;
769 }
770 } else {
771 /* Clean up what we have collected by so far. */
772 ares_freeaddrinfo(hquery->ai);
773 hquery->ai = NULL;
774 }
775 #if OHOS_DNS_PROXY_BY_NETSYS
776 char serv[12] = {0};
777 sprintf(serv, "%d", hquery->port);
778 ares_set_dns_cache(hquery->name, serv, &hquery->hints, hquery->ai);
779 hquery->process_info.hostname = hquery->name;
780 hquery->process_info.retCode = status;
781 int allDuration = ares_get_now_time() - hquery->process_info.queryTime;
782 int firstQueryEnd2AppDuration = allDuration - hquery->process_info.firstQueryEndDuration;
783 hquery->process_info.firstQueryEnd2AppDuration = firstQueryEnd2AppDuration;
784 ares_record_process(status, hquery->name, hquery->process_info.queryTime, NULL, hquery);
785 #endif
786 hquery->callback(hquery->arg, (int)status, (int)hquery->timeouts, hquery->ai);
787 hquery_free(hquery, ARES_FALSE);
788 }
789
ares_is_localhost(const char * name)790 ares_bool_t ares_is_localhost(const char *name)
791 {
792 /* RFC6761 6.3 says : The domain "localhost." and any names falling within
793 * ".localhost." */
794 size_t len;
795
796 if (name == NULL) {
797 return ARES_FALSE; /* LCOV_EXCL_LINE: DefensiveCoding */
798 }
799
800 if (ares_strcaseeq(name, "localhost")) {
801 return ARES_TRUE;
802 }
803
804 len = ares_strlen(name);
805 if (len < 10 /* strlen(".localhost") */) {
806 return ARES_FALSE;
807 }
808
809 if (ares_strcaseeq(name + (len - 10 /* strlen(".localhost") */),
810 ".localhost")) {
811 return ARES_TRUE;
812 }
813
814 return ARES_FALSE;
815 }
816
file_lookup(struct host_query * hquery)817 static ares_status_t file_lookup(struct host_query *hquery)
818 {
819 const ares_hosts_entry_t *entry;
820 ares_status_t status;
821
822 /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
823 if (ares_is_onion_domain(hquery->name)) {
824 return ARES_ENOTFOUND;
825 }
826
827 status = ares_hosts_search_host(
828 hquery->channel,
829 (hquery->hints.ai_flags & ARES_AI_ENVHOSTS) ? ARES_TRUE : ARES_FALSE,
830 hquery->name, &entry);
831
832 if (status != ARES_SUCCESS) {
833 goto done;
834 }
835
836 status = ares_hosts_entry_to_addrinfo(
837 entry, hquery->name, hquery->hints.ai_family, hquery->port,
838 (hquery->hints.ai_flags & ARES_AI_CANONNAME) ? ARES_TRUE : ARES_FALSE,
839 hquery->ai);
840
841 if (status != ARES_SUCCESS) {
842 goto done; /* LCOV_EXCL_LINE: OutOfMemory */
843 }
844
845
846 done:
847 /* RFC6761 section 6.3 #3 states that "Name resolution APIs and libraries
848 * SHOULD recognize localhost names as special and SHOULD always return the
849 * IP loopback address for address queries".
850 * We will also ignore ALL errors when trying to resolve localhost, such
851 * as permissions errors reading /etc/hosts or a malformed /etc/hosts.
852 *
853 * Also, just because the query itself returned success from /etc/hosts
854 * lookup doesn't mean it returned everything it needed to for all requested
855 * address families. As long as we're not on a critical out of memory
856 * condition pass it through to fill in any other address classes. */
857 if (status != ARES_ENOMEM && ares_is_localhost(hquery->name)) {
858 return ares_addrinfo_localhost(hquery->name, hquery->port, &hquery->hints,
859 hquery->ai);
860 }
861
862 return status;
863 }
864
next_lookup(struct host_query * hquery,ares_status_t status)865 static void next_lookup(struct host_query *hquery, ares_status_t status)
866 {
867 switch (*hquery->remaining_lookups) {
868 case 'b':
869 /* RFC6761 section 6.3 #3 says "Name resolution APIs SHOULD NOT send
870 * queries for localhost names to their configured caching DNS
871 * server(s)."
872 * Otherwise, DNS lookup. */
873 if (!ares_is_localhost(hquery->name) && next_dns_lookup(hquery)) {
874 break;
875 }
876
877 hquery->remaining_lookups++;
878 next_lookup(hquery, status);
879 break;
880
881 case 'f':
882 /* Host file lookup */
883 if (file_lookup(hquery) == ARES_SUCCESS) {
884 end_hquery(hquery, ARES_SUCCESS);
885 break;
886 }
887 hquery->remaining_lookups++;
888 next_lookup(hquery, status);
889 break;
890 default:
891 /* No lookup left */
892 end_hquery(hquery, status);
893 break;
894 }
895 }
896
terminate_retries(const struct host_query * hquery,unsigned short qid)897 static void terminate_retries(const struct host_query *hquery,
898 unsigned short qid)
899 {
900 unsigned short term_qid =
901 (qid == hquery->qid_a) ? hquery->qid_aaaa : hquery->qid_a;
902 const ares_channel_t *channel = hquery->channel;
903 ares_query_t *query = NULL;
904
905 /* No other outstanding queries, nothing to do */
906 if (!hquery->remaining) {
907 return;
908 }
909
910 query = ares_htable_szvp_get_direct(channel->queries_by_qid, term_qid);
911 if (query == NULL) {
912 return;
913 }
914
915 query->no_retries = ARES_TRUE;
916 }
917
ai_has_ipv4(struct ares_addrinfo * ai)918 static ares_bool_t ai_has_ipv4(struct ares_addrinfo *ai)
919 {
920 struct ares_addrinfo_node *node;
921
922 for (node = ai->nodes; node != NULL; node = node->ai_next) {
923 if (node->ai_family == AF_INET) {
924 return ARES_TRUE;
925 }
926 }
927 return ARES_FALSE;
928 }
929
host_callback(void * arg,ares_status_t status,size_t timeouts,const ares_dns_record_t * dnsrec)930 static void host_callback(void *arg, ares_status_t status, size_t timeouts,
931 const ares_dns_record_t *dnsrec)
932 {
933 struct host_query *hquery = (struct host_query *)arg;
934 ares_status_t addinfostatus = ARES_SUCCESS;
935 hquery->timeouts += timeouts;
936 hquery->remaining--;
937
938 if (status == ARES_SUCCESS) {
939 if (dnsrec == NULL) {
940 addinfostatus = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */
941 } else {
942 addinfostatus =
943 ares_parse_into_addrinfo(dnsrec, ARES_TRUE, hquery->port, hquery->ai);
944 }
945
946 /* We sent out ipv4 and ipv6 requests simultaneously. If we got a
947 * successful ipv4 response, we want to go ahead and tell the ipv6 request
948 * that if it fails or times out to not try again since we have the data
949 * we need.
950 *
951 * Our initial implementation of this would terminate retries if we got any
952 * successful response (ipv4 _or_ ipv6). But we did get some user-reported
953 * issues with this that had bad system configs and odd behavior:
954 * https://github.com/alpinelinux/docker-alpine/issues/366
955 *
956 * Essentially the ipv6 query succeeded but the ipv4 query failed or timed
957 * out, and so we only returned the ipv6 address, but the host couldn't
958 * use ipv6. If we continued to allow ipv4 retries it would have found a
959 * server that worked and returned both address classes (this is clearly
960 * unexpected behavior).
961 *
962 * At some point down the road if ipv6 actually becomes required and
963 * reliable we can drop this ipv4 check.
964 */
965 if (addinfostatus == ARES_SUCCESS && ai_has_ipv4(hquery->ai)) {
966 terminate_retries(hquery, ares_dns_record_get_id(dnsrec));
967 }
968 }
969 #if OHOS_DNS_PROXY_BY_NETSYS
970 ares_parse_query_info(status, dnsrec, hquery);
971 #endif
972 if (!hquery->remaining) {
973 if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) {
974 /* must make sure we don't do next_lookup() on destroy or cancel,
975 * and return the appropriate status. We won't return a partial
976 * result in this case. */
977 end_hquery(hquery, status);
978 } else if (addinfostatus != ARES_SUCCESS && addinfostatus != ARES_ENODATA) {
979 /* error in parsing result e.g. no memory */
980 if (addinfostatus == ARES_EBADRESP && hquery->ai->nodes) {
981 /* We got a bad response from server, but at least one query
982 * ended with ARES_SUCCESS */
983 end_hquery(hquery, ARES_SUCCESS);
984 } else {
985 end_hquery(hquery, addinfostatus);
986 }
987 } else if (hquery->ai->nodes) {
988 /* at least one query ended with ARES_SUCCESS */
989 end_hquery(hquery, ARES_SUCCESS);
990 } else if (status == ARES_ENOTFOUND || status == ARES_ENODATA ||
991 addinfostatus == ARES_ENODATA) {
992 if (status == ARES_ENODATA || addinfostatus == ARES_ENODATA) {
993 hquery->nodata_cnt++;
994 }
995 #if OHOS_DNS_PROXY_BY_NETSYS
996 if (hquery->nodata_cnt < ares_slist_len(hquery->channel->servers) && hquery->nodata_cnt > 0) {
997 hquery->next_name_idx--;
998 ares_slist_node_t *node;
999 ares_server_t *server;
1000 server = ares_slist_node_val(ares_slist_node_first(hquery->channel->servers));
1001 server->consec_failures++;
1002 node = ares_slist_node_find(hquery->channel->servers, server);
1003 ares_slist_node_reinsert(node);
1004 ares_qcache_flush(hquery->channel->qcache);
1005 }
1006 #endif
1007 next_lookup(hquery, hquery->nodata_cnt ? ARES_ENODATA : status);
1008 } else if ((status == ARES_ESERVFAIL || status == ARES_EREFUSED) &&
1009 ares_name_label_cnt(hquery->names[hquery->next_name_idx - 1]) ==
1010 1) {
1011 /* Issue #852, systemd-resolved may return SERVFAIL or REFUSED on a
1012 * single label domain name. */
1013 next_lookup(hquery, hquery->nodata_cnt ? ARES_ENODATA : status);
1014 } else {
1015 end_hquery(hquery, status);
1016 }
1017 }
1018
1019 /* at this point we keep on waiting for the next query to finish */
1020 }
1021
ares_getaddrinfo_int(ares_channel_t * channel,const char * name,const char * service,const struct ares_addrinfo_hints * hints,ares_addrinfo_callback callback,void * arg)1022 static void ares_getaddrinfo_int(ares_channel_t *channel, const char *name,
1023 const char *service,
1024 const struct ares_addrinfo_hints *hints,
1025 ares_addrinfo_callback callback, void *arg)
1026 {
1027 #if OHOS_DNS_PROXY_BY_NETSYS
1028 long long time_now = ares_get_now_time();
1029 struct ares_addrinfo *cache_res = ares_get_dns_cache(name, service, hints);
1030 if (cache_res && cache_res->nodes) {
1031 ares_record_process(ARES_SUCCESS, name, time_now, cache_res, NULL);
1032 callback(arg, ARES_SUCCESS, 0, cache_res);
1033 return;
1034 }
1035 #endif
1036 struct host_query *hquery;
1037 unsigned short port = 0;
1038 int family;
1039 struct ares_addrinfo *ai;
1040 ares_status_t status;
1041
1042 if (!hints) {
1043 hints = &default_hints;
1044 }
1045
1046 family = hints->ai_family;
1047
1048 /* Right now we only know how to look up Internet addresses
1049 and unspec means try both basically. */
1050 if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) {
1051 callback(arg, ARES_ENOTIMP, 0, NULL);
1052 return;
1053 }
1054
1055 if (ares_is_onion_domain(name)) {
1056 callback(arg, ARES_ENOTFOUND, 0, NULL);
1057 return;
1058 }
1059
1060 if (service) {
1061 if (hints->ai_flags & ARES_AI_NUMERICSERV) {
1062 unsigned long val;
1063 errno = 0;
1064 val = strtoul(service, NULL, 0);
1065 if ((val == 0 && errno != 0) || val > 65535) {
1066 callback(arg, ARES_ESERVICE, 0, NULL);
1067 return;
1068 }
1069 port = (unsigned short)val;
1070 } else {
1071 port = lookup_service(service, 0);
1072 if (!port) {
1073 unsigned long val;
1074 errno = 0;
1075 val = strtoul(service, NULL, 0);
1076 if ((val == 0 && errno != 0) || val > 65535) {
1077 callback(arg, ARES_ESERVICE, 0, NULL);
1078 return;
1079 }
1080 port = (unsigned short)val;
1081 }
1082 }
1083 }
1084
1085 ai = ares_malloc_zero(sizeof(*ai));
1086 if (!ai) {
1087 callback(arg, ARES_ENOMEM, 0, NULL);
1088 return;
1089 }
1090
1091 if (fake_addrinfo(name, port, hints, ai, callback, arg)) {
1092 return;
1093 }
1094
1095 /* Allocate and fill in the host query structure. */
1096 hquery = ares_malloc_zero(sizeof(*hquery));
1097 if (!hquery) {
1098 ares_freeaddrinfo(ai);
1099 callback(arg, ARES_ENOMEM, 0, NULL);
1100 return;
1101 }
1102
1103 hquery->port = port;
1104 hquery->channel = channel;
1105 hquery->hints = *hints;
1106 hquery->sent_family = -1; /* nothing is sent yet */
1107 hquery->callback = callback;
1108 hquery->arg = arg;
1109 hquery->ai = ai;
1110 hquery->name = ares_strdup(name);
1111 #if OHOS_DNS_PROXY_BY_NETSYS
1112 hquery->src_addr = NULL;
1113 hquery->process_info.queryTime = time_now;
1114 hquery->process_info.retCode = ARES_ENODATA;
1115 hquery->process_info.firstQueryEndDuration = 0;
1116 hquery->process_info.firstQueryEnd2AppDuration = 0;
1117 hquery->process_info.firstReturnType = 0;
1118 hquery->process_info.sourceFrom = SOURCE_FROM_CARES;
1119 hquery->process_info.ipv4QueryInfo = empty_family_query_info;
1120 hquery->process_info.ipv6QueryInfo = empty_family_query_info;
1121 #endif
1122 if (hquery->name == NULL) {
1123 #if OHOS_DNS_PROXY_BY_NETSYS
1124 ares_record_process(ARES_ENOMEM, name, time_now, NULL, NULL);
1125 #endif
1126 hquery_free(hquery, ARES_TRUE);
1127 callback(arg, ARES_ENOMEM, 0, NULL);
1128 return;
1129 }
1130
1131 status =
1132 ares_search_name_list(channel, name, &hquery->names, &hquery->names_cnt);
1133 if (status != ARES_SUCCESS) {
1134 #if OHOS_DNS_PROXY_BY_NETSYS
1135 ares_record_process(status, name, time_now, NULL, NULL);
1136 #endif
1137 hquery_free(hquery, ARES_TRUE);
1138 callback(arg, (int)status, 0, NULL);
1139 return;
1140 }
1141 hquery->next_name_idx = 0;
1142
1143
1144 hquery->lookups = ares_strdup(channel->lookups);
1145 if (hquery->lookups == NULL) {
1146 #if OHOS_DNS_PROXY_BY_NETSYS
1147 ares_record_process(status, name, time_now, NULL, NULL);
1148 #endif
1149 hquery_free(hquery, ARES_TRUE);
1150 callback(arg, ARES_ENOMEM, 0, NULL);
1151 return;
1152 }
1153 hquery->remaining_lookups = hquery->lookups;
1154
1155 /* Start performing lookups according to channel->lookups. */
1156 next_lookup(hquery, ARES_ECONNREFUSED /* initial error code */);
1157 }
1158
ares_getaddrinfo(ares_channel_t * channel,const char * name,const char * service,const struct ares_addrinfo_hints * hints,ares_addrinfo_callback callback,void * arg)1159 void ares_getaddrinfo(ares_channel_t *channel, const char *name,
1160 const char *service,
1161 const struct ares_addrinfo_hints *hints,
1162 ares_addrinfo_callback callback, void *arg)
1163 {
1164 if (channel == NULL) {
1165 return;
1166 }
1167 ares_channel_lock(channel);
1168 ares_getaddrinfo_int(channel, name, service, hints, callback, arg);
1169 ares_channel_unlock(channel);
1170 }
1171
next_dns_lookup(struct host_query * hquery)1172 static ares_bool_t next_dns_lookup(struct host_query *hquery)
1173 {
1174 const char *name = NULL;
1175
1176 if (hquery->next_name_idx >= hquery->names_cnt) {
1177 return ARES_FALSE;
1178 }
1179
1180 name = hquery->names[hquery->next_name_idx++];
1181
1182 /* NOTE: hquery may be invalidated during the call to ares_query_qid(),
1183 * so should not be referenced after this point */
1184 switch (hquery->hints.ai_family) {
1185 case AF_INET:
1186 hquery->remaining += 1;
1187 ares_query_nolock(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_A,
1188 host_callback, hquery, &hquery->qid_a);
1189 break;
1190 case AF_INET6:
1191 hquery->remaining += 1;
1192 ares_query_nolock(hquery->channel, name, ARES_CLASS_IN,
1193 ARES_REC_TYPE_AAAA, host_callback, hquery,
1194 &hquery->qid_aaaa);
1195 break;
1196 case AF_UNSPEC:
1197 hquery->remaining += 2;
1198 ares_query_nolock(hquery->channel, name, ARES_CLASS_IN, ARES_REC_TYPE_A,
1199 host_callback, hquery, &hquery->qid_a);
1200 ares_query_nolock(hquery->channel, name, ARES_CLASS_IN,
1201 ARES_REC_TYPE_AAAA, host_callback, hquery,
1202 &hquery->qid_aaaa);
1203 break;
1204 default:
1205 break;
1206 }
1207
1208 return ARES_TRUE;
1209 }
1210