1 /*
2  *  Copyright (c) 2017-2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  * @brief
32  *  This file defines the top-level DNS functions for the OpenThread library.
33  */
34 
35 #ifndef OPENTHREAD_DNS_CLIENT_H_
36 #define OPENTHREAD_DNS_CLIENT_H_
37 
38 #include <openthread/dns.h>
39 #include <openthread/instance.h>
40 #include <openthread/ip6.h>
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
46 /**
47  * @addtogroup api-dns
48  *
49  * @brief
50  *   This module includes functions that control DNS communication.
51  *
52  *   The functions in this module are available only if feature `OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE` is enabled.
53  *
54  * @{
55  *
56  */
57 
58 /**
59  * Type represents the "Recursion Desired" (RD) flag in an `otDnsQueryConfig`.
60  *
61  */
62 typedef enum
63 {
64     OT_DNS_FLAG_UNSPECIFIED       = 0, ///< Indicates the flag is not specified.
65     OT_DNS_FLAG_RECURSION_DESIRED = 1, ///< Indicates DNS name server can resolve the query recursively.
66     OT_DNS_FLAG_NO_RECURSION      = 2, ///< Indicates DNS name server can not resolve the query recursively.
67 } otDnsRecursionFlag;
68 
69 /**
70  * Type represents the NAT64 mode in an `otDnsQueryConfig`.
71  *
72  * The NAT64 mode indicates whether to allow or disallow NAT64 address translation during DNS client address resolution.
73  * This mode is only used when `OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE` is enabled.
74  *
75  */
76 typedef enum
77 {
78     OT_DNS_NAT64_UNSPECIFIED = 0, ///< NAT64 mode is not specified. Use default NAT64 mode.
79     OT_DNS_NAT64_ALLOW       = 1, ///< Allow NAT64 address translation during DNS client address resolution.
80     OT_DNS_NAT64_DISALLOW    = 2, ///< Do not allow NAT64 address translation during DNS client address resolution.
81 } otDnsNat64Mode;
82 
83 /**
84  * Type represents the service resolution mode in an `otDnsQueryConfig`.
85  *
86  * This is only used during DNS client service resolution `otDnsClientResolveService()`. It determines which
87  * record types to query.
88  *
89  */
90 typedef enum
91 {
92     OT_DNS_SERVICE_MODE_UNSPECIFIED      = 0, ///< Mode is not specified. Use default service mode.
93     OT_DNS_SERVICE_MODE_SRV              = 1, ///< Query for SRV record only.
94     OT_DNS_SERVICE_MODE_TXT              = 2, ///< Query for TXT record only.
95     OT_DNS_SERVICE_MODE_SRV_TXT          = 3, ///< Query for both SRV and TXT records in same message.
96     OT_DNS_SERVICE_MODE_SRV_TXT_SEPARATE = 4, ///< Query in parallel for SRV and TXT using separate messages.
97     OT_DNS_SERVICE_MODE_SRV_TXT_OPTIMIZE = 5, ///< Query for TXT/SRV together first, if fails then query separately.
98 } otDnsServiceMode;
99 
100 /**
101  * Type represents the DNS transport protocol in an `otDnsQueryConfig`.
102  *
103  * This `OT_DNS_TRANSPORT_TCP` is only supported when `OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE` is enabled.
104  *
105  */
106 typedef enum
107 {
108     OT_DNS_TRANSPORT_UNSPECIFIED = 0, /// DNS transport is unspecified.
109     OT_DNS_TRANSPORT_UDP         = 1, /// DNS query should be sent via UDP.
110     OT_DNS_TRANSPORT_TCP         = 2, /// DNS query should be sent via TCP.
111 } otDnsTransportProto;
112 
113 /**
114  * Represents a DNS query configuration.
115  *
116  * Any of the fields in this structure can be set to zero to indicate that it is not specified. How the unspecified
117  * fields are treated is determined by the function which uses the instance of `otDnsQueryConfig`.
118  *
119  */
120 typedef struct otDnsQueryConfig
121 {
122     otSockAddr          mServerSockAddr;  ///< Server address (IPv6 addr/port). All zero or zero port for unspecified.
123     uint32_t            mResponseTimeout; ///< Wait time (in msec) to rx response. Zero indicates unspecified value.
124     uint8_t             mMaxTxAttempts;   ///< Maximum tx attempts before reporting failure. Zero for unspecified value.
125     otDnsRecursionFlag  mRecursionFlag;   ///< Indicates whether the server can resolve the query recursively or not.
126     otDnsNat64Mode      mNat64Mode;       ///< Allow/Disallow NAT64 address translation during address resolution.
127     otDnsServiceMode    mServiceMode;     ///< Determines which records to query during service resolution.
128     otDnsTransportProto mTransportProto;  ///< Select default transport protocol.
129 } otDnsQueryConfig;
130 
131 /**
132  * Gets the current default query config used by DNS client.
133  *
134  * When OpenThread stack starts, the default DNS query config is determined from a set of OT config options such as
135  * `OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_IP6_ADDRESS`, `_DEFAULT_SERVER_PORT`, `_DEFAULT_RESPONSE_TIMEOUT`, etc.
136  * (see `config/dns_client.h` for all related config options).
137  *
138  * @param[in]  aInstance        A pointer to an OpenThread instance.
139  *
140  * @returns A pointer to the current default config being used by DNS client.
141  *
142  */
143 const otDnsQueryConfig *otDnsClientGetDefaultConfig(otInstance *aInstance);
144 
145 /**
146  * Sets the default query config on DNS client.
147  *
148  * @note Any ongoing query will continue to use the config from when it was started. The new default config will be
149  * used for any future DNS queries.
150  *
151  * The @p aConfig can be NULL. In this case the default config will be set to the defaults from OT config options
152  * `OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_{}`. This resets the default query config back to to the config when the
153  * OpenThread stack starts.
154  *
155  * In a non-NULL @p aConfig, caller can choose to leave some of the fields in `otDnsQueryConfig` instance unspecified
156  * (value zero). The unspecified fields are replaced by the corresponding OT config option definitions
157  * `OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_{}` to form the default query config.
158  *
159  * When `OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE` is enabled, the server's IPv6 address in
160  * the default config is automatically set and updated by DNS client. This is done only when user does not explicitly
161  * set or specify it. This behavior requires SRP client and its auto-start feature to be enabled. SRP client will then
162  * monitor the Thread Network Data for DNS/SRP Service entries to select an SRP server. The selected SRP server address
163  * is also set as the DNS server address in the default config.
164  *
165  * @param[in]  aInstance   A pointer to an OpenThread instance.
166  * @param[in]  aConfig     A pointer to the new query config to use as default.
167  *
168  */
169 void otDnsClientSetDefaultConfig(otInstance *aInstance, const otDnsQueryConfig *aConfig);
170 
171 /**
172  * An opaque representation of a response to an address resolution DNS query.
173  *
174  * Pointers to instance of this type are provided from callback `otDnsAddressCallback`.
175  *
176  */
177 typedef struct otDnsAddressResponse otDnsAddressResponse;
178 
179 /**
180  * Pointer is called when a DNS response is received for an address resolution query.
181  *
182  * Within this callback the user can use `otDnsAddressResponseGet{Item}()` functions along with the @p aResponse
183  * pointer to get more info about the response.
184  *
185  * The @p aResponse pointer can only be used within this callback and after returning from this function it will not
186  * stay valid, so the user MUST NOT retain the @p aResponse pointer for later use.
187  *
188  * @param[in]  aError     The result of the DNS transaction.
189  * @param[in]  aResponse  A pointer to the response (it is always non-NULL).
190  * @param[in]  aContext   A pointer to application-specific context.
191  *
192  * The @p aError can have the following:
193  *
194  *  - OT_ERROR_NONE              A response was received successfully.
195  *  - OT_ERROR_ABORT             A DNS transaction was aborted by stack.
196  *  - OT_ERROR_RESPONSE_TIMEOUT  No DNS response has been received within timeout.
197  *
198  * If the server rejects the address resolution request the error code from server is mapped as follow:
199  *
200  *  - (0)  NOERROR   Success (no error condition)                    -> OT_ERROR_NONE
201  *  - (1)  FORMERR   Server unable to interpret due to format error  -> OT_ERROR_PARSE
202  *  - (2)  SERVFAIL  Server encountered an internal failure          -> OT_ERROR_FAILED
203  *  - (3)  NXDOMAIN  Name that ought to exist, does not exist        -> OT_ERROR_NOT_FOUND
204  *  - (4)  NOTIMP    Server does not support the query type (OpCode) -> OT_ERROR_NOT_IMPLEMENTED
205  *  - (5)  REFUSED   Server refused for policy/security reasons      -> OT_ERROR_SECURITY
206  *  - (6)  YXDOMAIN  Some name that ought not to exist, does exist   -> OT_ERROR_DUPLICATED
207  *  - (7)  YXRRSET   Some RRset that ought not to exist, does exist  -> OT_ERROR_DUPLICATED
208  *  - (8)  NXRRSET   Some RRset that ought to exist, does not exist  -> OT_ERROR_NOT_FOUND
209  *  - (9)  NOTAUTH   Service is not authoritative for zone           -> OT_ERROR_SECURITY
210  *  - (10) NOTZONE   A name is not in the zone                       -> OT_ERROR_PARSE
211  *  - (20) BADNAME   Bad name                                        -> OT_ERROR_PARSE
212  *  - (21) BADALG    Bad algorithm                                   -> OT_ERROR_SECURITY
213  *  - (22) BADTRUN   Bad truncation                                  -> OT_ERROR_PARSE
214  *  - Other response codes                                           -> OT_ERROR_FAILED
215  *
216  */
217 typedef void (*otDnsAddressCallback)(otError aError, const otDnsAddressResponse *aResponse, void *aContext);
218 
219 /**
220  * Sends an address resolution DNS query for AAAA (IPv6) record(s) for a given host name.
221  *
222  * The @p aConfig can be NULL. In this case the default config (from `otDnsClientGetDefaultConfig()`) will be used as
223  * the config for this query. In a non-NULL @p aConfig, some of the fields can be left unspecified (value zero). The
224  * unspecified fields are then replaced by the values from the default config.
225  *
226  * @param[in]  aInstance        A pointer to an OpenThread instance.
227  * @param[in]  aHostName        The host name for which to query the address (MUST NOT be NULL).
228  * @param[in]  aCallback        A function pointer that shall be called on response reception or time-out.
229  * @param[in]  aContext         A pointer to arbitrary context information.
230  * @param[in]  aConfig          A pointer to the config to use for this query.
231  *
232  * @retval OT_ERROR_NONE          Query sent successfully. @p aCallback will be invoked to report the status.
233  * @retval OT_ERROR_NO_BUFS       Insufficient buffer to prepare and send query.
234  * @retval OT_ERROR_INVALID_ARGS  The host name is not valid format.
235  * @retval OT_ERROR_INVALID_STATE Cannot send query since Thread interface is not up.
236  *
237  */
238 otError otDnsClientResolveAddress(otInstance             *aInstance,
239                                   const char             *aHostName,
240                                   otDnsAddressCallback    aCallback,
241                                   void                   *aContext,
242                                   const otDnsQueryConfig *aConfig);
243 
244 /**
245  * Sends an address resolution DNS query for A (IPv4) record(s) for a given host name.
246  *
247  * Requires and is available when `OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE` is enabled.
248  *
249  * When a successful response is received, the addresses are returned from @p aCallback as NAT64 IPv6 translated
250  * versions of the IPv4 addresses from the query response.
251  *
252  * The @p aConfig can be NULL. In this case the default config (from `otDnsClientGetDefaultConfig()`) will be used as
253  * the config for this query. In a non-NULL @p aConfig, some of the fields can be left unspecified (value zero). The
254  * unspecified fields are then replaced by the values from the default config.
255  *
256  * @param[in]  aInstance        A pointer to an OpenThread instance.
257  * @param[in]  aHostName        The host name for which to query the address (MUST NOT be NULL).
258  * @param[in]  aCallback        A function pointer that shall be called on response reception or time-out.
259  * @param[in]  aContext         A pointer to arbitrary context information.
260  * @param[in]  aConfig          A pointer to the config to use for this query.
261  *
262  * @retval OT_ERROR_NONE          Query sent successfully. @p aCallback will be invoked to report the status.
263  * @retval OT_ERROR_NO_BUFS       Insufficient buffer to prepare and send query.
264  * @retval OT_ERROR_INVALID_ARGS  The host name is not valid format or NAT64 is not enabled in config.
265  * @retval OT_ERROR_INVALID_STATE Cannot send query since Thread interface is not up.
266  *
267  */
268 otError otDnsClientResolveIp4Address(otInstance             *aInstance,
269                                      const char             *aHostName,
270                                      otDnsAddressCallback    aCallback,
271                                      void                   *aContext,
272                                      const otDnsQueryConfig *aConfig);
273 
274 /**
275  * Gets the full host name associated with an address resolution DNS response.
276  *
277  * MUST only be used from `otDnsAddressCallback`.
278  *
279  * @param[in]  aResponse         A pointer to the response.
280  * @param[out] aNameBuffer       A buffer to char array to output the full host name (MUST NOT be NULL).
281  * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
282  *
283  * @retval OT_ERROR_NONE     The full host name was read successfully.
284  * @retval OT_ERROR_NO_BUFS  The name does not fit in @p aNameBuffer.
285  *
286  */
287 otError otDnsAddressResponseGetHostName(const otDnsAddressResponse *aResponse,
288                                         char                       *aNameBuffer,
289                                         uint16_t                    aNameBufferSize);
290 
291 /**
292  * Gets an IPv6 address associated with an address resolution DNS response.
293  *
294  * MUST only be used from `otDnsAddressCallback`.
295  *
296  * The response may include multiple IPv6 address records. @p aIndex can be used to iterate through the list of
297  * addresses. Index zero gets the first address and so on. When we reach end of the list, `OT_ERROR_NOT_FOUND` is
298  * returned.
299  *
300  * @param[in]  aResponse     A pointer to the response.
301  * @param[in]  aIndex        The address record index to retrieve.
302  * @param[out] aAddress      A pointer to a IPv6 address to output the address (MUST NOT be NULL).
303  * @param[out] aTtl          A pointer to an `uint32_t` to output TTL for the address. It can be NULL if caller does not
304  *                           want to get the TTL.
305  *
306  * @retval OT_ERROR_NONE           The address was read successfully.
307  * @retval OT_ERROR_NOT_FOUND      No address record in @p aResponse at @p aIndex.
308  * @retval OT_ERROR_PARSE          Could not parse the records in the @p aResponse.
309  * @retval OT_ERROR_INVALID_STATE  No NAT64 prefix (applicable only when NAT64 is allowed).
310  *
311  */
312 otError otDnsAddressResponseGetAddress(const otDnsAddressResponse *aResponse,
313                                        uint16_t                    aIndex,
314                                        otIp6Address               *aAddress,
315                                        uint32_t                   *aTtl);
316 
317 /**
318  * An opaque representation of a response to a browse (service instance enumeration) DNS query.
319  *
320  * Pointers to instance of this type are provided from callback `otDnsBrowseCallback`.
321  *
322  */
323 typedef struct otDnsBrowseResponse otDnsBrowseResponse;
324 
325 /**
326  * Pointer is called when a DNS response is received for a browse (service instance enumeration) query.
327  *
328  * Within this callback the user can use `otDnsBrowseResponseGet{Item}()` functions along with the @p aResponse
329  * pointer to get more info about the response.
330  *
331  * The @p aResponse pointer can only be used within this callback and after returning from this function it will not
332  * stay valid, so the user MUST NOT retain the @p aResponse pointer for later use.
333  *
334  * @param[in]  aError     The result of the DNS transaction.
335  * @param[in]  aResponse  A pointer to the response (it is always non-NULL).
336  * @param[in]  aContext   A pointer to application-specific context.
337  *
338  * For the full list of possible values for @p aError, please see `otDnsAddressCallback()`.
339  *
340  */
341 typedef void (*otDnsBrowseCallback)(otError aError, const otDnsBrowseResponse *aResponse, void *aContext);
342 
343 /**
344  * Provides info for a DNS service instance.
345  *
346  */
347 typedef struct otDnsServiceInfo
348 {
349     uint32_t     mTtl;                ///< Service record TTL (in seconds).
350     uint16_t     mPort;               ///< Service port number.
351     uint16_t     mPriority;           ///< Service priority.
352     uint16_t     mWeight;             ///< Service weight.
353     char        *mHostNameBuffer;     ///< Buffer to output the service host name (can be NULL if not needed).
354     uint16_t     mHostNameBufferSize; ///< Size of `mHostNameBuffer`.
355     otIp6Address mHostAddress;        ///< The host IPv6 address. Set to all zero if not available.
356     uint32_t     mHostAddressTtl;     ///< The host address TTL.
357     uint8_t     *mTxtData;            ///< Buffer to output TXT data (can be NULL if not needed).
358     uint16_t     mTxtDataSize;        ///< On input, size of `mTxtData` buffer. On output number bytes written.
359     bool         mTxtDataTruncated;   ///< Indicates if TXT data could not fit in `mTxtDataSize` and was truncated.
360     uint32_t     mTxtDataTtl;         ///< The TXT data TTL.
361 } otDnsServiceInfo;
362 
363 /**
364  * Sends a DNS browse (service instance enumeration) query for a given service name.
365  *
366  * Is available when `OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE` is enabled.
367  *
368  * The @p aConfig can be NULL. In this case the default config (from `otDnsClientGetDefaultConfig()`) will be used as
369  * the config for this query. In a non-NULL @p aConfig, some of the fields can be left unspecified (value zero). The
370  * unspecified fields are then replaced by the values from the default config.
371  *
372  * @param[in]  aInstance        A pointer to an OpenThread instance.
373  * @param[in]  aServiceName     The service name to query for (MUST NOT be NULL).
374  * @param[in]  aCallback        A function pointer that shall be called on response reception or time-out.
375  * @param[in]  aContext         A pointer to arbitrary context information.
376  * @param[in]  aConfig          A pointer to the config to use for this query.
377  *
378  * @retval OT_ERROR_NONE        Query sent successfully. @p aCallback will be invoked to report the status.
379  * @retval OT_ERROR_NO_BUFS     Insufficient buffer to prepare and send query.
380  *
381  */
382 otError otDnsClientBrowse(otInstance             *aInstance,
383                           const char             *aServiceName,
384                           otDnsBrowseCallback     aCallback,
385                           void                   *aContext,
386                           const otDnsQueryConfig *aConfig);
387 
388 /**
389  * Gets the service name associated with a DNS browse (service instance enumeration) response.
390  *
391  * MUST only be used from `otDnsBrowseCallback`.
392  *
393  * @param[in]  aResponse         A pointer to the response.
394  * @param[out] aNameBuffer       A buffer to char array to output the service name (MUST NOT be NULL).
395  * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
396  *
397  * @retval OT_ERROR_NONE     The service name was read successfully.
398  * @retval OT_ERROR_NO_BUFS  The name does not fit in @p aNameBuffer.
399  *
400  */
401 otError otDnsBrowseResponseGetServiceName(const otDnsBrowseResponse *aResponse,
402                                           char                      *aNameBuffer,
403                                           uint16_t                   aNameBufferSize);
404 
405 /**
406  * Gets a service instance associated with a DNS browse (service instance enumeration) response.
407  *
408  * MUST only be used from `otDnsBrowseCallback`.
409  *
410  * The response may include multiple service instance records. @p aIndex can be used to iterate through the list. Index
411  * zero gives the first record. When we reach end of the list, `OT_ERROR_NOT_FOUND` is returned.
412  *
413  * Note that this function gets the service instance label and not the full service instance name which is of the form
414  * `<Instance>.<Service>.<Domain>`.
415  *
416  * @param[in]  aResponse          A pointer to the response.
417  * @param[in]  aIndex             The service instance record index to retrieve.
418  * @param[out] aLabelBuffer       A buffer to char array to output the service instance label (MUST NOT be NULL).
419  * @param[in]  aLabelBufferSize   The size of @p aLabelBuffer.
420  *
421  * @retval OT_ERROR_NONE          The service instance was read successfully.
422  * @retval OT_ERROR_NO_BUFS       The name does not fit in @p aNameBuffer.
423  * @retval OT_ERROR_NOT_FOUND     No service instance record in @p aResponse at @p aIndex.
424  * @retval OT_ERROR_PARSE         Could not parse the records in the @p aResponse.
425  *
426  */
427 otError otDnsBrowseResponseGetServiceInstance(const otDnsBrowseResponse *aResponse,
428                                               uint16_t                   aIndex,
429                                               char                      *aLabelBuffer,
430                                               uint8_t                    aLabelBufferSize);
431 
432 /**
433  * Gets info for a service instance from a DNS browse (service instance enumeration) response.
434  *
435  * MUST only be used from `otDnsBrowseCallback`.
436  *
437  * A browse DNS response can include SRV, TXT, and AAAA records for the service instances that are enumerated. This is
438  * a SHOULD and not a MUST requirement, and servers/resolvers are not required to provide this. This function attempts
439  * to retrieve this info for a given service instance when available.
440  *
441  * - If no matching SRV record is found in @p aResponse, `OT_ERROR_NOT_FOUND` is returned. In this case, no additional
442  *   records (no TXT and/or AAAA) are read.
443  * - If a matching SRV record is found in @p aResponse, @p aServiceInfo is updated and `OT_ERROR_NONE` is returned.
444  * - If no matching TXT record is found in @p aResponse, `mTxtDataSize` in @p aServiceInfo is set to zero.
445  * - If TXT data length is greater than `mTxtDataSize`, it is read partially and `mTxtDataTruncated` is set to true.
446  * - If no matching AAAA record is found in @p aResponse, `mHostAddress is set to all zero or unspecified address.
447  * - If there are multiple AAAA records for the host name in @p aResponse, `mHostAddress` is set to the first one. The
448  *   other addresses can be retrieved using `otDnsBrowseResponseGetHostAddress()`.
449  *
450  * @param[in]  aResponse          A pointer to the response.
451  * @param[in]  aInstanceLabel     The service instance label (MUST NOT be NULL).
452  * @param[out] aServiceInfo       A `ServiceInfo` to output the service instance information (MUST NOT be NULL).
453  *
454  * @retval OT_ERROR_NONE          The service instance info was read. @p aServiceInfo is updated.
455  * @retval OT_ERROR_NOT_FOUND     Could not find a matching SRV record for @p aInstanceLabel.
456  * @retval OT_ERROR_NO_BUFS       The host name and/or TXT data could not fit in the given buffers.
457  * @retval OT_ERROR_PARSE         Could not parse the records in the @p aResponse.
458  *
459  */
460 otError otDnsBrowseResponseGetServiceInfo(const otDnsBrowseResponse *aResponse,
461                                           const char                *aInstanceLabel,
462                                           otDnsServiceInfo          *aServiceInfo);
463 
464 /**
465  * Gets the host IPv6 address from a DNS browse (service instance enumeration) response.
466  *
467  * MUST only be used from `otDnsBrowseCallback`.
468  *
469  * The response can include zero or more IPv6 address records. @p aIndex can be used to iterate through the list of
470  * addresses. Index zero gets the first address and so on. When we reach end of the list, `OT_ERROR_NOT_FOUND` is
471  * returned.
472  *
473  * @param[in]  aResponse     A pointer to the response.
474  * @param[in]  aHostName     The host name to get the address (MUST NOT be NULL).
475  * @param[in]  aIndex        The address record index to retrieve.
476  * @param[out] aAddress      A pointer to a IPv6 address to output the address (MUST NOT be NULL).
477  * @param[out] aTtl          A pointer to an `uint32_t` to output TTL for the address. It can be NULL if caller does
478  *                           not want to get the TTL.
479  *
480  * @retval OT_ERROR_NONE       The address was read successfully.
481  * @retval OT_ERROR_NOT_FOUND  No address record for @p aHostname in @p aResponse at @p aIndex.
482  * @retval OT_ERROR_PARSE      Could not parse the records in the @p aResponse.
483  *
484  */
485 otError otDnsBrowseResponseGetHostAddress(const otDnsBrowseResponse *aResponse,
486                                           const char                *aHostName,
487                                           uint16_t                   aIndex,
488                                           otIp6Address              *aAddress,
489                                           uint32_t                  *aTtl);
490 
491 /**
492  * An opaque representation of a response to a service instance resolution DNS query.
493  *
494  * Pointers to instance of this type are provided from callback `otDnsAddressCallback`.
495  *
496  */
497 typedef struct otDnsServiceResponse otDnsServiceResponse;
498 
499 /**
500  * Pointer is called when a DNS response is received for a service instance resolution query.
501  *
502  * Within this callback the user can use `otDnsServiceResponseGet{Item}()` functions along with the @p aResponse
503  * pointer to get more info about the response.
504  *
505  * The @p aResponse pointer can only be used within this callback and after returning from this function it will not
506  * stay valid, so the user MUST NOT retain the @p aResponse pointer for later use.
507  *
508  * @param[in]  aError     The result of the DNS transaction.
509  * @param[in]  aResponse  A pointer to the response (it is always non-NULL).
510  * @param[in]  aContext   A pointer to application-specific context.
511  *
512  * For the full list of possible values for @p aError, please see `otDnsAddressCallback()`.
513  *
514  */
515 typedef void (*otDnsServiceCallback)(otError aError, const otDnsServiceResponse *aResponse, void *aContext);
516 
517 /**
518  * Starts a DNS service instance resolution for a given service instance.
519  *
520  * Is available when `OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE` is enabled.
521  *
522  * The @p aConfig can be NULL. In this case the default config (from `otDnsClientGetDefaultConfig()`) will be used as
523  * the config for this query. In a non-NULL @p aConfig, some of the fields can be left unspecified (value zero). The
524  * unspecified fields are then replaced by the values from the default config.
525  *
526  * The function sends queries for SRV and/or TXT records for the given service instance. The `mServiceMode` field in
527  * `otDnsQueryConfig` determines which records to query (SRV only, TXT only, or both SRV and TXT) and how to perform
528  * the query (together in the same message, separately in parallel, or in optimized mode where client will try in the
529  * same message first and then separately if it fails to get a response).
530  *
531  * The SRV record provides information about service port, priority, and weight along with the host name associated
532  * with the service instance. This function DOES NOT perform address resolution for the host name discovered from SRV
533  * record. The server/resolver may provide AAAA/A record(s) for the host name in the Additional Data section of the
534  * response to SRV/TXT query and this information can be retrieved using `otDnsServiceResponseGetServiceInfo()` in
535  * `otDnsServiceCallback`. Users of this API MUST NOT assume that host address will always be available from
536  * `otDnsServiceResponseGetServiceInfo()`.
537  *
538  * @param[in]  aInstance          A pointer to an OpenThread instance.
539  * @param[in]  aInstanceLabel     The service instance label.
540  * @param[in]  aServiceName       The service name (together with @p aInstanceLabel form full instance name).
541  * @param[in]  aCallback          A function pointer that shall be called on response reception or time-out.
542  * @param[in]  aContext           A pointer to arbitrary context information.
543  * @param[in]  aConfig            A pointer to the config to use for this query.
544  *
545  * @retval OT_ERROR_NONE          Query sent successfully. @p aCallback will be invoked to report the status.
546  * @retval OT_ERROR_NO_BUFS       Insufficient buffer to prepare and send query.
547  * @retval OT_ERROR_INVALID_ARGS  @p aInstanceLabel is NULL.
548  *
549  */
550 otError otDnsClientResolveService(otInstance             *aInstance,
551                                   const char             *aInstanceLabel,
552                                   const char             *aServiceName,
553                                   otDnsServiceCallback    aCallback,
554                                   void                   *aContext,
555                                   const otDnsQueryConfig *aConfig);
556 
557 /**
558  * Starts a DNS service instance resolution for a given service instance, with a potential follow-up
559  * address resolution for the host name discovered for the service instance.
560  *
561  * Is available when `OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE` is enabled.
562  *
563  * The @p aConfig can be NULL. In this case the default config (from `otDnsClientGetDefaultConfig()`) will be used as
564  * the config for this query. In a non-NULL @p aConfig, some of the fields can be left unspecified (value zero). The
565  * unspecified fields are then replaced by the values from the default config. This function cannot be used with
566  * `mServiceMode` in DNS config set to `OT_DNS_SERVICE_MODE_TXT` (i.e., querying for TXT record only) and will return
567  * `OT_ERROR_INVALID_ARGS`.
568  *
569  * Behaves similarly to `otDnsClientResolveService()` sending queries for SRV and TXT records. However,
570  * if the server/resolver does not provide AAAA/A records for the host name in the response to SRV query (in the
571  * Additional Data section), it will perform host name resolution (sending an AAAA query) for the discovered host name
572  * from the SRV record. The callback @p aCallback is invoked when responses for all queries are received (i.e., both
573  * service and host address resolutions are finished).
574  *
575  * @param[in]  aInstance          A pointer to an OpenThread instance.
576  * @param[in]  aInstanceLabel     The service instance label.
577  * @param[in]  aServiceName       The service name (together with @p aInstanceLabel form full instance name).
578  * @param[in]  aCallback          A function pointer that shall be called on response reception or time-out.
579  * @param[in]  aContext           A pointer to arbitrary context information.
580  * @param[in]  aConfig            A pointer to the config to use for this query.
581  *
582  * @retval OT_ERROR_NONE          Query sent successfully. @p aCallback will be invoked to report the status.
583  * @retval OT_ERROR_NO_BUFS       Insufficient buffer to prepare and send query.
584  * @retval OT_ERROR_INVALID_ARGS  @p aInstanceLabel is NULL, or @p aConfig is invalid.
585  *
586  */
587 otError otDnsClientResolveServiceAndHostAddress(otInstance             *aInstance,
588                                                 const char             *aInstanceLabel,
589                                                 const char             *aServiceName,
590                                                 otDnsServiceCallback    aCallback,
591                                                 void                   *aContext,
592                                                 const otDnsQueryConfig *aConfig);
593 
594 /**
595  * Gets the service instance name associated with a DNS service instance resolution response.
596  *
597  * MUST only be used from `otDnsServiceCallback`.
598  *
599  * @param[in]  aResponse         A pointer to the response.
600  * @param[out] aLabelBuffer      A buffer to char array to output the service instance label (MUST NOT be NULL).
601  * @param[in]  aLabelBufferSize  The size of @p aLabelBuffer.
602  * @param[out] aNameBuffer       A buffer to char array to output the rest of service name (can be NULL if user is
603  *                               not interested in getting the name.
604  * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
605  *
606  * @retval OT_ERROR_NONE     The service name was read successfully.
607  * @retval OT_ERROR_NO_BUFS  Either the label or name does not fit in the given buffers.
608  *
609  */
610 otError otDnsServiceResponseGetServiceName(const otDnsServiceResponse *aResponse,
611                                            char                       *aLabelBuffer,
612                                            uint8_t                     aLabelBufferSize,
613                                            char                       *aNameBuffer,
614                                            uint16_t                    aNameBufferSize);
615 
616 /**
617  * Gets info for a service instance from a DNS service instance resolution response.
618  *
619  * MUST only be used from a `otDnsServiceCallback` triggered from `otDnsClientResolveService()` or
620  * `otDnsClientResolveServiceAndHostAddress()`.
621  *
622  * When this is is used from a `otDnsClientResolveService()` callback, the DNS response from server/resolver may
623  * include AAAA records in its Additional Data section for the host name associated with the service instance that is
624  * resolved. This is a SHOULD and not a MUST requirement so servers/resolvers are not required to provide this. This
625  * function attempts to parse AAAA record(s) if included in the response. If it is not included `mHostAddress` is set
626  * to all zeros (unspecified address). To also resolve the host address, user can use the DNS client API function
627  * `otDnsClientResolveServiceAndHostAddress()` which will perform service resolution followed up by a host name
628  * address resolution query (when AAAA records are not provided by server/resolver in the SRV query response).
629  *
630  * - If a matching SRV record is found in @p aResponse, @p aServiceInfo is updated.
631  * - If no matching SRV record is found, `OT_ERROR_NOT_FOUND` is returned unless the query config for this query
632  *   used `OT_DNS_SERVICE_MODE_TXT` for `mServiceMode` (meaning the request was only for TXT record). In this case, we
633  *   still try to parse the SRV record from Additional Data Section of response (in case server provided the info).
634  * - If no matching TXT record is found in @p aResponse, `mTxtDataSize` in @p aServiceInfo is set to zero.
635  * - If TXT data length is greater than `mTxtDataSize`, it is read partially and `mTxtDataTruncated` is set to true.
636  * - If no matching AAAA record is found in @p aResponse, `mHostAddress is set to all zero or unspecified address.
637  * - If there are multiple AAAA records for the host name in @p aResponse, `mHostAddress` is set to the first one. The
638  *   other addresses can be retrieved using `otDnsServiceResponseGetHostAddress()`.
639  *
640  * @param[in]  aResponse          A pointer to the response.
641  * @param[out] aServiceInfo       A `ServiceInfo` to output the service instance information (MUST NOT be NULL).
642  *
643  * @retval OT_ERROR_NONE          The service instance info was read. @p aServiceInfo is updated.
644  * @retval OT_ERROR_NOT_FOUND     Could not find a required record in @p aResponse.
645  * @retval OT_ERROR_NO_BUFS       The host name and/or TXT data could not fit in the given buffers.
646  * @retval OT_ERROR_PARSE         Could not parse the records in the @p aResponse.
647  *
648  */
649 otError otDnsServiceResponseGetServiceInfo(const otDnsServiceResponse *aResponse, otDnsServiceInfo *aServiceInfo);
650 
651 /**
652  * Gets the host IPv6 address from a DNS service instance resolution response.
653  *
654  * MUST only be used from `otDnsServiceCallback`.
655  *
656  * The response can include zero or more IPv6 address records. @p aIndex can be used to iterate through the list of
657  * addresses. Index zero gets the first address and so on. When we reach end of the list, `OT_ERROR_NOT_FOUND` is
658  * returned.
659  *
660  * @param[in]  aResponse     A pointer to the response.
661  * @param[in]  aHostName     The host name to get the address (MUST NOT be NULL).
662  * @param[in]  aIndex        The address record index to retrieve.
663  * @param[out] aAddress      A pointer to a IPv6 address to output the address (MUST NOT be NULL).
664  * @param[out] aTtl          A pointer to an `uint32_t` to output TTL for the address. It can be NULL if caller does
665  *                           not want to get the TTL.
666  *
667  * @retval OT_ERROR_NONE       The address was read successfully.
668  * @retval OT_ERROR_NOT_FOUND  No address record for @p aHostname in @p aResponse at @p aIndex.
669  * @retval OT_ERROR_PARSE      Could not parse the records in the @p aResponse.
670  *
671  */
672 otError otDnsServiceResponseGetHostAddress(const otDnsServiceResponse *aResponse,
673                                            const char                 *aHostName,
674                                            uint16_t                    aIndex,
675                                            otIp6Address               *aAddress,
676                                            uint32_t                   *aTtl);
677 
678 /**
679  * @}
680  *
681  */
682 
683 #ifdef __cplusplus
684 } // extern "C"
685 #endif
686 
687 #endif // OPENTHREAD_DNS_CLIENT_H_
688