1 /** @file
2 * @brief DNS resolving library
3 *
4 * An API for applications to resolve a DNS name.
5 */
6
7 /*
8 * Copyright (c) 2017 Intel Corporation
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #ifndef ZEPHYR_INCLUDE_NET_DNS_RESOLVE_H_
14 #define ZEPHYR_INCLUDE_NET_DNS_RESOLVE_H_
15
16 #include <zephyr/kernel.h>
17 #include <zephyr/net/net_ip.h>
18 #include <zephyr/net/net_if.h>
19 #include <zephyr/net/socket_poll.h>
20 #include <zephyr/net/net_core.h>
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 /**
27 * @brief DNS resolving library
28 * @defgroup dns_resolve DNS Resolve Library
29 * @since 1.8
30 * @version 0.8.0
31 * @ingroup networking
32 * @{
33 */
34
35 /**
36 * DNS query type enum
37 */
38 enum dns_query_type {
39 /** IPv4 query */
40 DNS_QUERY_TYPE_A = 1,
41 /** IPv6 query */
42 DNS_QUERY_TYPE_AAAA = 28
43 };
44
45 /** Max size of the resolved name. */
46 #ifndef DNS_MAX_NAME_SIZE
47 #define DNS_MAX_NAME_SIZE 20
48 #endif
49
50 /** @cond INTERNAL_HIDDEN */
51
52 #define DNS_BUF_TIMEOUT K_MSEC(500) /* ms */
53
54 /* This value is recommended by RFC 1035 */
55 #define DNS_RESOLVER_MAX_BUF_SIZE 512
56
57 /* Make sure that we can compile things even if CONFIG_DNS_RESOLVER
58 * is not enabled.
59 */
60 #if defined(CONFIG_DNS_RESOLVER_MAX_SERVERS)
61 #define DNS_RESOLVER_MAX_SERVERS CONFIG_DNS_RESOLVER_MAX_SERVERS
62 #else
63 #define DNS_RESOLVER_MAX_SERVERS 0
64 #endif
65
66 #if defined(CONFIG_DNS_NUM_CONCUR_QUERIES)
67 #define DNS_NUM_CONCUR_QUERIES CONFIG_DNS_NUM_CONCUR_QUERIES
68 #else
69 #define DNS_NUM_CONCUR_QUERIES 1
70 #endif
71
72 #if defined(CONFIG_NET_IF_MAX_IPV6_COUNT)
73 #define MAX_IPV6_IFACE_COUNT CONFIG_NET_IF_MAX_IPV6_COUNT
74 #else
75 #define MAX_IPV6_IFACE_COUNT 1
76 #endif
77
78 #if defined(CONFIG_NET_IF_MAX_IPV4_COUNT)
79 #define MAX_IPV4_IFACE_COUNT CONFIG_NET_IF_MAX_IPV4_COUNT
80 #else
81 #define MAX_IPV4_IFACE_COUNT 1
82 #endif
83
84 /* If mDNS is enabled, then add some extra well known multicast servers to the
85 * server list.
86 */
87 #if defined(CONFIG_MDNS_RESOLVER)
88 #if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
89 #define MDNS_SERVER_COUNT 2
90 #else
91 #define MDNS_SERVER_COUNT 1
92 #endif /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
93 #else
94 #define MDNS_SERVER_COUNT 0
95 #endif /* CONFIG_MDNS_RESOLVER */
96
97 /* If LLMNR is enabled, then add some extra well known multicast servers to the
98 * server list.
99 */
100 #if defined(CONFIG_LLMNR_RESOLVER)
101 #if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
102 #define LLMNR_SERVER_COUNT 2
103 #else
104 #define LLMNR_SERVER_COUNT 1
105 #endif /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
106 #else
107 #define LLMNR_SERVER_COUNT 0
108 #endif /* CONFIG_MDNS_RESOLVER */
109
110 #define DNS_MAX_MCAST_SERVERS (MDNS_SERVER_COUNT + LLMNR_SERVER_COUNT)
111
112 #if defined(CONFIG_MDNS_RESPONDER)
113 #if defined(CONFIG_NET_IPV6)
114 #define MDNS_MAX_IPV6_IFACE_COUNT CONFIG_NET_IF_MAX_IPV6_COUNT
115 #else
116 #define MDNS_MAX_IPV6_IFACE_COUNT 0
117 #endif /* CONFIG_NET_IPV6 */
118
119 #if defined(CONFIG_NET_IPV4)
120 #define MDNS_MAX_IPV4_IFACE_COUNT CONFIG_NET_IF_MAX_IPV4_COUNT
121 #else
122 #define MDNS_MAX_IPV4_IFACE_COUNT 0
123 #endif /* CONFIG_NET_IPV4 */
124
125 #define MDNS_MAX_POLL (MDNS_MAX_IPV4_IFACE_COUNT + MDNS_MAX_IPV6_IFACE_COUNT)
126 #else
127 #define MDNS_MAX_POLL 0
128 #endif /* CONFIG_MDNS_RESPONDER */
129
130 #if defined(CONFIG_LLMNR_RESPONDER)
131 #if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
132 #define LLMNR_MAX_POLL 2
133 #else
134 #define LLMNR_MAX_POLL 1
135 #endif
136 #else
137 #define LLMNR_MAX_POLL 0
138 #endif /* CONFIG_LLMNR_RESPONDER */
139
140 #define DNS_RESOLVER_MAX_POLL (DNS_RESOLVER_MAX_SERVERS + DNS_MAX_MCAST_SERVERS)
141
142 /** How many sockets the dispatcher is able to poll. */
143 #define DNS_DISPATCHER_MAX_POLL (DNS_RESOLVER_MAX_POLL + MDNS_MAX_POLL + LLMNR_MAX_POLL)
144
145 #if defined(CONFIG_ZVFS_POLL_MAX)
146 BUILD_ASSERT(CONFIG_ZVFS_POLL_MAX >= DNS_DISPATCHER_MAX_POLL,
147 "CONFIG_ZVFS_POLL_MAX must be larger than " STRINGIFY(DNS_DISPATCHER_MAX_POLL));
148 #endif
149
150 /** @brief What is the type of the socket given to DNS socket dispatcher,
151 * resolver or responder.
152 */
153 enum dns_socket_type {
154 DNS_SOCKET_RESOLVER = 1, /**< Socket is used for resolving (client type) */
155 DNS_SOCKET_RESPONDER = 2 /**< Socket is used for responding (server type) */
156 };
157
158 struct dns_resolve_context;
159 struct mdns_responder_context;
160 struct dns_socket_dispatcher;
161
162 /**
163 * @typedef dns_socket_dispatcher_cb
164 * @brief Callback used when the DNS socket dispatcher has found a handler for
165 * this type of socket.
166 *
167 * @param ctx struct dns_socket_dispatcher context.
168 * @param sock Socket which is seeing traffic.
169 * @param addr Socket address of the peer that sent the DNS packet.
170 * @param addrlen Length of the socket address.
171 * @param buf Pointer to data buffer containing the DNS message.
172 * @param data_len Length of the data in buffer chain.
173 *
174 * @return 0 if ok, <0 if error
175 */
176 typedef int (*dns_socket_dispatcher_cb)(struct dns_socket_dispatcher *ctx, int sock,
177 struct sockaddr *addr, size_t addrlen,
178 struct net_buf *buf, size_t data_len);
179
180 /** @brief DNS socket dispatcher context. */
181 struct dns_socket_dispatcher {
182 /** slist node for the different dispatcher contexts */
183 sys_snode_t node;
184 /** Socket service for this dispatcher instance */
185 const struct net_socket_service_desc *svc;
186 /** DNS resolver context that contains information needed by the
187 * resolver/responder handler, or mDNS responder context.
188 */
189 union {
190 void *ctx;
191 struct dns_resolve_context *resolve_ctx;
192 struct mdns_responder_context *mdns_ctx;
193 };
194
195 /** Type of the socket (resolver / responder) */
196 enum dns_socket_type type;
197 /** Local endpoint address (used when binding the socket) */
198 struct sockaddr local_addr;
199 /** DNS socket dispatcher callback is called for incoming traffic */
200 dns_socket_dispatcher_cb cb;
201 /** Socket descriptors to poll */
202 struct zsock_pollfd *fds;
203 /** Length of the poll array */
204 int fds_len;
205 /** Local socket to dispatch */
206 int sock;
207 /** Interface we are bound to */
208 int ifindex;
209 /** There can be two contexts to dispatch. This points to the other
210 * context if sharing the socket between resolver / responder.
211 */
212 struct dns_socket_dispatcher *pair;
213 /** Mutex lock protecting access to this dispatcher context */
214 struct k_mutex lock;
215 /** Buffer allocation timeout */
216 k_timeout_t buf_timeout;
217 };
218
219 /**
220 * @brief Register a DNS dispatcher socket. Each code wanting to use
221 * the dispatcher needs to create the dispatcher context and call
222 * this function.
223 *
224 * @param ctx DNS socket dispatcher context.
225 *
226 * @return 0 if ok, <1 if error
227 */
228 int dns_dispatcher_register(struct dns_socket_dispatcher *ctx);
229
230 /**
231 * @brief Unregister a DNS dispatcher socket. Called when the
232 * resolver/responder no longer needs to receive traffic for the
233 * socket.
234 *
235 * @param ctx DNS socket dispatcher context.
236 *
237 * @return 0 if ok, <1 if error
238 */
239 int dns_dispatcher_unregister(struct dns_socket_dispatcher *ctx);
240
241 /** @endcond */
242
243 /**
244 * Address info struct is passed to callback that gets all the results.
245 */
246 struct dns_addrinfo {
247 /** IP address information */
248 struct sockaddr ai_addr;
249 /** Length of the ai_addr field */
250 socklen_t ai_addrlen;
251 /** Address family of the address information */
252 uint8_t ai_family;
253 /** Canonical name of the address */
254 char ai_canonname[DNS_MAX_NAME_SIZE + 1];
255 };
256
257 /**
258 * Status values for the callback.
259 */
260 enum dns_resolve_status {
261 /** Invalid value for `ai_flags' field */
262 DNS_EAI_BADFLAGS = -1,
263 /** NAME or SERVICE is unknown */
264 DNS_EAI_NONAME = -2,
265 /** Temporary failure in name resolution */
266 DNS_EAI_AGAIN = -3,
267 /** Non-recoverable failure in name res */
268 DNS_EAI_FAIL = -4,
269 /** No address associated with NAME */
270 DNS_EAI_NODATA = -5,
271 /** `ai_family' not supported */
272 DNS_EAI_FAMILY = -6,
273 /** `ai_socktype' not supported */
274 DNS_EAI_SOCKTYPE = -7,
275 /** SRV not supported for `ai_socktype' */
276 DNS_EAI_SERVICE = -8,
277 /** Address family for NAME not supported */
278 DNS_EAI_ADDRFAMILY = -9,
279 /** Memory allocation failure */
280 DNS_EAI_MEMORY = -10,
281 /** System error returned in `errno' */
282 DNS_EAI_SYSTEM = -11,
283 /** Argument buffer overflow */
284 DNS_EAI_OVERFLOW = -12,
285 /** Processing request in progress */
286 DNS_EAI_INPROGRESS = -100,
287 /** Request canceled */
288 DNS_EAI_CANCELED = -101,
289 /** Request not canceled */
290 DNS_EAI_NOTCANCELED = -102,
291 /** All requests done */
292 DNS_EAI_ALLDONE = -103,
293 /** IDN encoding failed */
294 DNS_EAI_IDN_ENCODE = -105,
295 };
296
297 /**
298 * @typedef dns_resolve_cb_t
299 * @brief DNS resolve callback
300 *
301 * @details The DNS resolve callback is called after a successful
302 * DNS resolving. The resolver can call this callback multiple times, one
303 * for each resolved address.
304 *
305 * @param status The status of the query:
306 * DNS_EAI_INPROGRESS returned for each resolved address
307 * DNS_EAI_ALLDONE mark end of the resolving, info is set to NULL in
308 * this case
309 * DNS_EAI_CANCELED if the query was canceled manually or timeout happened
310 * DNS_EAI_FAIL if the name cannot be resolved by the server
311 * DNS_EAI_NODATA if there is no such name
312 * other values means that an error happened.
313 * @param info Query results are stored here.
314 * @param user_data The user data given in dns_resolve_name() call.
315 */
316 typedef void (*dns_resolve_cb_t)(enum dns_resolve_status status,
317 struct dns_addrinfo *info,
318 void *user_data);
319
320 /** @cond INTERNAL_HIDDEN */
321
322 enum dns_resolve_context_state {
323 DNS_RESOLVE_CONTEXT_ACTIVE,
324 DNS_RESOLVE_CONTEXT_DEACTIVATING,
325 DNS_RESOLVE_CONTEXT_INACTIVE,
326 };
327
328 /** @endcond */
329
330 /**
331 * DNS resolve context structure.
332 */
333 struct dns_resolve_context {
334 /** List of configured DNS servers */
335 struct dns_server {
336 /** DNS server information */
337 struct sockaddr dns_server;
338
339 /** Connection to the DNS server */
340 int sock;
341
342 /** Network interface index if the DNS resolving should be done
343 * via this interface. Value 0 indicates any interface can be used.
344 */
345 int if_index;
346
347 /** Is this server mDNS one */
348 uint8_t is_mdns : 1;
349
350 /** Is this server LLMNR one */
351 uint8_t is_llmnr : 1;
352
353 /** @cond INTERNAL_HIDDEN */
354 /** Dispatch DNS data between resolver and responder */
355 struct dns_socket_dispatcher dispatcher;
356 /** @endcond */
357 } servers[DNS_RESOLVER_MAX_POLL];
358
359 /** @cond INTERNAL_HIDDEN */
360 /** Socket polling for each server connection */
361 struct zsock_pollfd fds[DNS_RESOLVER_MAX_POLL];
362 /** @endcond */
363
364 /** Prevent concurrent access */
365 struct k_mutex lock;
366
367 /** This timeout is also used when a buffer is required from the
368 * buffer pools.
369 */
370 k_timeout_t buf_timeout;
371
372 /** Result callbacks. We have multiple callbacks here so that it is
373 * possible to do multiple queries at the same time.
374 *
375 * Contents of this structure can be inspected and changed only when
376 * the lock is held.
377 */
378 struct dns_pending_query {
379 /** Timeout timer */
380 struct k_work_delayable timer;
381
382 /** Back pointer to ctx, needed in timeout handler */
383 struct dns_resolve_context *ctx;
384
385 /** Result callback.
386 *
387 * A null value indicates the slot is not in use.
388 */
389 dns_resolve_cb_t cb;
390
391 /** User data */
392 void *user_data;
393
394 /** TX timeout */
395 k_timeout_t timeout;
396
397 /** String containing the thing to resolve like www.example.com
398 *
399 * This is set to a non-null value when the query is started,
400 * and is not used thereafter.
401 *
402 * If the query completed at a point where the work item was
403 * still pending the pointer is cleared to indicate that the
404 * query is complete, but release of the query slot will be
405 * deferred until a request for a slot determines that the
406 * work item has been released.
407 */
408 const char *query;
409
410 /** Query type */
411 enum dns_query_type query_type;
412
413 /** DNS id of this query */
414 uint16_t id;
415
416 /** Hash of the DNS name + query type we are querying.
417 * This hash is calculated so we can match the response that
418 * we are receiving. This is needed mainly for mDNS which is
419 * setting the DNS id to 0, which means that the id alone
420 * cannot be used to find correct pending query.
421 */
422 uint16_t query_hash;
423 } queries[DNS_NUM_CONCUR_QUERIES];
424
425 /** Is this context in use */
426 enum dns_resolve_context_state state;
427 };
428
429 /** @cond INTERNAL_HIDDEN */
430
431 struct mdns_probe_user_data {
432 struct mdns_responder_context *ctx;
433 char query[DNS_MAX_NAME_SIZE + 1];
434 uint16_t dns_id;
435 };
436
437 struct mdns_responder_context {
438 struct sockaddr server_addr;
439 struct dns_socket_dispatcher dispatcher;
440 struct zsock_pollfd fds[1];
441 int sock;
442 struct net_if *iface;
443 #if defined(CONFIG_MDNS_RESPONDER_PROBE)
444 struct k_work_delayable probe_timer;
445 struct dns_resolve_context probe_ctx;
446 struct mdns_probe_user_data probe_data;
447 #endif
448 };
449
450 /** @endcond */
451
452 /**
453 * @brief Init DNS resolving context.
454 *
455 * @details This function sets the DNS server address and initializes the
456 * DNS context that is used by the actual resolver. DNS server addresses
457 * can be specified either in textual form, or as struct sockaddr (or both).
458 * Note that the recommended way to resolve DNS names is to use
459 * the dns_get_addr_info() API. In that case user does not need to
460 * call dns_resolve_init() as the DNS servers are already setup by the system.
461 *
462 * @param ctx DNS context. If the context variable is allocated from
463 * the stack, then the variable needs to be valid for the whole duration of
464 * the resolving. Caller does not need to fill the variable beforehand or
465 * edit the context afterwards.
466 * @param dns_servers_str DNS server addresses using textual strings. The
467 * array is NULL terminated. The port number can be given in the string.
468 * Syntax for the server addresses with or without port numbers:
469 * IPv4 : 10.0.9.1
470 * IPv4 + port : 10.0.9.1:5353
471 * IPv6 : 2001:db8::22:42
472 * IPv6 + port : [2001:db8::22:42]:5353
473 * @param dns_servers_sa DNS server addresses as struct sockaddr. The array
474 * is NULL terminated. Port numbers are optional in struct sockaddr, the
475 * default will be used if set to 0.
476 *
477 * @return 0 if ok, <0 if error.
478 */
479 int dns_resolve_init(struct dns_resolve_context *ctx,
480 const char *dns_servers_str[],
481 const struct sockaddr *dns_servers_sa[]);
482
483 /**
484 * @brief Init DNS resolving context with default Kconfig options.
485 *
486 * @param ctx DNS context.
487 *
488 * @return 0 if ok, <0 if error.
489 */
490 int dns_resolve_init_default(struct dns_resolve_context *ctx);
491
492 /**
493 * @brief Close DNS resolving context.
494 *
495 * @details This releases DNS resolving context and marks the context unusable.
496 * Caller must call the dns_resolve_init() again to make context usable.
497 *
498 * @param ctx DNS context
499 *
500 * @return 0 if ok, <0 if error.
501 */
502 int dns_resolve_close(struct dns_resolve_context *ctx);
503
504 /**
505 * @brief Reconfigure DNS resolving context.
506 *
507 * @details Reconfigures DNS context with new server list.
508 *
509 * @param ctx DNS context
510 * @param servers_str DNS server addresses using textual strings. The
511 * array is NULL terminated. The port number can be given in the string.
512 * Syntax for the server addresses with or without port numbers:
513 * IPv4 : 10.0.9.1
514 * IPv4 + port : 10.0.9.1:5353
515 * IPv6 : 2001:db8::22:42
516 * IPv6 + port : [2001:db8::22:42]:5353
517 * @param servers_sa DNS server addresses as struct sockaddr. The array
518 * is NULL terminated. Port numbers are optional in struct sockaddr, the
519 * default will be used if set to 0.
520 *
521 * @return 0 if ok, <0 if error.
522 */
523 int dns_resolve_reconfigure(struct dns_resolve_context *ctx,
524 const char *servers_str[],
525 const struct sockaddr *servers_sa[]);
526
527 /**
528 * @brief Cancel a pending DNS query.
529 *
530 * @details This releases DNS resources used by a pending query.
531 *
532 * @param ctx DNS context
533 * @param dns_id DNS id of the pending query
534 *
535 * @return 0 if ok, <0 if error.
536 */
537 int dns_resolve_cancel(struct dns_resolve_context *ctx,
538 uint16_t dns_id);
539
540 /**
541 * @brief Cancel a pending DNS query using id, name and type.
542 *
543 * @details This releases DNS resources used by a pending query.
544 *
545 * @param ctx DNS context
546 * @param dns_id DNS id of the pending query
547 * @param query_name Name of the resource we are trying to query (hostname)
548 * @param query_type Type of the query (A or AAAA)
549 *
550 * @return 0 if ok, <0 if error.
551 */
552 int dns_resolve_cancel_with_name(struct dns_resolve_context *ctx,
553 uint16_t dns_id,
554 const char *query_name,
555 enum dns_query_type query_type);
556
557 /**
558 * @brief Resolve DNS name.
559 *
560 * @details This function can be used to resolve e.g., IPv4 or IPv6 address.
561 * Note that this is asynchronous call, the function will return immediately
562 * and system will call the callback after resolving has finished or timeout
563 * has occurred.
564 * We might send the query to multiple servers (if there are more than one
565 * server configured), but we only use the result of the first received
566 * response.
567 *
568 * @param ctx DNS context
569 * @param query What the caller wants to resolve.
570 * @param type What kind of data the caller wants to get.
571 * @param dns_id DNS id is returned to the caller. This is needed if one
572 * wishes to cancel the query. This can be set to NULL if there is no need
573 * to cancel the query.
574 * @param cb Callback to call after the resolving has finished or timeout
575 * has happened.
576 * @param user_data The user data.
577 * @param timeout The timeout value for the query. Possible values:
578 * SYS_FOREVER_MS: the query is tried forever, user needs to cancel it
579 * manually if it takes too long time to finish
580 * >0: start the query and let the system timeout it after specified ms
581 *
582 * @return 0 if resolving was started ok, < 0 otherwise
583 */
584 int dns_resolve_name(struct dns_resolve_context *ctx,
585 const char *query,
586 enum dns_query_type type,
587 uint16_t *dns_id,
588 dns_resolve_cb_t cb,
589 void *user_data,
590 int32_t timeout);
591
592 /**
593 * @brief Get default DNS context.
594 *
595 * @details The system level DNS context uses DNS servers that are
596 * defined in project config file. If no DNS servers are defined by the
597 * user, then resolving DNS names using default DNS context will do nothing.
598 * The configuration options are described in subsys/net/lib/dns/Kconfig file.
599 *
600 * @return Default DNS context.
601 */
602 struct dns_resolve_context *dns_resolve_get_default(void);
603
604 /**
605 * @brief Get IP address info from DNS.
606 *
607 * @details This function can be used to resolve e.g., IPv4 or IPv6 address.
608 * Note that this is asynchronous call, the function will return immediately
609 * and system will call the callback after resolving has finished or timeout
610 * has occurred.
611 * We might send the query to multiple servers (if there are more than one
612 * server configured), but we only use the result of the first received
613 * response.
614 * This variant uses system wide DNS servers.
615 *
616 * @param query What the caller wants to resolve.
617 * @param type What kind of data the caller wants to get.
618 * @param dns_id DNS id is returned to the caller. This is needed if one
619 * wishes to cancel the query. This can be set to NULL if there is no need
620 * to cancel the query.
621 * @param cb Callback to call after the resolving has finished or timeout
622 * has happened.
623 * @param user_data The user data.
624 * @param timeout The timeout value for the connection. Possible values:
625 * SYS_FOREVER_MS: the query is tried forever, user needs to cancel it
626 * manually if it takes too long time to finish
627 * >0: start the query and let the system timeout it after specified ms
628 *
629 * @return 0 if resolving was started ok, < 0 otherwise
630 */
dns_get_addr_info(const char * query,enum dns_query_type type,uint16_t * dns_id,dns_resolve_cb_t cb,void * user_data,int32_t timeout)631 static inline int dns_get_addr_info(const char *query,
632 enum dns_query_type type,
633 uint16_t *dns_id,
634 dns_resolve_cb_t cb,
635 void *user_data,
636 int32_t timeout)
637 {
638 return dns_resolve_name(dns_resolve_get_default(),
639 query,
640 type,
641 dns_id,
642 cb,
643 user_data,
644 timeout);
645 }
646
647 /**
648 * @brief Cancel a pending DNS query.
649 *
650 * @details This releases DNS resources used by a pending query.
651 *
652 * @param dns_id DNS id of the pending query
653 *
654 * @return 0 if ok, <0 if error.
655 */
dns_cancel_addr_info(uint16_t dns_id)656 static inline int dns_cancel_addr_info(uint16_t dns_id)
657 {
658 return dns_resolve_cancel(dns_resolve_get_default(), dns_id);
659 }
660
661 /**
662 * @}
663 */
664
665 /** @cond INTERNAL_HIDDEN */
666
667 /**
668 * @brief Initialize DNS subsystem.
669 */
670 #if defined(CONFIG_DNS_RESOLVER_AUTO_INIT)
671 void dns_init_resolver(void);
672
673 #else
674 #define dns_init_resolver(...)
675 #endif /* CONFIG_DNS_RESOLVER_AUTO_INIT */
676
677 /** @endcond */
678
679 #ifdef __cplusplus
680 }
681 #endif
682
683 #endif /* ZEPHYR_INCLUDE_NET_DNS_RESOLVE_H_ */
684