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 #ifndef DNS_CLIENT_HPP_
30 #define DNS_CLIENT_HPP_
31 
32 #include "openthread-core-config.h"
33 
34 #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
35 
36 #include <openthread/dns_client.h>
37 
38 #include "common/clearable.hpp"
39 #include "common/message.hpp"
40 #include "common/non_copyable.hpp"
41 #include "common/timer.hpp"
42 #include "net/dns_types.hpp"
43 #include "net/ip6.hpp"
44 #include "net/netif.hpp"
45 
46 /**
47  * @file
48  *   This file includes definitions for the DNS client.
49  */
50 
51 #if OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE
52 
53 #if !OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
54 #error "DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE requires OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE"
55 #endif
56 
57 #if !OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE
58 #error "DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE requires OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE"
59 #endif
60 
61 #endif
62 
63 /**
64  * This struct represents an opaque (and empty) type for a response to an address resolution DNS query.
65  *
66  */
67 struct otDnsAddressResponse
68 {
69 };
70 
71 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
72 
73 /**
74  * This struct represents an opaque (and empty) type for a response to browse (service instance enumeration) DNS query.
75  *
76  */
77 struct otDnsBrowseResponse
78 {
79 };
80 
81 /**
82  * This struct represents an opaque (and empty) type for a response to service inst resolution DNS query.
83  *
84  */
85 struct otDnsServiceResponse
86 {
87 };
88 
89 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
90 
91 namespace ot {
92 
93 namespace Srp {
94 class Client;
95 }
96 
97 namespace Dns {
98 
99 /**
100  * This class implements DNS client.
101  *
102  */
103 class Client : public InstanceLocator, private NonCopyable
104 {
105     friend class ot::Srp::Client;
106 
107     typedef Message Query; // `Message` is used to save `Query` related info.
108 
109 public:
110     /**
111      * This type represents a DNS query configuration (e.g., server address, response wait timeout, etc).
112      *
113      */
114     class QueryConfig : public otDnsQueryConfig, public Clearable<QueryConfig>
115     {
116         friend class Client;
117 
118     public:
119         /**
120          * This enumeration type represents the "Recursion Desired" (RD) flag in a `otDnsQueryConfig`.
121          *
122          */
123         enum RecursionFlag : uint8_t
124         {
125             kFlagUnspecified      = OT_DNS_FLAG_UNSPECIFIED,       ///< The flag is not specified.
126             kFlagRecursionDesired = OT_DNS_FLAG_RECURSION_DESIRED, ///< Server can resolve the query recursively.
127             kFlagNoRecursion      = OT_DNS_FLAG_NO_RECURSION,      ///< Server can not resolve the query recursively.
128         };
129 
130 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
131         /**
132          * This enumeration type represents the NAT64 mode.
133          *
134          */
135         enum Nat64Mode : uint8_t
136         {
137             kNat64Unspecified = OT_DNS_NAT64_UNSPECIFIED, ///< NAT64 mode is not specified. Use default NAT64 mode.
138             kNat64Allow       = OT_DNS_NAT64_ALLOW,       ///< Allow NAT64 address translation
139             kNat64Disallow    = OT_DNS_NAT64_DISALLOW,    ///< Disallow NAT64 address translation.
140         };
141 #endif
142 
143         /**
144          * This is the default constructor for `QueryConfig` object.
145          *
146          */
147         QueryConfig(void) = default;
148 
149         /**
150          * This method gets the server socket address (IPv6 address and port number).
151          *
152          * @returns The server socket address.
153          *
154          */
GetServerSockAddr(void) const155         const Ip6::SockAddr &GetServerSockAddr(void) const
156         {
157             return static_cast<const Ip6::SockAddr &>(mServerSockAddr);
158         }
159 
160         /**
161          * This method gets the wait time to receive response from server (in msec).
162          *
163          * @returns The timeout interval in msec.
164          *
165          */
GetResponseTimeout(void) const166         uint32_t GetResponseTimeout(void) const { return mResponseTimeout; }
167 
168         /**
169          * This method gets the maximum number of query transmit attempts before reporting failure.
170          *
171          * @returns The maximum number of query transmit attempts.
172          *
173          */
GetMaxTxAttempts(void) const174         uint8_t GetMaxTxAttempts(void) const { return mMaxTxAttempts; }
175 
176         /**
177          * This method gets the recursion flag indicating whether the server can resolve the query recursively or not.
178          *
179          * @returns The recursion flag.
180          *
181          */
GetRecursionFlag(void) const182         RecursionFlag GetRecursionFlag(void) const { return static_cast<RecursionFlag>(mRecursionFlag); }
183 
184 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
185         /**
186          * This method gets the NAT64 mode.
187          *
188          * @returns The NAT64 mode.
189          *
190          */
GetNat64Mode(void) const191         Nat64Mode GetNat64Mode(void) const { return static_cast<Nat64Mode>(mNat64Mode); }
192 #endif
193 
194     private:
195         static constexpr uint32_t kDefaultResponseTimeout = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_RESPONSE_TIMEOUT;
196         static constexpr uint16_t kDefaultServerPort      = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_PORT;
197         static constexpr uint8_t  kDefaultMaxTxAttempts   = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_MAX_TX_ATTEMPTS;
198         static constexpr bool kDefaultRecursionDesired    = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_RECURSION_DESIRED_FLAG;
199 
200 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
201         static constexpr bool kDefaultNat64Allowed = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_NAT64_ALLOWED;
202 #endif
203 
204         enum InitMode : uint8_t
205         {
206             kInitFromDefaults,
207         };
208 
209         static const char kDefaultServerAddressString[];
210 
211         explicit QueryConfig(InitMode aMode);
212 
GetServerSockAddr(void)213         Ip6::SockAddr &GetServerSockAddr(void) { return static_cast<Ip6::SockAddr &>(mServerSockAddr); }
214 
SetResponseTimeout(uint32_t aResponseTimeout)215         void SetResponseTimeout(uint32_t aResponseTimeout) { mResponseTimeout = aResponseTimeout; }
SetMaxTxAttempts(uint8_t aMaxTxAttempts)216         void SetMaxTxAttempts(uint8_t aMaxTxAttempts) { mMaxTxAttempts = aMaxTxAttempts; }
SetRecursionFlag(RecursionFlag aFlag)217         void SetRecursionFlag(RecursionFlag aFlag) { mRecursionFlag = static_cast<otDnsRecursionFlag>(aFlag); }
218 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
SetNat64Mode(Nat64Mode aMode)219         void SetNat64Mode(Nat64Mode aMode) { mNat64Mode = static_cast<otDnsNat64Mode>(aMode); }
220 #endif
221 
222         void SetFrom(const QueryConfig &aConfig, const QueryConfig &aDefaultConfig);
223     };
224 
225 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
226     /**
227      * This structure provides info for a DNS service instance.
228      *
229      */
230     typedef otDnsServiceInfo ServiceInfo;
231 #endif
232 
233     /**
234      * This class represents a DNS query response.
235      *
236      */
237     class Response : public otDnsAddressResponse,
238 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
239                      public otDnsBrowseResponse,
240                      public otDnsServiceResponse,
241 #endif
242                      public Clearable<Response>
243     {
244         friend class Client;
245 
246     protected:
247         enum Section : uint8_t
248         {
249             kAnswerSection,
250             kAdditionalDataSection,
251         };
252 
Response(void)253         Response(void) { Clear(); }
254 
255         Error GetName(char *aNameBuffer, uint16_t aNameBufferSize) const;
256         void  SelectSection(Section aSection, uint16_t &aOffset, uint16_t &aNumRecord) const;
257         Error CheckForHostNameAlias(Section aSection, Name &aHostName) const;
258         Error FindHostAddress(Section       aSection,
259                               const Name &  aHostName,
260                               uint16_t      aIndex,
261                               Ip6::Address &aAddress,
262                               uint32_t &    aTtl) const;
263 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
264         Error FindARecord(Section aSection, const Name &aHostName, uint16_t aIndex, ARecord &aARecord) const;
265 #endif
266 
267 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
268         Error FindServiceInfo(Section aSection, const Name &aName, ServiceInfo &aServiceInfo) const;
269 #endif
270 
271         Instance *     mInstance;              // The OpenThread instance.
272         Query *        mQuery;                 // The associated query.
273         const Message *mMessage;               // The response message.
274         uint16_t       mAnswerOffset;          // Answer section offset in `mMessage`.
275         uint16_t       mAnswerRecordCount;     // Number of records in answer section.
276         uint16_t       mAdditionalOffset;      // Additional data section offset in `mMessage`.
277         uint16_t       mAdditionalRecordCount; // Number of records in additional data section.
278 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
279         // This flag is only used in an IPv6 address query response.
280         // It indicates that the response does not contain any IPv6
281         // addresses but server provided at least one IPv4 address
282         // in the additional data section for NAT64 address synthesis.
283         bool mIp6QueryResponseRequiresNat64;
284 #endif
285     };
286 
287     /**
288      * This type represents the function pointer callback which is called when a DNS response for an address resolution
289      * query is received.
290      *
291      */
292     typedef otDnsAddressCallback AddressCallback;
293 
294     /**
295      * This type represents an address resolution query DNS response.
296      *
297      */
298     class AddressResponse : public Response
299     {
300         friend class Client;
301 
302     public:
303         /**
304          * This method gets the host name associated with an address resolution DNS response.
305          *
306          * This method MUST only be used from `AddressCallback`.
307          *
308          * @param[out] aNameBuffer       A buffer to char array to output the host name.
309          * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
310          *
311          * @retval kErrorNone    The host name was read successfully.
312          * @retval kErrorNoBufs  The name does not fit in @p aNameBuffer.
313          *
314          */
GetHostName(char * aNameBuffer,uint16_t aNameBufferSize) const315         Error GetHostName(char *aNameBuffer, uint16_t aNameBufferSize) const
316         {
317             return GetName(aNameBuffer, aNameBufferSize);
318         }
319 
320         /**
321          * This method gets the IPv6 address associated with an address resolution DNS response.
322          *
323          * This method MUST only be used from `AddressCallback`.
324          *
325          * The response may include multiple IPv6 address records. @p aIndex can be used to iterate through the list of
326          * addresses. Index zero gets the the first address and so on. When we reach end of the list, this method
327          * returns `kErrorNotFound`.
328          *
329          * @param[in]  aIndex        The address record index to retrieve.
330          * @param[out] aAddress      A reference to an IPv6 address to output the address.
331          * @param[out] aTtl          A reference to a `uint32_t` to output TTL for the address.
332          *
333          * @retval kErrorNone       The address was read successfully.
334          * @retval kErrorNotFound   No address record at @p aIndex.
335          * @retval kErrorParse      Could not parse the records.
336          *
337          */
338         Error GetAddress(uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const;
339 
340     private:
341 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
342         Error GetNat64Prefix(Ip6::Prefix &aPrefix) const;
343 #endif
344     };
345 
346 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
347 
348     /**
349      * This type represents the function pointer callback which is called when a response for a browse (service
350      * instance enumeration) DNS query is received.
351      *
352      */
353     typedef otDnsBrowseCallback BrowseCallback;
354 
355     /**
356      * This type represents a browse (service instance enumeration) DNS response.
357      *
358      */
359     class BrowseResponse : public Response
360     {
361         friend class Client;
362 
363     public:
364         /**
365          * This method gets the service name associated with a DNS browse response.
366          *
367          * This method MUST only be used from `BrowseCallback`.
368          *
369          * @param[out] aNameBuffer       A buffer to char array to output the host name.
370          * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
371          *
372          * @retval kErrorNone    The host name was read successfully.
373          * @retval kErrorNoBufs  The name does not fit in @p aNameBuffer.
374          *
375          */
GetServiceName(char * aNameBuffer,uint16_t aNameBufferSize) const376         Error GetServiceName(char *aNameBuffer, uint16_t aNameBufferSize) const
377         {
378             return GetName(aNameBuffer, aNameBufferSize);
379         }
380 
381         /**
382          * This method gets a service instance associated with a DNS browse (service instance enumeration) response.
383          *
384          * This method MUST only be used from `BrowseCallback`.
385          *
386          * A response may include multiple service instance records. @p aIndex can be used to iterate through the list.
387          * Index zero gives the the first record. When we reach end of the list, `kErrorNotFound` is returned.
388          *
389          * Note that this method gets the service instance label and not the full service instance name which is of the
390          * form `<Instance>.<Service>.<Domain>`.
391          *
392          * @param[in]  aResponse          A pointer to a response.
393          * @param[in]  aIndex             The service instance record index to retrieve.
394          * @param[out] aLabelBuffer       A char array to output the service instance label (MUST NOT be NULL).
395          * @param[in]  aLabelBufferSize   The size of @p aLabelBuffer.
396          *
397          * @retval kErrorNone         The service instance was read successfully.
398          * @retval kErrorNoBufs       The name does not fit in @p aNameBuffer.
399          * @retval kErrorNotFound     No service instance record at @p aIndex.
400          * @retval kErrorParse        Could not parse the records.
401          *
402          */
403         Error GetServiceInstance(uint16_t aIndex, char *aLabelBuffer, uint8_t aLabelBufferSize) const;
404 
405         /**
406          * This method gets info for a service instance from a DNS browse (service instance enumeration) response.
407          *
408          * This method MUST only be used from `BrowseCallback`.
409          *
410          * A browse DNS response should include the SRV, TXT, and AAAA records for the service instances that are
411          * enumerated (note that it is a SHOULD and not a MUST requirement). This method tries to retrieve this info
412          * for a given service instance.
413          *
414          * - If no matching SRV record is found, `kErrorNotFound` is returned.
415          * - If a matching SRV record is found, @p aServiceInfo is updated returning `kErrorNone`.
416          * - If no matching TXT record is found, `mTxtDataSize` in @p aServiceInfo is set to zero.
417          * - If no matching AAAA record is found, `mHostAddress is set to all zero or unspecified address.
418          * - If there are multiple AAAA records for the host name `mHostAddress` is set to the first one. The other
419          *   addresses can be retrieved using `GetHostAddress()` method.
420          *
421          * @param[in]  aInstanceLabel     The service instance label (MUST NOT be `nullptr`).
422          * @param[out] aServiceInfo       A `ServiceInfo` to output the service instance information.
423          *
424          * @retval kErrorNone         The service instance info was read. @p aServiceInfo is updated.
425          * @retval kErrorNotFound     Could not find a matching SRV record for @p aInstanceLabel.
426          * @retval kErrorNoBufs       The host name and/or the TXT data could not fit in given buffers.
427          * @retval kErrorParse        Could not parse the records.
428          *
429          */
430         Error GetServiceInfo(const char *aInstanceLabel, ServiceInfo &aServiceInfo) const;
431 
432         /**
433          * This method gets the host IPv6 address from a DNS browse (service instance enumeration) response.
434          *
435          * This method MUST only be used from `BrowseCallback`.
436          *
437          * The response can include zero or more IPv6 address records. @p aIndex can be used to iterate through the
438          * list of addresses. Index zero gets the first address and so on. When we reach end of the list, this method
439          * returns `kErrorNotFound`.
440          *
441          * @param[in]  aHostName     The host name to get the address (MUST NOT be `nullptr`).
442          * @param[in]  aIndex        The address record index to retrieve.
443          * @param[out] aAddress      A reference to an IPv6 address to output the address.
444          * @param[out] aTtl          A reference to a `uint32_t` to output TTL for the address.
445          *
446          * @retval kErrorNone       The address was read successfully.
447          * @retval kErrorNotFound   No address record for @p aHostname at @p aIndex.
448          * @retval kErrorParse      Could not parse the records.
449          *
450          */
451         Error GetHostAddress(const char *aHostName, uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const;
452 
453     private:
454         Error FindPtrRecord(const char *aInstanceLabel, Name &aInstanceName) const;
455     };
456 
457     /**
458      * This type represents the function pointer callback which is called when a response for a service instance
459      * resolution DNS query is received.
460      *
461      */
462     typedef otDnsServiceCallback ServiceCallback;
463 
464     /**
465      * This type represents a service instance resolution DNS response.
466      *
467      */
468     class ServiceResponse : public Response
469     {
470         friend class Client;
471 
472     public:
473         /**
474          * This method gets the service instance name associated with a DNS service instance resolution response.
475          *
476          * This method MUST only be used from `ServiceCallback`.
477          *
478          * @param[out] aLabelBuffer      A buffer to char array to output the service instance label (MUST NOT be NULL).
479          * @param[in]  aLabelBufferSize  The size of @p aLabelBuffer.
480          * @param[out] aNameBuffer       A buffer to char array to output the rest of service name (can be NULL if user
481          *                               is not interested in getting the name).
482          * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
483          *
484          * @retval kErrorNone    The service instance name was read successfully.
485          * @retval kErrorNoBufs  Either the label or name does not fit in the given buffers.
486          *
487          */
488         Error GetServiceName(char *   aLabelBuffer,
489                              uint8_t  aLabelBufferSize,
490                              char *   aNameBuffer,
491                              uint16_t aNameBufferSize) const;
492 
493         /**
494          * This method gets info for a service instance from a DNS service instance resolution response.
495          *
496          * This method MUST only be used from `ServiceCallback`.
497          *
498          * - If no matching SRV record is found, `kErrorNotFound` is returned.
499          * - If a matching SRV record is found, @p aServiceInfo is updated and `kErrorNone` is returned.
500          * - If no matching TXT record is found, `mTxtDataSize` in @p aServiceInfo is set to zero.
501          * - If no matching AAAA record is found, `mHostAddress is set to all zero or unspecified address.
502          * - If there are multiple AAAA records for the host name, `mHostAddress` is set to the first one. The other
503          *   addresses can be retrieved using `GetHostAddress()` method.
504          *
505          * @param[out] aServiceInfo       A `ServiceInfo` to output the service instance information
506          *
507          * @retval kErrorNone         The service instance info was read. @p aServiceInfo is updated.
508          * @retval kErrorNotFound     Could not find a matching SRV record.
509          * @retval kErrorNoBufs       The host name and/or TXT data could not fit in the given buffers.
510          * @retval kErrorParse        Could not parse the records in the @p aResponse.
511          *
512          */
513         Error GetServiceInfo(ServiceInfo &aServiceInfo) const;
514 
515         /**
516          * This method gets the host IPv6 address from a DNS service instance resolution response.
517          *
518          * This method MUST only be used from `ServiceCallback`.
519          *
520          * The response can include zero or more IPv6 address records. @p aIndex can be used to iterate through the
521          * list of addresses. Index zero gets the first address and so on. When we reach end of the list, this method
522          * returns `kErrorNotFound`.
523          *
524          * @param[in]  aHostName     The host name to get the address (MUST NOT be `nullptr`).
525          * @param[in]  aIndex        The address record index to retrieve.
526          * @param[out] aAddress      A reference to an IPv6 address to output the address.
527          * @param[out] aTtl          A reference to a `uint32_t` to output TTL for the address.
528          *
529          * @retval kErrorNone       The address was read successfully.
530          * @retval kErrorNotFound   No address record for @p aHostname at @p aIndex.
531          * @retval kErrorParse      Could not parse the records.
532          *
533          */
534         Error GetHostAddress(const char *aHostName, uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const;
535     };
536 
537 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
538 
539     /**
540      * This constructor initializes the object.
541      *
542      * @param[in]  aInstance     A reference to the OpenThread instance.
543      *
544      */
545     explicit Client(Instance &aInstance);
546 
547     /**
548      * This method starts the DNS client.
549      *
550      * @retval kErrorNone     Successfully started the DNS client.
551      * @retval kErrorAlready  The socket is already open.
552      *
553      */
554     Error Start(void);
555 
556     /**
557      * This method stops the DNS client.
558      *
559      */
560     void Stop(void);
561 
562     /**
563      * This method gets the current default query config being used by DNS client.
564      *
565      * @returns The current default query config.
566      *
567      */
GetDefaultConfig(void) const568     const QueryConfig &GetDefaultConfig(void) const { return mDefaultConfig; }
569 
570     /**
571      * This method sets the default query config.
572      *
573      * @param[in] aQueryConfig   The new default query config.
574      *
575      */
576     void SetDefaultConfig(const QueryConfig &aQueryConfig);
577 
578     /**
579      * This method resets the default config to the config used when the OpenThread stack starts.
580      *
581      * When OpenThread stack starts, the default DNS query config is determined from a set of OT config options such as
582      * `OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_IP6_ADDRESS`, `_DEFAULT_SERVER_PORT`, or `_DEFAULT_RESPONSE_TIMEOUT`
583      * etc. (see `config/dns_client.h` for all related config options).
584      *
585      */
586     void ResetDefaultConfig(void);
587 
588     /**
589      * This method sends an address resolution DNS query for AAAA (IPv6) record for a given host name.
590      *
591      * The @p aConfig can be nullptr. In this case the default config (from `GetDefaultConfig()`) will be used as
592      * the config for this query. In a non-nullptr @p aConfig, some of the fields can be left unspecified (value zero).
593      * The unspecified fields are then replaced by the values from the default config.
594      *
595      * @param[in]  aHostName        The host name for which to query the address (MUST NOT be `nullptr`).
596      * @param[in]  aCallback        A callback function pointer to report the result of query.
597      * @param[in]  aContext         A pointer to arbitrary context information passed to @p aCallback.
598      * @param[in]  aConfig          The config to use for this query.
599      *
600      * @retval kErrorNone           Successfully sent DNS query.
601      * @retval kErrorNoBufs         Failed to allocate retransmission data.
602      * @retval kErrorInvalidArgs    The host name is not valid format.
603      * @retval kErrorInvalidState   Cannot send query since Thread interface is not up.
604      *
605      */
606     Error ResolveAddress(const char *       aHostName,
607                          AddressCallback    aCallback,
608                          void *             aContext,
609                          const QueryConfig *aConfig = nullptr);
610 
611 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
612 
613     /**
614      * This method sends a browse (service instance enumeration) DNS query for a given service name.
615      *
616      * The @p aConfig can be nullptr. In this case the default config (from `GetDefaultConfig()`) will be used as
617      * the config for this query. In a non-nullptr @p aConfig, some of the fields can be left unspecified (value zero).
618      * The unspecified fields are then replaced by the values from the default config.
619      *
620      * @param[in]  aServiceName     The service name to query for (MUST NOT be `nullptr`).
621      * @param[in]  aCallback        The callback to report the response or errors (such as time-out).
622      * @param[in]  aContext         A pointer to arbitrary context information.
623      * @param[in]  aConfig          The config to use for this query.
624      *
625      * @retval kErrorNone       Query sent successfully. @p aCallback will be invoked to report the status.
626      * @retval kErrorNoBufs     Insufficient buffer to prepare and send query.
627      *
628      */
629     Error Browse(const char *       aServiceName,
630                  BrowseCallback     aCallback,
631                  void *             aContext,
632                  const QueryConfig *aConfig = nullptr);
633 
634     /**
635      * This method sends a DNS service instance resolution query for a given service instance.
636      *
637      * The @p aConfig can be nullptr. In this case the default config (from `GetDefaultConfig()`) will be used as
638      * the config for this query. In a non-nullptr @p aConfig, some of the fields can be left unspecified (value zero).
639      * The unspecified fields are then replaced by the values from the default config.
640      *
641      * @param[in]  aServerSockAddr    The server socket address.
642      * @param[in]  aInstanceLabel     The service instance label.
643      * @param[in]  aServiceName       The service name (together with @p aInstanceLabel form full instance name).
644      * @param[in]  aCallback          A function pointer that shall be called on response reception or time-out.
645      * @param[in]  aContext           A pointer to arbitrary context information.
646      * @param[in]  aConfig            The config to use for this query.
647      *
648      * @retval kErrorNone         Query sent successfully. @p aCallback will be invoked to report the status.
649      * @retval kErrorNoBufs       Insufficient buffer to prepare and send query.
650      * @retval kErrorInvalidArgs  @p aInstanceLabel is `nullptr`.
651      *
652      */
653     Error ResolveService(const char *         aInstanceLabel,
654                          const char *         aServiceName,
655                          otDnsServiceCallback aCallback,
656                          void *               aContext,
657                          const QueryConfig *  aConfig = nullptr);
658 
659 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
660 
661 private:
662     enum QueryType : uint8_t
663     {
664         kIp6AddressQuery, // IPv6 Address resolution.
665 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
666         kIp4AddressQuery, // IPv4 Address resolution
667 #endif
668 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
669         kBrowseQuery,  // Browse (service instance enumeration).
670         kServiceQuery, // Service instance resolution.
671 #endif
672     };
673 
674     union Callback
675     {
676         AddressCallback mAddressCallback;
677 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
678         BrowseCallback  mBrowseCallback;
679         ServiceCallback mServiceCallback;
680 #endif
681     };
682 
683     typedef MessageQueue QueryList; // List of queries.
684 
685     struct QueryInfo : public Clearable<QueryInfo> // Query related Info
686     {
ReadFromot::Dns::Client::QueryInfo687         void ReadFrom(const Query &aQuery) { IgnoreError(aQuery.Read(0, *this)); }
688 
689         QueryType   mQueryType;
690         uint16_t    mMessageId;
691         Callback    mCallback;
692         void *      mCallbackContext;
693         TimeMilli   mRetransmissionTime;
694         QueryConfig mConfig;
695         uint8_t     mTransmissionCount;
696         // Followed by the name (service, host, instance) encoded as a `Dns::Name`.
697     };
698 
699     static constexpr uint16_t kNameOffsetInQuery = sizeof(QueryInfo);
700 
701     Error       StartQuery(QueryInfo &        aInfo,
702                            const QueryConfig *aConfig,
703                            const char *       aLabel,
704                            const char *       aName,
705                            void *             aContext);
706     Error       AllocateQuery(const QueryInfo &aInfo, const char *aLabel, const char *aName, Query *&aQuery);
707     void        FreeQuery(Query &aQuery);
UpdateQuery(Query & aQuery,const QueryInfo & aInfo)708     void        UpdateQuery(Query &aQuery, const QueryInfo &aInfo) { aQuery.Write(0, aInfo); }
709     void        SendQuery(Query &aQuery, QueryInfo &aInfo, bool aUpdateTimer);
710     void        FinalizeQuery(Query &aQuery, Error aError);
711     void        FinalizeQuery(Response &Response, QueryType aType, Error aError);
712     static void GetCallback(const Query &aQuery, Callback &aCallback, void *&aContext);
713     Error       AppendNameFromQuery(const Query &aQuery, Message &aMessage);
714     Query *     FindQueryById(uint16_t aMessageId);
715     static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMsgInfo);
716     void        ProcessResponse(const Message &aMessage);
717     Error       ParseResponse(Response &aResponse, QueryType &aType, Error &aResponseError);
718     static void HandleTimer(Timer &aTimer);
719     void        HandleTimer(void);
720 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
721     Error CheckAddressResponse(Response &aResponse, Error aResponseError) const;
722 #endif
723 #if OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE
724     void UpdateDefaultConfigAddress(void);
725 #endif
726 
727     static const uint8_t   kQuestionCount[];
728     static const uint16_t *kQuestionRecordTypes[];
729 
730     static const uint16_t kIp6AddressQueryRecordTypes[];
731 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
732     static const uint16_t kIp4AddressQueryRecordTypes[];
733 #endif
734 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
735     static const uint16_t kBrowseQueryRecordTypes[];
736     static const uint16_t kServiceQueryRecordTypes[];
737 #endif
738 
739     Ip6::Udp::Socket mSocket;
740     QueryList        mQueries;
741     TimerMilli       mTimer;
742     QueryConfig      mDefaultConfig;
743 #if OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE
744     bool mUserDidSetDefaultAddress;
745 #endif
746 };
747 
748 } // namespace Dns
749 } // namespace ot
750 
751 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
752 
753 #endif // DNS_CLIENT_HPP_
754