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