1 /** @file
2 * @brief DNS resolve API
3 *
4 * An API for applications to do DNS query.
5 */
6
7 /*
8 * Copyright (c) 2017 Intel Corporation
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #include <logging/log.h>
14 LOG_MODULE_REGISTER(net_dns_resolve, CONFIG_DNS_RESOLVER_LOG_LEVEL);
15
16 #include <zephyr/types.h>
17 #include <random/rand32.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <stdlib.h>
21
22 #include <sys/crc.h>
23 #include <net/net_ip.h>
24 #include <net/net_pkt.h>
25 #include <net/net_mgmt.h>
26 #include <net/dns_resolve.h>
27 #include "dns_pack.h"
28 #include "dns_internal.h"
29
30 #define DNS_SERVER_COUNT CONFIG_DNS_RESOLVER_MAX_SERVERS
31 #define SERVER_COUNT (DNS_SERVER_COUNT + DNS_MAX_MCAST_SERVERS)
32
33 #define MDNS_IPV4_ADDR "224.0.0.251:5353"
34 #define MDNS_IPV6_ADDR "[ff02::fb]:5353"
35
36 #define LLMNR_IPV4_ADDR "224.0.0.252:5355"
37 #define LLMNR_IPV6_ADDR "[ff02::1:3]:5355"
38
39 #define DNS_BUF_TIMEOUT K_MSEC(500) /* ms */
40
41 /* RFC 1035, 3.1. Name space definitions
42 * To simplify implementations, the total length of a domain name (i.e.,
43 * label octets and label length octets) is restricted to 255 octets or
44 * less.
45 */
46 #define DNS_MAX_NAME_LEN 255
47
48 #define DNS_QUERY_MAX_SIZE (DNS_MSG_HEADER_SIZE + DNS_MAX_NAME_LEN + \
49 DNS_QTYPE_LEN + DNS_QCLASS_LEN)
50
51 /* This value is recommended by RFC 1035 */
52 #define DNS_RESOLVER_MAX_BUF_SIZE 512
53 #define DNS_RESOLVER_MIN_BUF 1
54 #define DNS_RESOLVER_BUF_CTR (DNS_RESOLVER_MIN_BUF + \
55 CONFIG_DNS_RESOLVER_ADDITIONAL_BUF_CTR)
56
57 /* Compressed RR uses a pointer to another RR. So, min size is 12 bytes without
58 * considering RR payload.
59 * See https://tools.ietf.org/html/rfc1035#section-4.1.4
60 */
61 #define DNS_ANSWER_PTR_LEN 12
62
63 /* See dns_unpack_answer, and also see:
64 * https://tools.ietf.org/html/rfc1035#section-4.1.2
65 */
66 #define DNS_QUERY_POS 0x0c
67
68 #define DNS_IPV4_LEN sizeof(struct in_addr)
69 #define DNS_IPV6_LEN sizeof(struct in6_addr)
70
71 NET_BUF_POOL_DEFINE(dns_msg_pool, DNS_RESOLVER_BUF_CTR,
72 DNS_RESOLVER_MAX_BUF_SIZE, 0, NULL);
73
74 NET_BUF_POOL_DEFINE(dns_qname_pool, DNS_RESOLVER_BUF_CTR, DNS_MAX_NAME_LEN,
75 0, NULL);
76
77 static struct dns_resolve_context dns_default_ctx;
78
79 /* Must be invoked with context lock held */
80 static int dns_write(struct dns_resolve_context *ctx,
81 int server_idx,
82 int query_idx,
83 struct net_buf *dns_data,
84 struct net_buf *dns_qname,
85 int hop_limit);
86
server_is_mdns(sa_family_t family,struct sockaddr * addr)87 static bool server_is_mdns(sa_family_t family, struct sockaddr *addr)
88 {
89 if (family == AF_INET) {
90 if (net_ipv4_is_addr_mcast(&net_sin(addr)->sin_addr) &&
91 net_sin(addr)->sin_addr.s4_addr[3] == 251U) {
92 return true;
93 }
94
95 return false;
96 }
97
98 if (family == AF_INET6) {
99 if (net_ipv6_is_addr_mcast(&net_sin6(addr)->sin6_addr) &&
100 net_sin6(addr)->sin6_addr.s6_addr[15] == 0xfb) {
101 return true;
102 }
103
104 return false;
105 }
106
107 return false;
108 }
109
server_is_llmnr(sa_family_t family,struct sockaddr * addr)110 static bool server_is_llmnr(sa_family_t family, struct sockaddr *addr)
111 {
112 if (family == AF_INET) {
113 if (net_ipv4_is_addr_mcast(&net_sin(addr)->sin_addr) &&
114 net_sin(addr)->sin_addr.s4_addr[3] == 252U) {
115 return true;
116 }
117
118 return false;
119 }
120
121 if (family == AF_INET6) {
122 if (net_ipv6_is_addr_mcast(&net_sin6(addr)->sin6_addr) &&
123 net_sin6(addr)->sin6_addr.s6_addr[15] == 0x03) {
124 return true;
125 }
126
127 return false;
128 }
129
130 return false;
131 }
132
dns_postprocess_server(struct dns_resolve_context * ctx,int idx)133 static void dns_postprocess_server(struct dns_resolve_context *ctx, int idx)
134 {
135 struct sockaddr *addr = &ctx->servers[idx].dns_server;
136
137 if (addr->sa_family == AF_INET) {
138 ctx->servers[idx].is_mdns = server_is_mdns(AF_INET, addr);
139 if (!ctx->servers[idx].is_mdns) {
140 ctx->servers[idx].is_llmnr =
141 server_is_llmnr(AF_INET, addr);
142 }
143
144 if (net_sin(addr)->sin_port == 0U) {
145 if (IS_ENABLED(CONFIG_MDNS_RESOLVER) &&
146 ctx->servers[idx].is_mdns) {
147 /* We only use 5353 as a default port
148 * if mDNS support is enabled. User can
149 * override this by defining the port
150 * in config file.
151 */
152 net_sin(addr)->sin_port = htons(5353);
153 } else if (IS_ENABLED(CONFIG_LLMNR_RESOLVER) &&
154 ctx->servers[idx].is_llmnr) {
155 /* We only use 5355 as a default port
156 * if LLMNR support is enabled. User can
157 * override this by defining the port
158 * in config file.
159 */
160 net_sin(addr)->sin_port = htons(5355);
161 } else {
162 net_sin(addr)->sin_port = htons(53);
163 }
164 }
165 } else {
166 ctx->servers[idx].is_mdns = server_is_mdns(AF_INET6, addr);
167 if (!ctx->servers[idx].is_mdns) {
168 ctx->servers[idx].is_llmnr =
169 server_is_llmnr(AF_INET6, addr);
170 }
171
172 if (net_sin6(addr)->sin6_port == 0U) {
173 if (IS_ENABLED(CONFIG_MDNS_RESOLVER) &&
174 ctx->servers[idx].is_mdns) {
175 net_sin6(addr)->sin6_port = htons(5353);
176 } else if (IS_ENABLED(CONFIG_LLMNR_RESOLVER) &&
177 ctx->servers[idx].is_llmnr) {
178 net_sin6(addr)->sin6_port = htons(5355);
179 } else {
180 net_sin6(addr)->sin6_port = htons(53);
181 }
182 }
183 }
184 }
185
186 /* Must be invoked with context lock held */
dns_resolve_init_locked(struct dns_resolve_context * ctx,const char * servers[],const struct sockaddr * servers_sa[])187 static int dns_resolve_init_locked(struct dns_resolve_context *ctx,
188 const char *servers[],
189 const struct sockaddr *servers_sa[])
190 {
191 #if defined(CONFIG_NET_IPV6)
192 struct sockaddr_in6 local_addr6 = {
193 .sin6_family = AF_INET6,
194 .sin6_port = 0,
195 };
196 #endif
197 #if defined(CONFIG_NET_IPV4)
198 struct sockaddr_in local_addr4 = {
199 .sin_family = AF_INET,
200 .sin_port = 0,
201 };
202 #endif
203 struct sockaddr *local_addr = NULL;
204 socklen_t addr_len = 0;
205 int i = 0, idx = 0;
206 struct net_if *iface;
207 int ret, count;
208
209 if (!ctx) {
210 return -ENOENT;
211 }
212
213 if (ctx->state != DNS_RESOLVE_CONTEXT_INACTIVE) {
214 ret = -ENOTEMPTY;
215 goto fail;
216 }
217
218 if (servers) {
219 for (i = 0; idx < SERVER_COUNT && servers[i]; i++) {
220 struct sockaddr *addr = &ctx->servers[idx].dns_server;
221
222 (void)memset(addr, 0, sizeof(*addr));
223
224 ret = net_ipaddr_parse(servers[i], strlen(servers[i]),
225 addr);
226 if (!ret) {
227 continue;
228 }
229
230 dns_postprocess_server(ctx, idx);
231
232 NET_DBG("[%d] %s%s%s", i, log_strdup(servers[i]),
233 IS_ENABLED(CONFIG_MDNS_RESOLVER) ?
234 (ctx->servers[i].is_mdns ? " mDNS" : "") : "",
235 IS_ENABLED(CONFIG_LLMNR_RESOLVER) ?
236 (ctx->servers[i].is_llmnr ?
237 " LLMNR" : "") : "");
238 idx++;
239 }
240 }
241
242 if (servers_sa) {
243 for (i = 0; idx < SERVER_COUNT && servers_sa[i]; i++) {
244 memcpy(&ctx->servers[idx].dns_server, servers_sa[i],
245 sizeof(ctx->servers[idx].dns_server));
246 dns_postprocess_server(ctx, idx);
247 idx++;
248 }
249 }
250
251 for (i = 0, count = 0;
252 i < SERVER_COUNT && ctx->servers[i].dns_server.sa_family; i++) {
253
254 if (ctx->servers[i].dns_server.sa_family == AF_INET6) {
255 #if defined(CONFIG_NET_IPV6)
256 local_addr = (struct sockaddr *)&local_addr6;
257 addr_len = sizeof(struct sockaddr_in6);
258
259 if (IS_ENABLED(CONFIG_MDNS_RESOLVER) &&
260 ctx->servers[i].is_mdns) {
261 local_addr6.sin6_port = htons(5353);
262 }
263 #else
264 continue;
265 #endif
266 }
267
268 if (ctx->servers[i].dns_server.sa_family == AF_INET) {
269 #if defined(CONFIG_NET_IPV4)
270 local_addr = (struct sockaddr *)&local_addr4;
271 addr_len = sizeof(struct sockaddr_in);
272
273 if (IS_ENABLED(CONFIG_MDNS_RESOLVER) &&
274 ctx->servers[i].is_mdns) {
275 local_addr4.sin_port = htons(5353);
276 }
277 #else
278 continue;
279 #endif
280 }
281
282 if (!local_addr) {
283 NET_DBG("Local address not set");
284 ret = -EAFNOSUPPORT;
285 goto fail;
286 }
287
288 ret = net_context_get(ctx->servers[i].dns_server.sa_family,
289 SOCK_DGRAM, IPPROTO_UDP,
290 &ctx->servers[i].net_ctx);
291 if (ret < 0) {
292 NET_DBG("Cannot get net_context (%d)", ret);
293 goto fail;
294 }
295
296 ret = net_context_bind(ctx->servers[i].net_ctx,
297 local_addr, addr_len);
298 if (ret < 0) {
299 NET_DBG("Cannot bind DNS context (%d)", ret);
300 goto fail;
301 }
302
303 iface = net_context_get_iface(ctx->servers[i].net_ctx);
304
305 if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) {
306 net_mgmt_event_notify_with_info(
307 NET_EVENT_DNS_SERVER_ADD,
308 iface, (void *)&ctx->servers[i].dns_server,
309 sizeof(struct sockaddr));
310 } else {
311 net_mgmt_event_notify(NET_EVENT_DNS_SERVER_ADD, iface);
312 }
313
314 #if defined(CONFIG_NET_IPV6)
315 local_addr6.sin6_port = 0;
316 #endif
317
318 #if defined(CONFIG_NET_IPV4)
319 local_addr4.sin_port = 0;
320 #endif
321
322 count++;
323 }
324
325 if (count == 0) {
326 /* No servers defined */
327 NET_DBG("No DNS servers defined.");
328 ret = -EINVAL;
329 goto fail;
330 }
331
332 ctx->state = DNS_RESOLVE_CONTEXT_ACTIVE;
333 ctx->buf_timeout = DNS_BUF_TIMEOUT;
334 ret = 0;
335
336 fail:
337 return ret;
338 }
339
dns_resolve_init(struct dns_resolve_context * ctx,const char * servers[],const struct sockaddr * servers_sa[])340 int dns_resolve_init(struct dns_resolve_context *ctx, const char *servers[],
341 const struct sockaddr *servers_sa[])
342 {
343 if (!ctx) {
344 return -ENOENT;
345 }
346
347 (void)memset(ctx, 0, sizeof(*ctx));
348
349 (void)k_mutex_init(&ctx->lock);
350 ctx->state = DNS_RESOLVE_CONTEXT_INACTIVE;
351
352 /* As this function is called only once during system init, there is no
353 * reason to acquire lock.
354 */
355 return dns_resolve_init_locked(ctx, servers, servers_sa);
356 }
357
358 /* Check whether a slot is available for use, or optionally whether it can be
359 * reclaimed.
360 *
361 * @param pending_query the query slot in question
362 *
363 * @param reclaim_if_available if the slot is marked in use, but the query has
364 * been completed and the work item is no longer pending, complete the release
365 * of the slot.
366 *
367 * @return true if and only if the slot can be used for a new query.
368 */
check_query_active(struct dns_pending_query * pending_query,bool reclaim_if_available)369 static inline bool check_query_active(struct dns_pending_query *pending_query,
370 bool reclaim_if_available)
371 {
372 int ret = false;
373
374 if (pending_query->cb != NULL) {
375 ret = true;
376 if (reclaim_if_available
377 && pending_query->query == NULL
378 && k_work_delayable_busy_get(&pending_query->timer) == 0) {
379 pending_query->cb = NULL;
380 ret = false;
381 }
382 }
383
384 return ret;
385 }
386
387 /* Must be invoked with context lock held */
get_cb_slot(struct dns_resolve_context * ctx)388 static inline int get_cb_slot(struct dns_resolve_context *ctx)
389 {
390 int i;
391
392 for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
393 if (!check_query_active(&ctx->queries[i], true)) {
394 return i;
395 }
396 }
397
398 return -ENOENT;
399 }
400
401 /* Invoke the callback associated with a query slot, if still relevant.
402 *
403 * Must be invoked with context lock held.
404 *
405 * @param status the query status value
406 * @param info the query result structure
407 * @param pending_query the query slot that will provide the callback
408 **/
invoke_query_callback(int status,struct dns_addrinfo * info,struct dns_pending_query * pending_query)409 static inline void invoke_query_callback(int status,
410 struct dns_addrinfo *info,
411 struct dns_pending_query *pending_query)
412 {
413 /* Only notify if the slot is neither released nor in the process of
414 * being released.
415 */
416 if (pending_query->query != NULL) {
417 pending_query->cb(status, info, pending_query->user_data);
418 }
419 }
420
421 /* Release a query slot reserved by get_cb_slot().
422 *
423 * Must be invoked with context lock held.
424 *
425 * @param pending_query the query slot to be released
426 */
release_query(struct dns_pending_query * pending_query)427 static void release_query(struct dns_pending_query *pending_query)
428 {
429 int busy = k_work_cancel_delayable(&pending_query->timer);
430
431 /* If the work item is no longer pending we're done. */
432 if (busy == 0) {
433 /* All done. */
434 pending_query->cb = NULL;
435 } else {
436 /* Work item is still pending. Set a secondary condition that
437 * can be checked by get_cb_slot() to complete release of the
438 * slot once the work item has been confirmed to be completed.
439 */
440 pending_query->query = NULL;
441 }
442 }
443
444 /* Must be invoked with context lock held */
get_slot_by_id(struct dns_resolve_context * ctx,uint16_t dns_id,uint16_t query_hash)445 static inline int get_slot_by_id(struct dns_resolve_context *ctx,
446 uint16_t dns_id,
447 uint16_t query_hash)
448 {
449 int i;
450
451 for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
452 if (check_query_active(&ctx->queries[i], false) &&
453 ctx->queries[i].id == dns_id &&
454 (query_hash == 0 ||
455 ctx->queries[i].query_hash == query_hash)) {
456 return i;
457 }
458 }
459
460 return -ENOENT;
461 }
462
463 /* Unit test needs to be able to call this function */
464 #if !defined(CONFIG_NET_TEST)
465 static
466 #endif
dns_validate_msg(struct dns_resolve_context * ctx,struct dns_msg_t * dns_msg,uint16_t * dns_id,int * query_idx,struct net_buf * dns_cname,uint16_t * query_hash)467 int dns_validate_msg(struct dns_resolve_context *ctx,
468 struct dns_msg_t *dns_msg,
469 uint16_t *dns_id,
470 int *query_idx,
471 struct net_buf *dns_cname,
472 uint16_t *query_hash)
473 {
474 struct dns_addrinfo info = { 0 };
475 uint32_t ttl; /* RR ttl, so far it is not passed to caller */
476 uint8_t *src, *addr;
477 const char *query_name;
478 int address_size;
479 /* index that points to the current answer being analyzed */
480 int answer_ptr;
481 int items;
482 int server_idx;
483 int ret = 0;
484
485 /* Make sure that we can read DNS id, flags and rcode */
486 if (dns_msg->msg_size < (sizeof(*dns_id) + sizeof(uint16_t))) {
487 ret = DNS_EAI_FAIL;
488 goto quit;
489 }
490
491 /* The dns_unpack_response_header() has design flaw as it expects
492 * dns id to be given instead of returning the id to the caller.
493 * In our case we would like to get it returned instead so that we
494 * can match the DNS query that we sent. When dns_read() is called,
495 * we do not know what the DNS id is yet.
496 */
497 *dns_id = dns_unpack_header_id(dns_msg->msg);
498
499 if (dns_header_rcode(dns_msg->msg) == DNS_HEADER_REFUSED) {
500 ret = DNS_EAI_FAIL;
501 goto quit;
502 }
503
504 /* We might receive a query while we are waiting for a response, in that
505 * case we just ignore the query instead of making the resolving fail.
506 */
507 if (dns_header_qr(dns_msg->msg) == DNS_QUERY) {
508 ret = 0;
509 goto quit;
510 }
511
512 ret = dns_unpack_response_header(dns_msg, *dns_id);
513 if (ret < 0) {
514 ret = DNS_EAI_FAIL;
515 goto quit;
516 }
517
518 if (dns_header_qdcount(dns_msg->msg) != 1) {
519 /* For mDNS (when dns_id == 0) the query count is 0 */
520 if (*dns_id > 0) {
521 ret = DNS_EAI_FAIL;
522 goto quit;
523 }
524 }
525
526 ret = dns_unpack_response_query(dns_msg);
527 if (ret < 0) {
528 /* Check mDNS like above */
529 if (*dns_id > 0) {
530 ret = DNS_EAI_FAIL;
531 goto quit;
532 }
533
534 /* mDNS responses to do not have the query part so the
535 * answer starts immediately after the header.
536 */
537 dns_msg->answer_offset = dns_msg->query_offset;
538 }
539
540 /* Because in mDNS the DNS id is set to 0 and must be ignored
541 * on reply, we need to figure out the answer in order to find
542 * the proper query. To simplify things, the normal DNS responses
543 * are handled the same way.
544 */
545
546 answer_ptr = DNS_QUERY_POS;
547 items = 0;
548 server_idx = 0;
549 enum dns_rr_type answer_type = DNS_RR_TYPE_INVALID;
550
551 while (server_idx < dns_header_ancount(dns_msg->msg)) {
552 ret = dns_unpack_answer(dns_msg, answer_ptr, &ttl,
553 &answer_type);
554 if (ret < 0) {
555 ret = DNS_EAI_FAIL;
556 goto quit;
557 }
558
559 switch (dns_msg->response_type) {
560 case DNS_RESPONSE_IP:
561 if (*query_idx >= 0) {
562 goto query_known;
563 }
564
565 query_name = dns_msg->msg + dns_msg->query_offset;
566
567 /* Add \0 and query type (A or AAAA) to the hash */
568 *query_hash = crc16_ansi(query_name,
569 strlen(query_name) + 1 + 2);
570
571 *query_idx = get_slot_by_id(ctx, *dns_id, *query_hash);
572 if (*query_idx < 0) {
573 ret = DNS_EAI_SYSTEM;
574 goto quit;
575 }
576
577 query_known:
578 if (ctx->queries[*query_idx].query_type ==
579 DNS_QUERY_TYPE_A) {
580 if (answer_type != DNS_RR_TYPE_A) {
581 ret = DNS_EAI_ADDRFAMILY;
582 goto quit;
583 }
584
585 address_size = DNS_IPV4_LEN;
586 addr = (uint8_t *)&net_sin(&info.ai_addr)->
587 sin_addr;
588 info.ai_family = AF_INET;
589 info.ai_addr.sa_family = AF_INET;
590 info.ai_addrlen = sizeof(struct sockaddr_in);
591
592 } else if (ctx->queries[*query_idx].query_type ==
593 DNS_QUERY_TYPE_AAAA) {
594 if (answer_type != DNS_RR_TYPE_AAAA) {
595 ret = DNS_EAI_ADDRFAMILY;
596 goto quit;
597 }
598
599 /* We cannot resolve IPv6 address if IPv6 is
600 * disabled. The reason being that
601 * "struct sockaddr" does not have enough space
602 * for IPv6 address in that case.
603 */
604 #if defined(CONFIG_NET_IPV6)
605 address_size = DNS_IPV6_LEN;
606 addr = (uint8_t *)&net_sin6(&info.ai_addr)->
607 sin6_addr;
608 info.ai_family = AF_INET6;
609 info.ai_addr.sa_family = AF_INET6;
610 info.ai_addrlen = sizeof(struct sockaddr_in6);
611 #else
612 ret = DNS_EAI_FAMILY;
613 goto quit;
614 #endif
615 } else {
616 ret = DNS_EAI_FAMILY;
617 goto quit;
618 }
619
620 if (dns_msg->response_length < address_size) {
621 /* it seems this is a malformed message */
622 ret = DNS_EAI_FAIL;
623 goto quit;
624 }
625
626 if ((dns_msg->response_position + address_size) >
627 dns_msg->msg_size) {
628 /* Too short message */
629 ret = DNS_EAI_FAIL;
630 goto quit;
631 }
632
633 src = dns_msg->msg + dns_msg->response_position;
634 memcpy(addr, src, address_size);
635
636 invoke_query_callback(DNS_EAI_INPROGRESS, &info,
637 &ctx->queries[*query_idx]);
638 items++;
639 break;
640
641 case DNS_RESPONSE_CNAME_NO_IP:
642 /* Instead of using the QNAME at DNS_QUERY_POS,
643 * we will use this CNAME
644 */
645 answer_ptr = dns_msg->response_position;
646 break;
647
648 default:
649 ret = DNS_EAI_FAIL;
650 goto quit;
651 }
652
653 /* Update the answer offset to point to the next RR (answer) */
654 dns_msg->answer_offset += dns_msg->response_position -
655 dns_msg->answer_offset;
656 dns_msg->answer_offset += dns_msg->response_length;
657
658 server_idx++;
659 }
660
661 if (*query_idx < 0) {
662 /* If the query_idx is still unknown, try to get it here
663 * and hope it is found.
664 */
665 query_name = dns_msg->msg + dns_msg->query_offset;
666 *query_hash = crc16_ansi(query_name,
667 strlen(query_name) + 1 + 2);
668
669 *query_idx = get_slot_by_id(ctx, *dns_id, *query_hash);
670 if (*query_idx < 0) {
671 ret = DNS_EAI_SYSTEM;
672 goto quit;
673 }
674 }
675
676 /* No IP addresses were found, so we take the last CNAME to generate
677 * another query. Number of additional queries is controlled via Kconfig
678 */
679 if (items == 0) {
680 if (dns_msg->response_type == DNS_RESPONSE_CNAME_NO_IP) {
681 uint16_t pos = dns_msg->response_position;
682
683 /* The dns_cname should always be set. As a special
684 * case, it might not be set for unit tests that call
685 * this function directly.
686 */
687 if (dns_cname) {
688 ret = dns_copy_qname(dns_cname->data,
689 &dns_cname->len,
690 dns_cname->size,
691 dns_msg, pos);
692 if (ret < 0) {
693 ret = DNS_EAI_SYSTEM;
694 goto quit;
695 }
696 }
697
698 ret = DNS_EAI_AGAIN;
699 goto quit;
700 }
701 }
702
703 if (items == 0) {
704 ret = DNS_EAI_NODATA;
705 } else {
706 ret = DNS_EAI_ALLDONE;
707 }
708
709 quit:
710 return ret;
711 }
712
713 /* Must be invoked with context lock held */
dns_read(struct dns_resolve_context * ctx,struct net_pkt * pkt,struct net_buf * dns_data,uint16_t * dns_id,struct net_buf * dns_cname,uint16_t * query_hash)714 static int dns_read(struct dns_resolve_context *ctx,
715 struct net_pkt *pkt,
716 struct net_buf *dns_data,
717 uint16_t *dns_id,
718 struct net_buf *dns_cname,
719 uint16_t *query_hash)
720 {
721 /* Helper struct to track the dns msg received from the server */
722 struct dns_msg_t dns_msg;
723 int data_len;
724 int ret;
725 int query_idx = -1;
726
727 data_len = MIN(net_pkt_remaining_data(pkt), DNS_RESOLVER_MAX_BUF_SIZE);
728
729 /* TODO: Instead of this temporary copy, just use the net_pkt directly.
730 */
731 ret = net_pkt_read(pkt, dns_data->data, data_len);
732 if (ret < 0) {
733 ret = DNS_EAI_MEMORY;
734 goto quit;
735 }
736
737 dns_msg.msg = dns_data->data;
738 dns_msg.msg_size = data_len;
739
740 ret = dns_validate_msg(ctx, &dns_msg, dns_id, &query_idx,
741 dns_cname, query_hash);
742 if (ret == DNS_EAI_AGAIN) {
743 goto finished;
744 }
745
746 if (ret < 0) {
747 goto quit;
748 }
749
750 invoke_query_callback(ret, NULL, &ctx->queries[query_idx]);
751
752 /* Marks the end of the results */
753 release_query(&ctx->queries[query_idx]);
754
755 net_pkt_unref(pkt);
756
757 return 0;
758
759 finished:
760 dns_resolve_cancel_with_name(ctx, *dns_id,
761 ctx->queries[query_idx].query,
762 ctx->queries[query_idx].query_type);
763 quit:
764 net_pkt_unref(pkt);
765
766 return ret;
767 }
768
cb_recv(struct net_context * net_ctx,struct net_pkt * pkt,union net_ip_header * ip_hdr,union net_proto_header * proto_hdr,int status,void * user_data)769 static void cb_recv(struct net_context *net_ctx,
770 struct net_pkt *pkt,
771 union net_ip_header *ip_hdr,
772 union net_proto_header *proto_hdr,
773 int status,
774 void *user_data)
775 {
776 struct dns_resolve_context *ctx = user_data;
777 struct net_buf *dns_cname = NULL;
778 struct net_buf *dns_data = NULL;
779 uint16_t query_hash = 0U;
780 uint16_t dns_id = 0U;
781 int ret, i;
782
783 ARG_UNUSED(net_ctx);
784
785 k_mutex_lock(&ctx->lock, K_FOREVER);
786
787 if (ctx->state != DNS_RESOLVE_CONTEXT_ACTIVE) {
788 goto unlock;
789 }
790
791 if (status) {
792 ret = DNS_EAI_SYSTEM;
793 goto quit;
794 }
795
796 dns_data = net_buf_alloc(&dns_msg_pool, ctx->buf_timeout);
797 if (!dns_data) {
798 ret = DNS_EAI_MEMORY;
799 goto quit;
800 }
801
802 dns_cname = net_buf_alloc(&dns_qname_pool, ctx->buf_timeout);
803 if (!dns_cname) {
804 ret = DNS_EAI_MEMORY;
805 goto quit;
806 }
807
808 ret = dns_read(ctx, pkt, dns_data, &dns_id, dns_cname, &query_hash);
809 if (!ret) {
810 /* We called the callback already in dns_read() if there
811 * was no errors.
812 */
813 goto free_buf;
814 }
815
816 /* Query again if we got CNAME */
817 if (ret == DNS_EAI_AGAIN) {
818 int failure = 0;
819 int j;
820
821 i = get_slot_by_id(ctx, dns_id, query_hash);
822 if (i < 0) {
823 goto free_buf;
824 }
825
826 for (j = 0; j < SERVER_COUNT; j++) {
827 if (!ctx->servers[j].net_ctx) {
828 continue;
829 }
830
831 ret = dns_write(ctx, j, i, dns_data, dns_cname, 0);
832 if (ret < 0) {
833 failure++;
834 }
835 }
836
837 if (failure) {
838 NET_DBG("DNS cname query failed %d times", failure);
839
840 if (failure == j) {
841 ret = DNS_EAI_SYSTEM;
842 goto quit;
843 }
844 }
845
846 goto free_buf;
847 }
848
849 quit:
850 i = get_slot_by_id(ctx, dns_id, query_hash);
851 if (i < 0) {
852 goto free_buf;
853 }
854
855 invoke_query_callback(ret, NULL, &ctx->queries[i]);
856
857 /* Marks the end of the results */
858 release_query(&ctx->queries[i]);
859
860 free_buf:
861 if (dns_data) {
862 net_buf_unref(dns_data);
863 }
864
865 if (dns_cname) {
866 net_buf_unref(dns_cname);
867 }
868
869 unlock:
870 k_mutex_unlock(&ctx->lock);
871 }
872
873 /* Must be invoked with context lock held */
dns_write(struct dns_resolve_context * ctx,int server_idx,int query_idx,struct net_buf * dns_data,struct net_buf * dns_qname,int hop_limit)874 static int dns_write(struct dns_resolve_context *ctx,
875 int server_idx,
876 int query_idx,
877 struct net_buf *dns_data,
878 struct net_buf *dns_qname,
879 int hop_limit)
880 {
881 enum dns_query_type query_type;
882 struct net_context *net_ctx;
883 struct sockaddr *server;
884 int server_addr_len;
885 uint16_t dns_id;
886 int ret;
887
888 net_ctx = ctx->servers[server_idx].net_ctx;
889 server = &ctx->servers[server_idx].dns_server;
890 dns_id = ctx->queries[query_idx].id;
891 query_type = ctx->queries[query_idx].query_type;
892
893 ret = dns_msg_pack_query(dns_data->data, &dns_data->len, dns_data->size,
894 dns_qname->data, dns_qname->len, dns_id,
895 (enum dns_rr_type)query_type);
896 if (ret < 0) {
897 return -EINVAL;
898 }
899
900 /* Add \0 and query type (A or AAAA) to the hash. Note that
901 * the dns_qname->len contains the length of \0
902 */
903 ctx->queries[query_idx].query_hash =
904 crc16_ansi(dns_data->data + DNS_MSG_HEADER_SIZE,
905 dns_qname->len + 2);
906
907 if (IS_ENABLED(CONFIG_NET_IPV6) &&
908 net_context_get_family(net_ctx) == AF_INET6) {
909 net_context_set_ipv6_hop_limit(net_ctx, hop_limit);
910 } else if (IS_ENABLED(CONFIG_NET_IPV4) &&
911 net_context_get_family(net_ctx) == AF_INET) {
912 net_context_set_ipv4_ttl(net_ctx, hop_limit);
913 }
914
915 ret = net_context_recv(net_ctx, cb_recv, K_NO_WAIT, ctx);
916 if (ret < 0 && ret != -EALREADY) {
917 NET_DBG("Could not receive from socket (%d)", ret);
918 return ret;
919 }
920
921 if (server->sa_family == AF_INET) {
922 server_addr_len = sizeof(struct sockaddr_in);
923 } else {
924 server_addr_len = sizeof(struct sockaddr_in6);
925 }
926
927 ret = k_work_reschedule(&ctx->queries[query_idx].timer,
928 ctx->queries[query_idx].timeout);
929 if (ret < 0) {
930 NET_DBG("[%u] cannot submit work to server idx %d for id %u "
931 "ret %d", query_idx, server_idx, dns_id, ret);
932 return ret;
933 }
934
935 NET_DBG("[%u] submitting work to server idx %d for id %u "
936 "hash %u", query_idx, server_idx, dns_id,
937 ctx->queries[query_idx].query_hash);
938
939 ret = net_context_sendto(net_ctx, dns_data->data, dns_data->len,
940 server, server_addr_len, NULL,
941 K_NO_WAIT, NULL);
942 if (ret < 0) {
943 NET_DBG("Cannot send query (%d)", ret);
944 return ret;
945 }
946
947 return 0;
948 }
949
950 /* Must be invoked with context lock held */
dns_resolve_cancel_slot(struct dns_resolve_context * ctx,int slot)951 static void dns_resolve_cancel_slot(struct dns_resolve_context *ctx, int slot)
952 {
953 invoke_query_callback(DNS_EAI_CANCELED, NULL, &ctx->queries[slot]);
954
955 release_query(&ctx->queries[slot]);
956 }
957
958 /* Must be invoked with context lock held */
dns_resolve_cancel_all(struct dns_resolve_context * ctx)959 static void dns_resolve_cancel_all(struct dns_resolve_context *ctx)
960 {
961 int i;
962
963 for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
964 if (ctx->queries[i].cb && ctx->queries[i].query) {
965 dns_resolve_cancel_slot(ctx, i);
966 }
967 }
968 }
969
dns_resolve_cancel_with_hash(struct dns_resolve_context * ctx,uint16_t dns_id,uint16_t query_hash,const char * query_name)970 static int dns_resolve_cancel_with_hash(struct dns_resolve_context *ctx,
971 uint16_t dns_id,
972 uint16_t query_hash,
973 const char *query_name)
974 {
975 int ret = 0;
976 int i;
977
978 k_mutex_lock(&ctx->lock, K_FOREVER);
979
980 if (ctx->state == DNS_RESOLVE_CONTEXT_DEACTIVATING) {
981 /*
982 * Cancel is part of context "deactivating" process, so no need
983 * to do anything more.
984 */
985 goto unlock;
986 }
987
988 i = get_slot_by_id(ctx, dns_id, query_hash);
989 if (i < 0) {
990 ret = -ENOENT;
991 goto unlock;
992 }
993
994 NET_DBG("Cancelling DNS req %u (name %s type %d hash %u)", dns_id,
995 log_strdup(query_name), ctx->queries[i].query_type,
996 query_hash);
997
998 dns_resolve_cancel_slot(ctx, i);
999
1000 unlock:
1001 k_mutex_unlock(&ctx->lock);
1002
1003 return 0;
1004 }
1005
dns_resolve_cancel_with_name(struct dns_resolve_context * ctx,uint16_t dns_id,const char * query_name,enum dns_query_type query_type)1006 int dns_resolve_cancel_with_name(struct dns_resolve_context *ctx,
1007 uint16_t dns_id,
1008 const char *query_name,
1009 enum dns_query_type query_type)
1010 {
1011 uint16_t query_hash = 0;
1012
1013 if (query_name) {
1014 struct net_buf *buf;
1015 uint16_t len;
1016 int ret;
1017
1018 /* Use net_buf as a temporary buffer to store the packed
1019 * DNS name.
1020 */
1021 buf = net_buf_alloc(&dns_msg_pool, ctx->buf_timeout);
1022 if (!buf) {
1023 return -ENOMEM;
1024 }
1025
1026 ret = dns_msg_pack_qname(&len, buf->data, buf->size,
1027 query_name);
1028 if (ret >= 0) {
1029 /* If the query string + \0 + query type (A or AAAA)
1030 * does not fit the tmp buf, then bail out
1031 */
1032 if ((len + 2) > buf->size) {
1033 net_buf_unref(buf);
1034 return -ENOMEM;
1035 }
1036
1037 net_buf_add(buf, len);
1038 net_buf_add_be16(buf, query_type);
1039
1040 query_hash = crc16_ansi(buf->data, len + 2);
1041 }
1042
1043 net_buf_unref(buf);
1044
1045 if (ret < 0) {
1046 return ret;
1047 }
1048 }
1049
1050 return dns_resolve_cancel_with_hash(ctx, dns_id, query_hash,
1051 query_name);
1052 }
1053
dns_resolve_cancel(struct dns_resolve_context * ctx,uint16_t dns_id)1054 int dns_resolve_cancel(struct dns_resolve_context *ctx, uint16_t dns_id)
1055 {
1056 return dns_resolve_cancel_with_name(ctx, dns_id, NULL, 0);
1057 }
1058
query_timeout(struct k_work * work)1059 static void query_timeout(struct k_work *work)
1060 {
1061 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
1062 struct dns_pending_query *pending_query =
1063 CONTAINER_OF(dwork, struct dns_pending_query, timer);
1064 int ret;
1065
1066 /* We have to take the lock as we're inspecting protected content
1067 * associated with the query. But don't block the system work queue:
1068 * if the lock can't be taken immediately, reschedule the work item to
1069 * be run again after everything else has had a chance.
1070 *
1071 * Note that it's OK to use the k_work API on the delayable work
1072 * without holding the lock: it's only the associated state in the
1073 * containing structure that must be protected.
1074 */
1075 ret = k_mutex_lock(&pending_query->ctx->lock, K_NO_WAIT);
1076 if (ret != 0) {
1077 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
1078
1079 /*
1080 * Reschedule query timeout handler with some delay, so that all
1081 * threads (including those with lower priorities) have a chance
1082 * to move forward and release DNS context lock.
1083 *
1084 * Timeout value was arbitrarily chosen and can be updated in
1085 * future if needed.
1086 */
1087 k_work_reschedule(dwork, K_MSEC(10));
1088 return;
1089 }
1090
1091 NET_DBG("Query timeout DNS req %u type %d hash %u", pending_query->id,
1092 pending_query->query_type, pending_query->query_hash);
1093
1094 /* The resolve cancel will invoke release_query(), but release will
1095 * not be completed because the work item is still pending. Instead
1096 * the release will be completed when check_query_active() confirms
1097 * the work item is no longer active.
1098 */
1099 (void)dns_resolve_cancel_with_hash(pending_query->ctx,
1100 pending_query->id,
1101 pending_query->query_hash,
1102 pending_query->query);
1103
1104 k_mutex_unlock(&pending_query->ctx->lock);
1105 }
1106
dns_resolve_name(struct dns_resolve_context * ctx,const char * query,enum dns_query_type type,uint16_t * dns_id,dns_resolve_cb_t cb,void * user_data,int32_t timeout)1107 int dns_resolve_name(struct dns_resolve_context *ctx,
1108 const char *query,
1109 enum dns_query_type type,
1110 uint16_t *dns_id,
1111 dns_resolve_cb_t cb,
1112 void *user_data,
1113 int32_t timeout)
1114 {
1115 k_timeout_t tout;
1116 struct net_buf *dns_data = NULL;
1117 struct net_buf *dns_qname = NULL;
1118 struct sockaddr addr;
1119 int ret, i = -1, j = 0;
1120 int failure = 0;
1121 bool mdns_query = false;
1122 uint8_t hop_limit;
1123
1124 if (!ctx || !query || !cb) {
1125 return -EINVAL;
1126 }
1127
1128 tout = SYS_TIMEOUT_MS(timeout);
1129
1130 /* Timeout cannot be 0 as we cannot resolve name that fast.
1131 */
1132 if (K_TIMEOUT_EQ(tout, K_NO_WAIT)) {
1133 return -EINVAL;
1134 }
1135
1136 ret = net_ipaddr_parse(query, strlen(query), &addr);
1137 if (ret) {
1138 /* The query name was already in numeric form, no
1139 * need to continue further.
1140 */
1141 struct dns_addrinfo info = { 0 };
1142
1143 if (type == DNS_QUERY_TYPE_A) {
1144 if (net_sin(&addr)->sin_family == AF_INET6) {
1145 return -EPFNOSUPPORT;
1146 }
1147
1148 memcpy(net_sin(&info.ai_addr), net_sin(&addr),
1149 sizeof(struct sockaddr_in));
1150 info.ai_family = AF_INET;
1151 info.ai_addr.sa_family = AF_INET;
1152 info.ai_addrlen = sizeof(struct sockaddr_in);
1153 } else if (type == DNS_QUERY_TYPE_AAAA) {
1154 /* We do not support AI_V4MAPPED atm, so if the user
1155 * asks an IPv6 address but it is an IPv4 one, then
1156 * return an error. Note that getaddrinfo() will swap
1157 * the error to EINVAL, the EPFNOSUPPORT is returned
1158 * here so that we can find it easily.
1159 */
1160 if (net_sin(&addr)->sin_family == AF_INET) {
1161 return -EPFNOSUPPORT;
1162 }
1163
1164 #if defined(CONFIG_NET_IPV6)
1165 memcpy(net_sin6(&info.ai_addr), net_sin6(&addr),
1166 sizeof(struct sockaddr_in6));
1167 info.ai_family = AF_INET6;
1168 info.ai_addr.sa_family = AF_INET6;
1169 info.ai_addrlen = sizeof(struct sockaddr_in6);
1170 #else
1171 return -EAFNOSUPPORT;
1172 #endif
1173 } else {
1174 goto try_resolve;
1175 }
1176
1177 cb(DNS_EAI_INPROGRESS, &info, user_data);
1178 cb(DNS_EAI_ALLDONE, NULL, user_data);
1179
1180 return 0;
1181 }
1182
1183 try_resolve:
1184 k_mutex_lock(&ctx->lock, K_FOREVER);
1185
1186 if (ctx->state != DNS_RESOLVE_CONTEXT_ACTIVE) {
1187 ret = -EINVAL;
1188 goto fail;
1189 }
1190
1191 i = get_cb_slot(ctx);
1192 if (i < 0) {
1193 ret = -EAGAIN;
1194 goto fail;
1195 }
1196
1197 ctx->queries[i].cb = cb;
1198 ctx->queries[i].timeout = tout;
1199 ctx->queries[i].query = query;
1200 ctx->queries[i].query_type = type;
1201 ctx->queries[i].user_data = user_data;
1202 ctx->queries[i].ctx = ctx;
1203 ctx->queries[i].query_hash = 0;
1204
1205 k_work_init_delayable(&ctx->queries[i].timer, query_timeout);
1206
1207 dns_data = net_buf_alloc(&dns_msg_pool, ctx->buf_timeout);
1208 if (!dns_data) {
1209 ret = -ENOMEM;
1210 goto quit;
1211 }
1212
1213 dns_qname = net_buf_alloc(&dns_qname_pool, ctx->buf_timeout);
1214 if (!dns_qname) {
1215 ret = -ENOMEM;
1216 goto quit;
1217 }
1218
1219 ret = dns_msg_pack_qname(&dns_qname->len, dns_qname->data,
1220 DNS_MAX_NAME_LEN, ctx->queries[i].query);
1221 if (ret < 0) {
1222 goto quit;
1223 }
1224
1225 ctx->queries[i].id = sys_rand32_get();
1226
1227 /* If mDNS is enabled, then send .local queries only to multicast
1228 * address. For mDNS the id should be set to 0, see RFC 6762 ch. 18.1
1229 * for details.
1230 */
1231 if (IS_ENABLED(CONFIG_MDNS_RESOLVER)) {
1232 const char *ptr = strrchr(query, '.');
1233
1234 /* Note that we memcmp() the \0 here too */
1235 if (ptr && !memcmp(ptr, (const void *){ ".local" }, 7)) {
1236 mdns_query = true;
1237
1238 ctx->queries[i].id = 0;
1239 }
1240 }
1241
1242 /* Do this immediately after calculating the Id so that the unit
1243 * test will work properly.
1244 */
1245 if (dns_id) {
1246 *dns_id = ctx->queries[i].id;
1247
1248 NET_DBG("DNS id will be %u", *dns_id);
1249 }
1250
1251 for (j = 0; j < SERVER_COUNT; j++) {
1252 hop_limit = 0U;
1253
1254 if (!ctx->servers[j].net_ctx) {
1255 continue;
1256 }
1257
1258 /* If mDNS is enabled, then send .local queries only to
1259 * a well known multicast mDNS server address.
1260 */
1261 if (IS_ENABLED(CONFIG_MDNS_RESOLVER) && mdns_query &&
1262 !ctx->servers[j].is_mdns) {
1263 continue;
1264 }
1265
1266 /* If llmnr is enabled, then all the queries are sent to
1267 * LLMNR multicast address unless it is a mDNS query.
1268 */
1269 if (!mdns_query && IS_ENABLED(CONFIG_LLMNR_RESOLVER)) {
1270 if (!ctx->servers[j].is_llmnr) {
1271 continue;
1272 }
1273
1274 hop_limit = 1U;
1275 }
1276
1277 ret = dns_write(ctx, j, i, dns_data, dns_qname, hop_limit);
1278 if (ret < 0) {
1279 failure++;
1280 continue;
1281 }
1282
1283 /* Do one concurrent query only for each name resolve.
1284 * TODO: Change the i (query index) to do multiple concurrent
1285 * to each server.
1286 */
1287 break;
1288 }
1289
1290 if (failure) {
1291 NET_DBG("DNS query failed %d times", failure);
1292
1293 if (failure == j) {
1294 ret = -ENOENT;
1295 goto quit;
1296 }
1297 }
1298
1299 ret = 0;
1300
1301 quit:
1302 if (ret < 0) {
1303 if (i >= 0) {
1304 release_query(&ctx->queries[i]);
1305 }
1306
1307 if (dns_id) {
1308 *dns_id = 0U;
1309 }
1310 }
1311
1312 if (dns_data) {
1313 net_buf_unref(dns_data);
1314 }
1315
1316 if (dns_qname) {
1317 net_buf_unref(dns_qname);
1318 }
1319
1320 fail:
1321 k_mutex_unlock(&ctx->lock);
1322
1323 return ret;
1324 }
1325
1326 /* Must be invoked with context lock held */
dns_resolve_close_locked(struct dns_resolve_context * ctx)1327 static int dns_resolve_close_locked(struct dns_resolve_context *ctx)
1328 {
1329 int i;
1330
1331 if (ctx->state != DNS_RESOLVE_CONTEXT_ACTIVE) {
1332 return -ENOENT;
1333 }
1334
1335 ctx->state = DNS_RESOLVE_CONTEXT_DEACTIVATING;
1336
1337 /* ctx->net_ctx is never used in "deactivating" state. Additionally
1338 * following code is guaranteed to be executed only by one thread at a
1339 * time, due to required "active" -> "deactivating" state change. This
1340 * means that it is safe to put net_ctx with mutex released.
1341 *
1342 * Released mutex will prevent lower networking layers from deadlock
1343 * when calling cb_recv() (which acquires ctx->lock) just before closing
1344 * network context.
1345 */
1346 k_mutex_unlock(&ctx->lock);
1347
1348 for (i = 0; i < SERVER_COUNT; i++) {
1349 if (ctx->servers[i].net_ctx) {
1350 struct net_if *iface;
1351
1352 iface = net_context_get_iface(ctx->servers[i].net_ctx);
1353
1354 if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) {
1355 net_mgmt_event_notify_with_info(
1356 NET_EVENT_DNS_SERVER_DEL,
1357 iface,
1358 (void *)&ctx->servers[i].dns_server,
1359 sizeof(struct sockaddr));
1360 } else {
1361 net_mgmt_event_notify(NET_EVENT_DNS_SERVER_DEL,
1362 iface);
1363 }
1364
1365 net_context_put(ctx->servers[i].net_ctx);
1366 ctx->servers[i].net_ctx = NULL;
1367 }
1368 }
1369
1370 k_mutex_lock(&ctx->lock, K_FOREVER);
1371
1372 ctx->state = DNS_RESOLVE_CONTEXT_INACTIVE;
1373
1374 return 0;
1375 }
1376
dns_resolve_close(struct dns_resolve_context * ctx)1377 int dns_resolve_close(struct dns_resolve_context *ctx)
1378 {
1379 int ret;
1380
1381 k_mutex_lock(&ctx->lock, K_FOREVER);
1382 ret = dns_resolve_close_locked(ctx);
1383 k_mutex_unlock(&ctx->lock);
1384
1385 return ret;
1386 }
1387
dns_resolve_reconfigure(struct dns_resolve_context * ctx,const char * servers[],const struct sockaddr * servers_sa[])1388 int dns_resolve_reconfigure(struct dns_resolve_context *ctx,
1389 const char *servers[],
1390 const struct sockaddr *servers_sa[])
1391 {
1392 int err;
1393
1394 if (!ctx) {
1395 return -ENOENT;
1396 }
1397
1398 k_mutex_lock(&ctx->lock, K_FOREVER);
1399
1400 if (ctx->state == DNS_RESOLVE_CONTEXT_DEACTIVATING) {
1401 err = -EBUSY;
1402 goto unlock;
1403 }
1404
1405 if (ctx->state == DNS_RESOLVE_CONTEXT_ACTIVE) {
1406 dns_resolve_cancel_all(ctx);
1407
1408 err = dns_resolve_close_locked(ctx);
1409 if (err) {
1410 goto unlock;
1411 }
1412 }
1413
1414 err = dns_resolve_init_locked(ctx, servers, servers_sa);
1415
1416 unlock:
1417 k_mutex_unlock(&ctx->lock);
1418
1419 return err;
1420 }
1421
dns_resolve_get_default(void)1422 struct dns_resolve_context *dns_resolve_get_default(void)
1423 {
1424 return &dns_default_ctx;
1425 }
1426
dns_init_resolver(void)1427 void dns_init_resolver(void)
1428 {
1429 #if defined(CONFIG_DNS_SERVER_IP_ADDRESSES)
1430 static const char *dns_servers[SERVER_COUNT + 1];
1431 int count = DNS_SERVER_COUNT;
1432 int ret;
1433
1434 if (count > 5) {
1435 count = 5;
1436 }
1437
1438 switch (count) {
1439 #if DNS_SERVER_COUNT > 4
1440 case 5:
1441 dns_servers[4] = CONFIG_DNS_SERVER5;
1442 __fallthrough;
1443 #endif
1444 #if DNS_SERVER_COUNT > 3
1445 case 4:
1446 dns_servers[3] = CONFIG_DNS_SERVER4;
1447 __fallthrough;
1448 #endif
1449 #if DNS_SERVER_COUNT > 2
1450 case 3:
1451 dns_servers[2] = CONFIG_DNS_SERVER3;
1452 __fallthrough;
1453 #endif
1454 #if DNS_SERVER_COUNT > 1
1455 case 2:
1456 dns_servers[1] = CONFIG_DNS_SERVER2;
1457 __fallthrough;
1458 #endif
1459 #if DNS_SERVER_COUNT > 0
1460 case 1:
1461 dns_servers[0] = CONFIG_DNS_SERVER1;
1462 __fallthrough;
1463 #endif
1464 case 0:
1465 break;
1466 }
1467
1468 #if defined(CONFIG_MDNS_RESOLVER) && (MDNS_SERVER_COUNT > 0)
1469 #if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
1470 dns_servers[DNS_SERVER_COUNT + 1] = MDNS_IPV6_ADDR;
1471 dns_servers[DNS_SERVER_COUNT] = MDNS_IPV4_ADDR;
1472 #else /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
1473 #if defined(CONFIG_NET_IPV6)
1474 dns_servers[DNS_SERVER_COUNT] = MDNS_IPV6_ADDR;
1475 #endif
1476 #if defined(CONFIG_NET_IPV4)
1477 dns_servers[DNS_SERVER_COUNT] = MDNS_IPV4_ADDR;
1478 #endif
1479 #endif /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
1480 #endif /* MDNS_RESOLVER && MDNS_SERVER_COUNT > 0 */
1481
1482 #if defined(CONFIG_LLMNR_RESOLVER) && (LLMNR_SERVER_COUNT > 0)
1483 #if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
1484 dns_servers[DNS_SERVER_COUNT + MDNS_SERVER_COUNT + 1] =
1485 LLMNR_IPV6_ADDR;
1486 dns_servers[DNS_SERVER_COUNT + MDNS_SERVER_COUNT] = LLMNR_IPV4_ADDR;
1487 #else /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
1488 #if defined(CONFIG_NET_IPV6)
1489 dns_servers[DNS_SERVER_COUNT + MDNS_SERVER_COUNT] = LLMNR_IPV6_ADDR;
1490 #endif
1491 #if defined(CONFIG_NET_IPV4)
1492 dns_servers[DNS_SERVER_COUNT + MDNS_SERVER_COUNT] = LLMNR_IPV4_ADDR;
1493 #endif
1494 #endif /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
1495 #endif /* LLMNR_RESOLVER && LLMNR_SERVER_COUNT > 0 */
1496
1497 dns_servers[SERVER_COUNT] = NULL;
1498
1499 ret = dns_resolve_init(dns_resolve_get_default(), dns_servers, NULL);
1500 if (ret < 0) {
1501 NET_WARN("Cannot initialize DNS resolver (%d)", ret);
1502 }
1503 #endif
1504 }
1505