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