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/net/net_ip.h>
17 #include <zephyr/net/net_context.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 /**
24  * @brief DNS resolving library
25  * @defgroup dns_resolve DNS Resolve Library
26  * @ingroup networking
27  * @{
28  */
29 
30 /**
31  * DNS query type enum
32  */
33 enum dns_query_type {
34 	/** IPv4 query */
35 	DNS_QUERY_TYPE_A = 1,
36 	/** IPv6 query */
37 	DNS_QUERY_TYPE_AAAA = 28
38 };
39 
40 /** Max size of the resolved name. */
41 #ifndef DNS_MAX_NAME_SIZE
42 #define DNS_MAX_NAME_SIZE 20
43 #endif
44 
45 /** @cond INTERNAL_HIDDEN */
46 
47 /* Make sure that we can compile things even if CONFIG_DNS_RESOLVER
48  * is not enabled.
49  */
50 #if !defined(CONFIG_DNS_RESOLVER_MAX_SERVERS)
51 #define CONFIG_DNS_RESOLVER_MAX_SERVERS 1
52 #endif
53 #if !defined(CONFIG_DNS_NUM_CONCUR_QUERIES)
54 #define CONFIG_DNS_NUM_CONCUR_QUERIES 1
55 #endif
56 
57 /* If mDNS is enabled, then add some extra well known multicast servers to the
58  * server list.
59  */
60 #if defined(CONFIG_MDNS_RESOLVER)
61 #if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
62 #define MDNS_SERVER_COUNT 2
63 #else
64 #define MDNS_SERVER_COUNT 1
65 #endif /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
66 #else
67 #define MDNS_SERVER_COUNT 0
68 #endif /* CONFIG_MDNS_RESOLVER */
69 
70 /* If LLMNR is enabled, then add some extra well known multicast servers to the
71  * server list.
72  */
73 #if defined(CONFIG_LLMNR_RESOLVER)
74 #if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4)
75 #define LLMNR_SERVER_COUNT 2
76 #else
77 #define LLMNR_SERVER_COUNT 1
78 #endif /* CONFIG_NET_IPV6 && CONFIG_NET_IPV4 */
79 #else
80 #define LLMNR_SERVER_COUNT 0
81 #endif /* CONFIG_MDNS_RESOLVER */
82 
83 #define DNS_MAX_MCAST_SERVERS (MDNS_SERVER_COUNT + LLMNR_SERVER_COUNT)
84 
85 /** @endcond */
86 
87 /**
88  * Address info struct is passed to callback that gets all the results.
89  */
90 struct dns_addrinfo {
91 	struct sockaddr ai_addr;
92 	socklen_t       ai_addrlen;
93 	uint8_t            ai_family;
94 	char            ai_canonname[DNS_MAX_NAME_SIZE + 1];
95 };
96 
97 /**
98  * Status values for the callback.
99  */
100 enum dns_resolve_status {
101 	/** Invalid value for `ai_flags' field */
102 	DNS_EAI_BADFLAGS    = -1,
103 	/** NAME or SERVICE is unknown */
104 	DNS_EAI_NONAME      = -2,
105 	/** Temporary failure in name resolution */
106 	DNS_EAI_AGAIN       = -3,
107 	/** Non-recoverable failure in name res */
108 	DNS_EAI_FAIL        = -4,
109 	/** No address associated with NAME */
110 	DNS_EAI_NODATA      = -5,
111 	/** `ai_family' not supported */
112 	DNS_EAI_FAMILY      = -6,
113 	/** `ai_socktype' not supported */
114 	DNS_EAI_SOCKTYPE    = -7,
115 	/** SRV not supported for `ai_socktype' */
116 	DNS_EAI_SERVICE     = -8,
117 	/** Address family for NAME not supported */
118 	DNS_EAI_ADDRFAMILY  = -9,
119 	/** Memory allocation failure */
120 	DNS_EAI_MEMORY      = -10,
121 	/** System error returned in `errno' */
122 	DNS_EAI_SYSTEM      = -11,
123 	/** Argument buffer overflow */
124 	DNS_EAI_OVERFLOW    = -12,
125 	/** Processing request in progress */
126 	DNS_EAI_INPROGRESS  = -100,
127 	/** Request canceled */
128 	DNS_EAI_CANCELED    = -101,
129 	/** Request not canceled */
130 	DNS_EAI_NOTCANCELED = -102,
131 	/** All requests done */
132 	DNS_EAI_ALLDONE     = -103,
133 	/** IDN encoding failed */
134 	DNS_EAI_IDN_ENCODE  = -105,
135 };
136 
137 /**
138  * @typedef dns_resolve_cb_t
139  * @brief DNS resolve callback
140  *
141  * @details The DNS resolve callback is called after a successful
142  * DNS resolving. The resolver can call this callback multiple times, one
143  * for each resolved address.
144  *
145  * @param status The status of the query:
146  *  DNS_EAI_INPROGRESS returned for each resolved address
147  *  DNS_EAI_ALLDONE    mark end of the resolving, info is set to NULL in
148  *                     this case
149  *  DNS_EAI_CANCELED   if the query was canceled manually or timeout happened
150  *  DNS_EAI_FAIL       if the name cannot be resolved by the server
151  *  DNS_EAI_NODATA     if there is no such name
152  *  other values means that an error happened.
153  * @param info Query results are stored here.
154  * @param user_data The user data given in dns_resolve_name() call.
155  */
156 typedef void (*dns_resolve_cb_t)(enum dns_resolve_status status,
157 				 struct dns_addrinfo *info,
158 				 void *user_data);
159 
160 enum dns_resolve_context_state {
161 	DNS_RESOLVE_CONTEXT_ACTIVE,
162 	DNS_RESOLVE_CONTEXT_DEACTIVATING,
163 	DNS_RESOLVE_CONTEXT_INACTIVE,
164 };
165 
166 /**
167  * DNS resolve context structure.
168  */
169 struct dns_resolve_context {
170 	struct {
171 		/** DNS server information */
172 		struct sockaddr dns_server;
173 
174 		/** Connection to the DNS server */
175 		struct net_context *net_ctx;
176 
177 		/** Is this server mDNS one */
178 		uint8_t is_mdns : 1;
179 
180 		/** Is this server LLMNR one */
181 		uint8_t is_llmnr : 1;
182 	} servers[CONFIG_DNS_RESOLVER_MAX_SERVERS + DNS_MAX_MCAST_SERVERS];
183 
184 	/** Prevent concurrent access */
185 	struct k_mutex lock;
186 
187 	/** This timeout is also used when a buffer is required from the
188 	 * buffer pools.
189 	 */
190 	k_timeout_t buf_timeout;
191 
192 	/** Result callbacks. We have multiple callbacks here so that it is
193 	 * possible to do multiple queries at the same time.
194 	 *
195 	 * Contents of this structure can be inspected and changed only when
196 	 * the lock is held.
197 	 */
198 	struct dns_pending_query {
199 		/** Timeout timer */
200 		struct k_work_delayable timer;
201 
202 		/** Back pointer to ctx, needed in timeout handler */
203 		struct dns_resolve_context *ctx;
204 
205 		/** Result callback.
206 		 *
207 		 * A null value indicates the slot is not in use.
208 		 */
209 		dns_resolve_cb_t cb;
210 
211 		/** User data */
212 		void *user_data;
213 
214 		/** TX timeout */
215 		k_timeout_t timeout;
216 
217 		/** String containing the thing to resolve like www.example.com
218 		 *
219 		 * This is set to a non-null value when the query is started,
220 		 * and is not used thereafter.
221 		 *
222 		 * If the query completed at a point where the work item was
223 		 * still pending the pointer is cleared to indicate that the
224 		 * query is complete, but release of the query slot will be
225 		 * deferred until a request for a slot determines that the
226 		 * work item has been released.
227 		 */
228 		const char *query;
229 
230 		/** Query type */
231 		enum dns_query_type query_type;
232 
233 		/** DNS id of this query */
234 		uint16_t id;
235 
236 		/** Hash of the DNS name + query type we are querying.
237 		 * This hash is calculated so we can match the response that
238 		 * we are receiving. This is needed mainly for mDNS which is
239 		 * setting the DNS id to 0, which means that the id alone
240 		 * cannot be used to find correct pending query.
241 		 */
242 		uint16_t query_hash;
243 	} queries[CONFIG_DNS_NUM_CONCUR_QUERIES];
244 
245 	/** Is this context in use */
246 	enum dns_resolve_context_state state;
247 };
248 
249 /**
250  * @brief Init DNS resolving context.
251  *
252  * @details This function sets the DNS server address and initializes the
253  * DNS context that is used by the actual resolver. DNS server addresses
254  * can be specified either in textual form, or as struct sockaddr (or both).
255  * Note that the recommended way to resolve DNS names is to use
256  * the dns_get_addr_info() API. In that case user does not need to
257  * call dns_resolve_init() as the DNS servers are already setup by the system.
258  *
259  * @param ctx DNS context. If the context variable is allocated from
260  * the stack, then the variable needs to be valid for the whole duration of
261  * the resolving. Caller does not need to fill the variable beforehand or
262  * edit the context afterwards.
263  * @param dns_servers_str DNS server addresses using textual strings. The
264  * array is NULL terminated. The port number can be given in the string.
265  * Syntax for the server addresses with or without port numbers:
266  *    IPv4        : 10.0.9.1
267  *    IPv4 + port : 10.0.9.1:5353
268  *    IPv6        : 2001:db8::22:42
269  *    IPv6 + port : [2001:db8::22:42]:5353
270  * @param dns_servers_sa DNS server addresses as struct sockaddr. The array
271  * is NULL terminated. Port numbers are optional in struct sockaddr, the
272  * default will be used if set to 0.
273  *
274  * @return 0 if ok, <0 if error.
275  */
276 int dns_resolve_init(struct dns_resolve_context *ctx,
277 		     const char *dns_servers_str[],
278 		     const struct sockaddr *dns_servers_sa[]);
279 
280 /**
281  * @brief Close DNS resolving context.
282  *
283  * @details This releases DNS resolving context and marks the context unusable.
284  * Caller must call the dns_resolve_init() again to make context usable.
285  *
286  * @param ctx DNS context
287  *
288  * @return 0 if ok, <0 if error.
289  */
290 int dns_resolve_close(struct dns_resolve_context *ctx);
291 
292 /**
293  * @brief Reconfigure DNS resolving context.
294  *
295  * @details Reconfigures DNS context with new server list.
296  *
297  * @param ctx DNS context
298  * @param servers_str DNS server addresses using textual strings. The
299  * array is NULL terminated. The port number can be given in the string.
300  * Syntax for the server addresses with or without port numbers:
301  *    IPv4        : 10.0.9.1
302  *    IPv4 + port : 10.0.9.1:5353
303  *    IPv6        : 2001:db8::22:42
304  *    IPv6 + port : [2001:db8::22:42]:5353
305  * @param servers_sa DNS server addresses as struct sockaddr. The array
306  * is NULL terminated. Port numbers are optional in struct sockaddr, the
307  * default will be used if set to 0.
308  *
309  * @return 0 if ok, <0 if error.
310  */
311 int dns_resolve_reconfigure(struct dns_resolve_context *ctx,
312 			    const char *servers_str[],
313 			    const struct sockaddr *servers_sa[]);
314 
315 /**
316  * @brief Cancel a pending DNS query.
317  *
318  * @details This releases DNS resources used by a pending query.
319  *
320  * @param ctx DNS context
321  * @param dns_id DNS id of the pending query
322  *
323  * @return 0 if ok, <0 if error.
324  */
325 int dns_resolve_cancel(struct dns_resolve_context *ctx,
326 		       uint16_t dns_id);
327 
328 /**
329  * @brief Cancel a pending DNS query using id, name and type.
330  *
331  * @details This releases DNS resources used by a pending query.
332  *
333  * @param ctx DNS context
334  * @param dns_id DNS id of the pending query
335  * @param query_name Name of the resource we are trying to query (hostname)
336  * @param query_type Type of the query (A or AAAA)
337  *
338  * @return 0 if ok, <0 if error.
339  */
340 int dns_resolve_cancel_with_name(struct dns_resolve_context *ctx,
341 				 uint16_t dns_id,
342 				 const char *query_name,
343 				 enum dns_query_type query_type);
344 
345 /**
346  * @brief Resolve DNS name.
347  *
348  * @details This function can be used to resolve e.g., IPv4 or IPv6 address.
349  * Note that this is asynchronous call, the function will return immediately
350  * and system will call the callback after resolving has finished or timeout
351  * has occurred.
352  * We might send the query to multiple servers (if there are more than one
353  * server configured), but we only use the result of the first received
354  * response.
355  *
356  * @param ctx DNS context
357  * @param query What the caller wants to resolve.
358  * @param type What kind of data the caller wants to get.
359  * @param dns_id DNS id is returned to the caller. This is needed if one
360  * wishes to cancel the query. This can be set to NULL if there is no need
361  * to cancel the query.
362  * @param cb Callback to call after the resolving has finished or timeout
363  * has happened.
364  * @param user_data The user data.
365  * @param timeout The timeout value for the query. Possible values:
366  * SYS_FOREVER_MS: the query is tried forever, user needs to cancel it
367  *            manually if it takes too long time to finish
368  * >0: start the query and let the system timeout it after specified ms
369  *
370  * @return 0 if resolving was started ok, < 0 otherwise
371  */
372 int dns_resolve_name(struct dns_resolve_context *ctx,
373 		     const char *query,
374 		     enum dns_query_type type,
375 		     uint16_t *dns_id,
376 		     dns_resolve_cb_t cb,
377 		     void *user_data,
378 		     int32_t timeout);
379 
380 /**
381  * @brief Get default DNS context.
382  *
383  * @details The system level DNS context uses DNS servers that are
384  * defined in project config file. If no DNS servers are defined by the
385  * user, then resolving DNS names using default DNS context will do nothing.
386  * The configuration options are described in subsys/net/lib/dns/Kconfig file.
387  *
388  * @return Default DNS context.
389  */
390 struct dns_resolve_context *dns_resolve_get_default(void);
391 
392 /**
393  * @brief Get IP address info from DNS.
394  *
395  * @details This function can be used to resolve e.g., IPv4 or IPv6 address.
396  * Note that this is asynchronous call, the function will return immediately
397  * and system will call the callback after resolving has finished or timeout
398  * has occurred.
399  * We might send the query to multiple servers (if there are more than one
400  * server configured), but we only use the result of the first received
401  * response.
402  * This variant uses system wide DNS servers.
403  *
404  * @param query What the caller wants to resolve.
405  * @param type What kind of data the caller wants to get.
406  * @param dns_id DNS id is returned to the caller. This is needed if one
407  * wishes to cancel the query. This can be set to NULL if there is no need
408  * to cancel the query.
409  * @param cb Callback to call after the resolving has finished or timeout
410  * has happened.
411  * @param user_data The user data.
412  * @param timeout The timeout value for the connection. Possible values:
413  * SYS_FOREVER_MS: the query is tried forever, user needs to cancel it
414  *            manually if it takes too long time to finish
415  * >0: start the query and let the system timeout it after specified ms
416  *
417  * @return 0 if resolving was started ok, < 0 otherwise
418  */
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)419 static inline int dns_get_addr_info(const char *query,
420 				    enum dns_query_type type,
421 				    uint16_t *dns_id,
422 				    dns_resolve_cb_t cb,
423 				    void *user_data,
424 				    int32_t timeout)
425 {
426 	return dns_resolve_name(dns_resolve_get_default(),
427 				query,
428 				type,
429 				dns_id,
430 				cb,
431 				user_data,
432 				timeout);
433 }
434 
435 /**
436  * @brief Cancel a pending DNS query.
437  *
438  * @details This releases DNS resources used by a pending query.
439  *
440  * @param dns_id DNS id of the pending query
441  *
442  * @return 0 if ok, <0 if error.
443  */
dns_cancel_addr_info(uint16_t dns_id)444 static inline int dns_cancel_addr_info(uint16_t dns_id)
445 {
446 	return dns_resolve_cancel(dns_resolve_get_default(), dns_id);
447 }
448 
449 /**
450  * @}
451  */
452 
453 /** @cond INTERNAL_HIDDEN */
454 
455 /**
456  * @brief Initialize DNS subsystem.
457  */
458 #if defined(CONFIG_DNS_RESOLVER)
459 void dns_init_resolver(void);
460 
461 #else
462 #define dns_init_resolver(...)
463 #endif /* CONFIG_DNS_RESOLVER */
464 
465 /** @endcond */
466 
467 #ifdef __cplusplus
468 }
469 #endif
470 
471 #endif /* ZEPHYR_INCLUDE_NET_DNS_RESOLVE_H_ */
472