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 #if !OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE
65 #error "OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE requires OPENTHREAD_CONFIG_TCP_ENABLE"
66 #endif
67 
68 /**
69  * Represents an opaque (and empty) type for a response to an address resolution DNS query.
70  */
71 struct otDnsAddressResponse
72 {
73 };
74 
75 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
76 
77 /**
78  * Represents an opaque (and empty) type for a response to browse (service instance enumeration) DNS query.
79  */
80 struct otDnsBrowseResponse
81 {
82 };
83 
84 /**
85  * Represents an opaque (and empty) type for a response to service inst resolution DNS query.
86  */
87 struct otDnsServiceResponse
88 {
89 };
90 
91 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
92 
93 namespace ot {
94 
95 namespace Srp {
96 class Client;
97 }
98 
99 namespace Dns {
100 
101 /**
102  * Implements DNS client.
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      * Represents a DNS query configuration (e.g., server address, response wait timeout, etc).
113      */
114     class QueryConfig : public otDnsQueryConfig, public Clearable<QueryConfig>
115     {
116         friend class Client;
117 
118     public:
119         /**
120          * Type represents the "Recursion Desired" (RD) flag in a `otDnsQueryConfig`.
121          */
122         enum RecursionFlag : uint8_t
123         {
124             kFlagUnspecified      = OT_DNS_FLAG_UNSPECIFIED,       ///< The flag is not specified.
125             kFlagRecursionDesired = OT_DNS_FLAG_RECURSION_DESIRED, ///< Server can resolve the query recursively.
126             kFlagNoRecursion      = OT_DNS_FLAG_NO_RECURSION,      ///< Server can not resolve the query recursively.
127         };
128 
129 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
130         /**
131          * Type represents the NAT64 mode.
132          */
133         enum Nat64Mode : uint8_t
134         {
135             kNat64Unspecified = OT_DNS_NAT64_UNSPECIFIED, ///< NAT64 mode is not specified. Use default NAT64 mode.
136             kNat64Allow       = OT_DNS_NAT64_ALLOW,       ///< Allow NAT64 address translation.
137             kNat64Disallow    = OT_DNS_NAT64_DISALLOW,    ///< Disallow NAT64 address translation.
138         };
139 #endif
140 
141         /**
142          * Type represents the service resolution mode.
143          */
144         enum ServiceMode : uint8_t
145         {
146             kServiceModeUnspecified    = OT_DNS_SERVICE_MODE_UNSPECIFIED,      ///< Unspecified. Use default.
147             kServiceModeSrv            = OT_DNS_SERVICE_MODE_SRV,              ///< SRV record only.
148             kServiceModeTxt            = OT_DNS_SERVICE_MODE_TXT,              ///< TXT record only.
149             kServiceModeSrvTxt         = OT_DNS_SERVICE_MODE_SRV_TXT,          ///< SRV and TXT same msg.
150             kServiceModeSrvTxtSeparate = OT_DNS_SERVICE_MODE_SRV_TXT_SEPARATE, ///< SRV and TXT separate msgs.
151             kServiceModeSrvTxtOptimize = OT_DNS_SERVICE_MODE_SRV_TXT_OPTIMIZE, ///< Same msg first, if fail separate.
152         };
153 
154         /**
155          * Type represents the DNS transport protocol selection.
156          */
157         enum TransportProto : uint8_t
158         {
159             kDnsTransportUnspecified = OT_DNS_TRANSPORT_UNSPECIFIED, /// Dns transport is unspecified.
160             kDnsTransportUdp         = OT_DNS_TRANSPORT_UDP,         /// Dns query should be sent via UDP.
161             kDnsTransportTcp         = OT_DNS_TRANSPORT_TCP,         /// Dns query should be sent via TCP.
162         };
163 
164         /**
165          * This is the default constructor for `QueryConfig` object.
166          */
167         QueryConfig(void) = default;
168 
169         /**
170          * Gets the server socket address (IPv6 address and port number).
171          *
172          * @returns The server socket address.
173          */
GetServerSockAddr(void) const174         const Ip6::SockAddr &GetServerSockAddr(void) const
175         {
176             return static_cast<const Ip6::SockAddr &>(mServerSockAddr);
177         }
178 
179         /**
180          * Gets the wait time to receive response from server (in msec).
181          *
182          * @returns The timeout interval in msec.
183          */
GetResponseTimeout(void) const184         uint32_t GetResponseTimeout(void) const { return mResponseTimeout; }
185 
186         /**
187          * Gets the maximum number of query transmit attempts before reporting failure.
188          *
189          * @returns The maximum number of query transmit attempts.
190          */
GetMaxTxAttempts(void) const191         uint8_t GetMaxTxAttempts(void) const { return mMaxTxAttempts; }
192 
193         /**
194          * Gets the recursion flag indicating whether the server can resolve the query recursively or not.
195          *
196          * @returns The recursion flag.
197          */
GetRecursionFlag(void) const198         RecursionFlag GetRecursionFlag(void) const { return static_cast<RecursionFlag>(mRecursionFlag); }
199 
200 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
201         /**
202          * Gets the NAT64 mode.
203          *
204          * @returns The NAT64 mode.
205          */
GetNat64Mode(void) const206         Nat64Mode GetNat64Mode(void) const { return static_cast<Nat64Mode>(mNat64Mode); }
207 #endif
208         /**
209          * Gets the service resolution mode.
210          *
211          * @returns The service resolution mode.
212          */
GetServiceMode(void) const213         ServiceMode GetServiceMode(void) const { return static_cast<ServiceMode>(mServiceMode); }
214 
215         /**
216          * Gets the transport protocol.
217          *
218          * @returns The transport protocol.
219          */
GetTransportProto(void) const220         TransportProto GetTransportProto(void) const { return static_cast<TransportProto>(mTransportProto); };
221 
222     private:
223         static constexpr uint32_t kDefaultResponseTimeout = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_RESPONSE_TIMEOUT;
224         static constexpr uint16_t kDefaultServerPort      = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_PORT;
225         static constexpr uint8_t  kDefaultMaxTxAttempts   = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_MAX_TX_ATTEMPTS;
226         static constexpr bool kDefaultRecursionDesired    = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_RECURSION_DESIRED_FLAG;
227         static constexpr ServiceMode kDefaultServiceMode =
228             static_cast<ServiceMode>(OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVICE_MODE);
229 
230         static_assert(kDefaultServiceMode != kServiceModeUnspecified, "Invalid default service mode");
231 
232 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
233         static constexpr bool kDefaultNat64Allowed = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_NAT64_ALLOWED;
234 #endif
235 
236         enum InitMode : uint8_t
237         {
238             kInitFromDefaults,
239         };
240 
241         static const char kDefaultServerAddressString[];
242 
243         explicit QueryConfig(InitMode aMode);
244 
GetServerSockAddr(void)245         Ip6::SockAddr &GetServerSockAddr(void) { return AsCoreType(&mServerSockAddr); }
246 
SetResponseTimeout(uint32_t aResponseTimeout)247         void SetResponseTimeout(uint32_t aResponseTimeout) { mResponseTimeout = aResponseTimeout; }
SetMaxTxAttempts(uint8_t aMaxTxAttempts)248         void SetMaxTxAttempts(uint8_t aMaxTxAttempts) { mMaxTxAttempts = aMaxTxAttempts; }
SetRecursionFlag(RecursionFlag aFlag)249         void SetRecursionFlag(RecursionFlag aFlag) { mRecursionFlag = static_cast<otDnsRecursionFlag>(aFlag); }
SetServiceMode(ServiceMode aMode)250         void SetServiceMode(ServiceMode aMode) { mServiceMode = static_cast<otDnsServiceMode>(aMode); }
251 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
SetNat64Mode(Nat64Mode aMode)252         void SetNat64Mode(Nat64Mode aMode) { mNat64Mode = static_cast<otDnsNat64Mode>(aMode); }
253 #endif
SetTransportProto(TransportProto aTransportProto)254         void SetTransportProto(TransportProto aTransportProto)
255         {
256             mTransportProto = static_cast<otDnsTransportProto>(aTransportProto);
257         }
258 
259         void SetFrom(const QueryConfig *aConfig, const QueryConfig &aDefaultConfig);
260     };
261 
262 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
263     /**
264      * Provides info for a DNS service instance.
265      */
266     typedef otDnsServiceInfo ServiceInfo;
267 #endif
268 
269     /**
270      * Represents a DNS query response.
271      */
272     class Response : public otDnsAddressResponse,
273 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
274                      public otDnsBrowseResponse,
275                      public otDnsServiceResponse,
276 #endif
277                      public Clearable<Response>
278     {
279         friend class Client;
280 
281     protected:
282         enum Section : uint8_t
283         {
284             kAnswerSection,
285             kAdditionalDataSection,
286         };
287 
Response(void)288         Response(void) { Clear(); }
289 
290         Error GetName(char *aNameBuffer, uint16_t aNameBufferSize) const;
291         void  SelectSection(Section aSection, uint16_t &aOffset, uint16_t &aNumRecord) const;
292         Error CheckForHostNameAlias(Section aSection, Name &aHostName) const;
293         Error FindHostAddress(Section       aSection,
294                               const Name   &aHostName,
295                               uint16_t      aIndex,
296                               Ip6::Address &aAddress,
297                               uint32_t     &aTtl) const;
298 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
299         Error FindARecord(Section aSection, const Name &aHostName, uint16_t aIndex, ARecord &aARecord) const;
300 #endif
301 
302 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
303         void  InitServiceInfo(ServiceInfo &aServiceInfo) const;
304         Error ReadServiceInfo(Section aSection, const Name &aName, ServiceInfo &aServiceInfo) const;
305         Error ReadTxtRecord(Section aSection, const Name &aName, ServiceInfo &aServiceInfo) const;
306 #endif
307         void PopulateFrom(const Message &aMessage);
308 
309         Instance      *mInstance;              // The OpenThread instance.
310         Query         *mQuery;                 // The associated query.
311         const Message *mMessage;               // The response message.
312         Response      *mNext;                  // The next response when we have related queries.
313         uint16_t       mAnswerOffset;          // Answer section offset in `mMessage`.
314         uint16_t       mAnswerRecordCount;     // Number of records in answer section.
315         uint16_t       mAdditionalOffset;      // Additional data section offset in `mMessage`.
316         uint16_t       mAdditionalRecordCount; // Number of records in additional data section.
317 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
318         // This flag is only used in an IPv6 address query response.
319         // It indicates that the response does not contain any IPv6
320         // addresses but server provided at least one IPv4 address
321         // in the additional data section for NAT64 address synthesis.
322         bool mIp6QueryResponseRequiresNat64;
323 #endif
324     };
325 
326     /**
327      * Represents the function pointer callback which is called when a DNS response for an address resolution
328      * query is received.
329      */
330     typedef otDnsAddressCallback AddressCallback;
331 
332     /**
333      * Represents an address resolution query DNS response.
334      */
335     class AddressResponse : public Response
336     {
337         friend class Client;
338 
339     public:
340         /**
341          * Gets the host name associated with an address resolution DNS response.
342          *
343          * MUST only be used from `AddressCallback`.
344          *
345          * @param[out] aNameBuffer       A buffer to char array to output the host name.
346          * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
347          *
348          * @retval kErrorNone    The host name was read successfully.
349          * @retval kErrorNoBufs  The name does not fit in @p aNameBuffer.
350          */
GetHostName(char * aNameBuffer,uint16_t aNameBufferSize) const351         Error GetHostName(char *aNameBuffer, uint16_t aNameBufferSize) const
352         {
353             return GetName(aNameBuffer, aNameBufferSize);
354         }
355 
356         /**
357          * Gets the IPv6 address associated with an address resolution DNS response.
358          *
359          * MUST only be used from `AddressCallback`.
360          *
361          * The response may include multiple IPv6 address records. @p aIndex can be used to iterate through the list of
362          * addresses. Index zero gets the the first address and so on. When we reach end of the list, this method
363          * returns `kErrorNotFound`.
364          *
365          * @param[in]  aIndex        The address record index to retrieve.
366          * @param[out] aAddress      A reference to an IPv6 address to output the address.
367          * @param[out] aTtl          A reference to a `uint32_t` to output TTL for the address.
368          *
369          * @retval kErrorNone          The address was read successfully.
370          * @retval kErrorNotFound      No address record at @p aIndex.
371          * @retval kErrorParse         Could not parse the records.
372          * @retval kErrorInvalidState  No NAT64 prefix (applicable only when NAT64 is allowed).
373          */
374         Error GetAddress(uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const;
375 
376     private:
377 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
378         Error GetNat64Prefix(Ip6::Prefix &aPrefix) const;
379 #endif
380     };
381 
382 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
383 
384     /**
385      * Represents the function pointer callback which is called when a response for a browse (service
386      * instance enumeration) DNS query is received.
387      */
388     typedef otDnsBrowseCallback BrowseCallback;
389 
390     /**
391      * Represents a browse (service instance enumeration) DNS response.
392      */
393     class BrowseResponse : public Response
394     {
395         friend class Client;
396 
397     public:
398         /**
399          * Gets the service name associated with a DNS browse response.
400          *
401          * MUST only be used from `BrowseCallback`.
402          *
403          * @param[out] aNameBuffer       A buffer to char array to output the host name.
404          * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
405          *
406          * @retval kErrorNone    The host name was read successfully.
407          * @retval kErrorNoBufs  The name does not fit in @p aNameBuffer.
408          */
GetServiceName(char * aNameBuffer,uint16_t aNameBufferSize) const409         Error GetServiceName(char *aNameBuffer, uint16_t aNameBufferSize) const
410         {
411             return GetName(aNameBuffer, aNameBufferSize);
412         }
413 
414         /**
415          * Gets a service instance associated with a DNS browse (service instance enumeration) response.
416          *
417          * MUST only be used from `BrowseCallback`.
418          *
419          * A response may include multiple service instance records. @p aIndex can be used to iterate through the list.
420          * Index zero gives the the first record. When we reach end of the list, `kErrorNotFound` is returned.
421          *
422          * Note that this method gets the service instance label and not the full service instance name which is of the
423          * form `<Instance>.<Service>.<Domain>`.
424          *
425          * @param[in]  aIndex             The service instance record index to retrieve.
426          * @param[out] aLabelBuffer       A char array to output the service instance label (MUST NOT be NULL).
427          * @param[in]  aLabelBufferSize   The size of @p aLabelBuffer.
428          *
429          * @retval kErrorNone         The service instance was read successfully.
430          * @retval kErrorNoBufs       The name does not fit in @p aNameBuffer.
431          * @retval kErrorNotFound     No service instance record at @p aIndex.
432          * @retval kErrorParse        Could not parse the records.
433          */
434         Error GetServiceInstance(uint16_t aIndex, char *aLabelBuffer, uint8_t aLabelBufferSize) const;
435 
436         /**
437          * Gets info for a service instance from a DNS browse (service instance enumeration) response.
438          *
439          * MUST only be used from `BrowseCallback`.
440          *
441          * A browse DNS response should include the SRV, TXT, and AAAA records for the service instances that are
442          * enumerated (note that it is a SHOULD and not a MUST requirement). This method tries to retrieve this info
443          * for a given service instance.
444          *
445          * - If no matching SRV record is found, `kErrorNotFound` is returned.
446          * - If a matching SRV record is found, @p aServiceInfo is updated returning `kErrorNone`.
447          * - If no matching TXT record is found, `mTxtDataSize` in @p aServiceInfo is set to zero.
448          * - If no matching AAAA record is found, `mHostAddress is set to all zero or unspecified address.
449          * - If there are multiple AAAA records for the host name `mHostAddress` is set to the first one. The other
450          *   addresses can be retrieved using `GetHostAddress()` method.
451          *
452          * @param[in]  aInstanceLabel     The service instance label (MUST NOT be `nullptr`).
453          * @param[out] aServiceInfo       A `ServiceInfo` to output the service instance information.
454          *
455          * @retval kErrorNone         The service instance info was read. @p aServiceInfo is updated.
456          * @retval kErrorNotFound     Could not find a matching SRV record for @p aInstanceLabel.
457          * @retval kErrorNoBufs       The host name and/or the TXT data could not fit in given buffers.
458          * @retval kErrorParse        Could not parse the records.
459          */
460         Error GetServiceInfo(const char *aInstanceLabel, ServiceInfo &aServiceInfo) const;
461 
462         /**
463          * Gets the host IPv6 address from a DNS browse (service instance enumeration) response.
464          *
465          * MUST only be used from `BrowseCallback`.
466          *
467          * The response can include zero or more IPv6 address records. @p aIndex can be used to iterate through the
468          * list of addresses. Index zero gets the first address and so on. When we reach end of the list, this method
469          * returns `kErrorNotFound`.
470          *
471          * @param[in]  aHostName     The host name to get the address (MUST NOT be `nullptr`).
472          * @param[in]  aIndex        The address record index to retrieve.
473          * @param[out] aAddress      A reference to an IPv6 address to output the address.
474          * @param[out] aTtl          A reference to a `uint32_t` to output TTL for the address.
475          *
476          * @retval kErrorNone       The address was read successfully.
477          * @retval kErrorNotFound   No address record for @p aHostname at @p aIndex.
478          * @retval kErrorParse      Could not parse the records.
479          */
480         Error GetHostAddress(const char *aHostName, uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const;
481 
482     private:
483         Error FindPtrRecord(const char *aInstanceLabel, Name &aInstanceName) const;
484     };
485 
486     /**
487      * Represents the function pointer callback which is called when a response for a service instance
488      * resolution DNS query is received.
489      */
490     typedef otDnsServiceCallback ServiceCallback;
491 
492     /**
493      * Represents a service instance resolution DNS response.
494      */
495     class ServiceResponse : public Response
496     {
497         friend class Client;
498 
499     public:
500         /**
501          * Gets the service instance name associated with a DNS service instance resolution response.
502          *
503          * MUST only be used from `ServiceCallback`.
504          *
505          * @param[out] aLabelBuffer      A buffer to char array to output the service instance label (MUST NOT be NULL).
506          * @param[in]  aLabelBufferSize  The size of @p aLabelBuffer.
507          * @param[out] aNameBuffer       A buffer to char array to output the rest of service name (can be NULL if user
508          *                               is not interested in getting the name).
509          * @param[in]  aNameBufferSize   The size of @p aNameBuffer.
510          *
511          * @retval kErrorNone    The service instance name was read successfully.
512          * @retval kErrorNoBufs  Either the label or name does not fit in the given buffers.
513          */
514         Error GetServiceName(char    *aLabelBuffer,
515                              uint8_t  aLabelBufferSize,
516                              char    *aNameBuffer,
517                              uint16_t aNameBufferSize) const;
518 
519         /**
520          * Gets info for a service instance from a DNS service instance resolution response.
521          *
522          * MUST only be used from `ServiceCallback`.
523          *
524          * - If no matching SRV record is found, `kErrorNotFound` is returned.
525          * - If a matching SRV record is found, @p aServiceInfo is updated and `kErrorNone` is returned.
526          * - If no matching TXT record is found, `mTxtDataSize` in @p aServiceInfo is set to zero.
527          * - If no matching AAAA record is found, `mHostAddress is set to all zero or unspecified address.
528          * - If there are multiple AAAA records for the host name, `mHostAddress` is set to the first one. The other
529          *   addresses can be retrieved using `GetHostAddress()` method.
530          *
531          * @param[out] aServiceInfo       A `ServiceInfo` to output the service instance information
532          *
533          * @retval kErrorNone         The service instance info was read. @p aServiceInfo is updated.
534          * @retval kErrorNotFound     Could not find a matching SRV record.
535          * @retval kErrorNoBufs       The host name and/or TXT data could not fit in the given buffers.
536          * @retval kErrorParse        Could not parse the records in the @p aResponse.
537          */
538         Error GetServiceInfo(ServiceInfo &aServiceInfo) const;
539 
540         /**
541          * Gets the host IPv6 address from a DNS service instance resolution response.
542          *
543          * MUST only be used from `ServiceCallback`.
544          *
545          * The response can include zero or more IPv6 address records. @p aIndex can be used to iterate through the
546          * list of addresses. Index zero gets the first address and so on. When we reach end of the list, this method
547          * returns `kErrorNotFound`.
548          *
549          * @param[in]  aHostName     The host name to get the address (MUST NOT be `nullptr`).
550          * @param[in]  aIndex        The address record index to retrieve.
551          * @param[out] aAddress      A reference to an IPv6 address to output the address.
552          * @param[out] aTtl          A reference to a `uint32_t` to output TTL for the address.
553          *
554          * @retval kErrorNone       The address was read successfully.
555          * @retval kErrorNotFound   No address record for @p aHostname at @p aIndex.
556          * @retval kErrorParse      Could not parse the records.
557          */
558         Error GetHostAddress(const char *aHostName, uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const;
559     };
560 
561 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
562 
563     /**
564      * Initializes the object.
565      *
566      * @param[in]  aInstance     A reference to the OpenThread instance.
567      */
568     explicit Client(Instance &aInstance);
569 
570     /**
571      * Starts the DNS client.
572      *
573      * @retval kErrorNone     Successfully started the DNS client.
574      * @retval kErrorAlready  The socket is already open.
575      */
576     Error Start(void);
577 
578     /**
579      * Stops the DNS client.
580      */
581     void Stop(void);
582 
583     /**
584      * Gets the current default query config being used by DNS client.
585      *
586      * @returns The current default query config.
587      */
GetDefaultConfig(void) const588     const QueryConfig &GetDefaultConfig(void) const { return mDefaultConfig; }
589 
590     /**
591      * Sets the default query config.
592      *
593      * @param[in] aQueryConfig   The new default query config.
594      */
595     void SetDefaultConfig(const QueryConfig &aQueryConfig);
596 
597     /**
598      * Resets the default config to the config used when the OpenThread stack starts.
599      *
600      * When OpenThread stack starts, the default DNS query config is determined from a set of OT config options such as
601      * `OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_IP6_ADDRESS`, `_DEFAULT_SERVER_PORT`, or `_DEFAULT_RESPONSE_TIMEOUT`
602      * etc. (see `config/dns_client.h` for all related config options).
603      */
604     void ResetDefaultConfig(void);
605 
606     /**
607      * Sends an address resolution DNS query for AAAA (IPv6) record for a given host name.
608      *
609      * The @p aConfig can be nullptr. In this case the default config (from `GetDefaultConfig()`) will be used as
610      * the config for this query. In a non-nullptr @p aConfig, some of the fields can be left unspecified (value zero).
611      * The unspecified fields are then replaced by the values from the default config.
612      *
613      * @param[in]  aHostName        The host name for which to query the address (MUST NOT be `nullptr`).
614      * @param[in]  aCallback        A callback function pointer to report the result of query.
615      * @param[in]  aContext         A pointer to arbitrary context information passed to @p aCallback.
616      * @param[in]  aConfig          The config to use for this query.
617      *
618      * @retval kErrorNone           Successfully sent DNS query.
619      * @retval kErrorNoBufs         Failed to allocate retransmission data.
620      * @retval kErrorInvalidArgs    The host name is not valid format.
621      * @retval kErrorInvalidState   Cannot send query since Thread interface is not up.
622      */
623     Error ResolveAddress(const char        *aHostName,
624                          AddressCallback    aCallback,
625                          void              *aContext,
626                          const QueryConfig *aConfig = nullptr);
627 
628 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
629     /**
630      * Sends an address resolution DNS query for A (IPv4) record for a given host name.
631      *
632      * When a successful response is received, the addresses are returned from @p aCallback as NAT64 IPv6 translated
633      * versions of the IPv4 addresses from the query response.
634      *
635      * The @p aConfig can be nullptr. In this case the default config (from `GetDefaultConfig()`) will be used as
636      * the config for this query. In a non-nullptr @p aConfig, some of the fields can be left unspecified (value zero).
637      * The unspecified fields are then replaced by the values from the default config.
638      *
639      * @param[in]  aHostName        The host name for which to query the address (MUST NOT be `nullptr`).
640      * @param[in]  aCallback        A callback function pointer to report the result of query.
641      * @param[in]  aContext         A pointer to arbitrary context information passed to @p aCallback.
642      * @param[in]  aConfig          The config to use for this query.
643      *
644      * @retval kErrorNone           Successfully sent DNS query.
645      * @retval kErrorNoBufs         Failed to allocate retransmission data.
646      * @retval kErrorInvalidArgs    The host name is not valid format or NAT64 is not enabled in config.
647      * @retval kErrorInvalidState   Cannot send query since Thread interface is not up, or there is no NAT64 prefix.
648      */
649     Error ResolveIp4Address(const char        *aHostName,
650                             AddressCallback    aCallback,
651                             void              *aContext,
652                             const QueryConfig *aConfig = nullptr);
653 #endif
654 
655 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
656 
657     /**
658      * Sends a browse (service instance enumeration) DNS query for a given service name.
659      *
660      * The @p aConfig can be nullptr. In this case the default config (from `GetDefaultConfig()`) will be used as
661      * the config for this query. In a non-nullptr @p aConfig, some of the fields can be left unspecified (value zero).
662      * The unspecified fields are then replaced by the values from the default config.
663      *
664      * @param[in]  aServiceName     The service name to query for (MUST NOT be `nullptr`).
665      * @param[in]  aCallback        The callback to report the response or errors (such as time-out).
666      * @param[in]  aContext         A pointer to arbitrary context information.
667      * @param[in]  aConfig          The config to use for this query.
668      *
669      * @retval kErrorNone       Query sent successfully. @p aCallback will be invoked to report the status.
670      * @retval kErrorNoBufs     Insufficient buffer to prepare and send query.
671      */
672     Error Browse(const char        *aServiceName,
673                  BrowseCallback     aCallback,
674                  void              *aContext,
675                  const QueryConfig *aConfig = nullptr);
676 
677     /**
678      * Starts a DNS service instance resolution for a given service instance.
679      *
680      * The @p aConfig can be `nullptr`. In this case the default config (from `GetDefaultConfig()`) will be used as
681      * the config for this query. In a non-`nullptr` @p aConfig, some of the fields can be left unspecified (value
682      * zero). The unspecified fields are then replaced by the values from the default config.
683      *
684      * @param[in]  aInstanceLabel     The service instance label.
685      * @param[in]  aServiceName       The service name (together with @p aInstanceLabel form full instance name).
686      * @param[in]  aCallback          A function pointer that shall be called on response reception or time-out.
687      * @param[in]  aContext           A pointer to arbitrary context information.
688      * @param[in]  aConfig            The config to use for this query.
689      *
690      * @retval kErrorNone         Query sent successfully. @p aCallback will be invoked to report the status.
691      * @retval kErrorNoBufs       Insufficient buffer to prepare and send query.
692      * @retval kErrorInvalidArgs  @p aInstanceLabel is `nullptr`.
693      */
694     Error ResolveService(const char          *aInstanceLabel,
695                          const char          *aServiceName,
696                          otDnsServiceCallback aCallback,
697                          void                *aContext,
698                          const QueryConfig   *aConfig = nullptr);
699 
700     /**
701      * Starts a DNS service instance resolution for a given service instance, with a potential follow-up
702      * host name resolution (if the server/resolver does not provide AAAA/A records for the host name in the response
703      * to SRV query).
704      *
705      * The @p aConfig can be `nullptr`. In this case the default config (from `GetDefaultConfig()`) will be used as
706      * the config for this query. In a non-`nullptr` @p aConfig, some of the fields can be left unspecified (value
707      * zero). The unspecified fields are then replaced by the values from the default config.
708      *
709      * @param[in]  aInstanceLabel     The service instance label.
710      * @param[in]  aServiceName       The service name (together with @p aInstanceLabel form full instance name).
711      * @param[in]  aCallback          A function pointer that shall be called on response reception or time-out.
712      * @param[in]  aContext           A pointer to arbitrary context information.
713      * @param[in]  aConfig            The config to use for this query.
714      *
715      * @retval kErrorNone         Query sent successfully. @p aCallback will be invoked to report the status.
716      * @retval kErrorNoBufs       Insufficient buffer to prepare and send query.
717      * @retval kErrorInvalidArgs  @p aInstanceLabel is `nullptr` or the @p aConfig is invalid.
718      */
719     Error ResolveServiceAndHostAddress(const char        *aInstanceLabel,
720                                        const char        *aServiceName,
721                                        ServiceCallback    aCallback,
722                                        void              *aContext,
723                                        const QueryConfig *aConfig = nullptr);
724 
725 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
726 
727 private:
728     static constexpr uint16_t kMaxCnameAliasNameChanges     = 40;
729     static constexpr uint8_t  kLimitedQueryServersArraySize = 3;
730 
731     enum QueryType : uint8_t
732     {
733         kIp6AddressQuery, // IPv6 Address resolution.
734 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
735         kIp4AddressQuery, // IPv4 Address resolution
736 #endif
737 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
738         kBrowseQuery,        // Browse (service instance enumeration).
739         kServiceQuerySrvTxt, // Service instance resolution both SRV and TXT records.
740         kServiceQuerySrv,    // Service instance resolution SRV record only.
741         kServiceQueryTxt,    // Service instance resolution TXT record only.
742 #endif
743         kNoQuery,
744     };
745 
746 #if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE
747     enum TcpState : uint8_t
748     {
749         kTcpUninitialized = 0,
750         kTcpConnecting,
751         kTcpConnectedIdle,
752         kTcpConnectedSending,
753     };
754 #endif
755 
756     union Callback
757     {
758         AddressCallback mAddressCallback;
759 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
760         BrowseCallback  mBrowseCallback;
761         ServiceCallback mServiceCallback;
762 #endif
763     };
764 
765     typedef MessageQueue QueryList; // List of queries.
766 
767     struct QueryInfo : public Clearable<QueryInfo> // Query related Info
768     {
ReadFromot::Dns::Client::QueryInfo769         void ReadFrom(const Query &aQuery) { IgnoreError(aQuery.Read(0, *this)); }
770 
771         QueryType   mQueryType;
772         uint16_t    mMessageId;
773         Callback    mCallback;
774         void       *mCallbackContext;
775         TimeMilli   mRetransmissionTime;
776         QueryConfig mConfig;
777         uint8_t     mTransmissionCount;
778         bool        mShouldResolveHostAddr;
779         Query      *mMainQuery;
780         Query      *mNextQuery;
781         Message    *mSavedResponse;
782         // Followed by the name (service, host, instance) encoded as a `Dns::Name`.
783     };
784 
785     static constexpr uint16_t kNameOffsetInQuery = sizeof(QueryInfo);
786 
787     Error       StartQuery(QueryInfo &aInfo, const char *aLabel, const char *aName, QueryType aSecondType = kNoQuery);
788     Error       AllocateQuery(const QueryInfo &aInfo, const char *aLabel, const char *aName, Query *&aQuery);
789     void        FreeQuery(Query &aQuery);
UpdateQuery(Query & aQuery,const QueryInfo & aInfo)790     void        UpdateQuery(Query &aQuery, const QueryInfo &aInfo) { aQuery.Write(0, aInfo); }
791     Query      &FindMainQuery(Query &aQuery);
792     Error       SendQuery(Query &aQuery, QueryInfo &aInfo, bool aUpdateTimer);
793     void        FinalizeQuery(Query &aQuery, Error aError);
794     void        FinalizeQuery(Response &Response, Error aError);
795     static void GetQueryTypeAndCallback(const Query &aQuery, QueryType &aType, Callback &aCallback, void *&aContext);
796     Error       AppendNameFromQuery(const Query &aQuery, Message &aMessage);
797     Query      *FindQueryById(uint16_t aMessageId);
798     void        HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMsgInfo);
799     void        ProcessResponse(const Message &aResponseMessage);
800     Error       ParseResponse(const Message &aResponseMessage, Query *&aQuery, Error &aResponseError);
801     bool        CanFinalizeQuery(Query &aQuery);
802     void        SaveQueryResponse(Query &aQuery, const Message &aResponseMessage);
803     Query      *PopulateResponse(Response &aResponse, Query &aQuery, const Message &aResponseMessage);
804     void        PrepareResponseAndFinalize(Query &aQuery, const Message &aResponseMessage, Response *aPrevResponse);
805     void        HandleTimer(void);
806 
807 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
808     Error ReplaceWithIp4Query(Query &aQuery, const Message &aResponseMessage);
809 #endif
810 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
811     Error Resolve(const char        *aInstanceLabel,
812                   const char        *aServiceName,
813                   ServiceCallback    aCallback,
814                   void              *aContext,
815                   const QueryConfig *aConfig,
816                   bool               aShouldResolveHostAddr);
817     void  CheckAndUpdateServiceMode(QueryConfig &aConfig, const QueryConfig *aRequestConfig) const;
818     void  RecordServerAsLimitedToSingleQuestion(const Ip6::Address &aServerAddress);
819     void  RecordServerAsCapableOfMultiQuestions(const Ip6::Address &aServerAddress);
820     Error ReplaceWithSeparateSrvTxtQueries(Query &aQuery);
821     void  ResolveHostAddressIfNeeded(Query &aQuery, const Message &aResponseMessage);
822 #endif
823 
824 #if OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE
825     void UpdateDefaultConfigAddress(void);
826 #endif
827 
828 #if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE
829     static void HandleTcpEstablishedCallback(otTcpEndpoint *aEndpoint);
830     static void HandleTcpSendDoneCallback(otTcpEndpoint *aEndpoint, otLinkedBuffer *aData);
831     static void HandleTcpDisconnectedCallback(otTcpEndpoint *aEndpoint, otTcpDisconnectedReason aReason);
832     static void HandleTcpReceiveAvailableCallback(otTcpEndpoint *aEndpoint,
833                                                   size_t         aBytesAvailable,
834                                                   bool           aEndOfStream,
835                                                   size_t         aBytesRemaining);
836 
837     void  HandleTcpEstablished(otTcpEndpoint *aEndpoint);
838     void  HandleTcpSendDone(otTcpEndpoint *aEndpoint, otLinkedBuffer *aData);
839     void  HandleTcpDisconnected(otTcpEndpoint *aEndpoint, otTcpDisconnectedReason aReason);
840     void  HandleTcpReceiveAvailable(otTcpEndpoint *aEndpoint,
841                                     size_t         aBytesAvailable,
842                                     bool           aEndOfStream,
843                                     size_t         aBytesRemaining);
844     Error InitTcpSocket(void);
845     Error ReadFromLinkBuffer(const otLinkedBuffer *&aLinkedBuffer,
846                              size_t                &aOffset,
847                              Message               &aMessage,
848                              uint16_t               aLength);
849     void  PrepareTcpMessage(Message &aMessage);
850 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE
851 
852     static const uint8_t         kQuestionCount[];
853     static const uint16_t *const kQuestionRecordTypes[];
854 
855     static const uint16_t kIp6AddressQueryRecordTypes[];
856 #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
857     static const uint16_t kIp4AddressQueryRecordTypes[];
858 #endif
859 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
860     static const uint16_t kBrowseQueryRecordTypes[];
861     static const uint16_t kServiceQueryRecordTypes[];
862 #endif
863 
864     static constexpr uint16_t kUdpQueryMaxSize = 512;
865 
866     using RetryTimer   = TimerMilliIn<Client, &Client::HandleTimer>;
867     using ClientSocket = Ip6::Udp::SocketIn<Client, &Client::HandleUdpReceive>;
868 
869     ClientSocket mSocket;
870 
871 #if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE
872     Ip6::Tcp::Endpoint mEndpoint;
873 
874     otLinkedBuffer mSendLink;
875     uint8_t        mSendBufferBytes[OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_QUERY_MAX_SIZE];
876     uint8_t        mReceiveBufferBytes[OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_QUERY_MAX_SIZE];
877 
878     TcpState mTcpState;
879 #endif
880 
881     QueryList   mMainQueries;
882     RetryTimer  mTimer;
883     QueryConfig mDefaultConfig;
884 #if OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_SERVER_ADDRESS_AUTO_SET_ENABLE
885     bool mUserDidSetDefaultAddress;
886 #endif
887     Array<Ip6::Address, kLimitedQueryServersArraySize> mLimitedQueryServers;
888 };
889 
890 } // namespace Dns
891 
892 DefineCoreType(otDnsQueryConfig, Dns::Client::QueryConfig);
893 DefineCoreType(otDnsAddressResponse, Dns::Client::AddressResponse);
894 #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
895 DefineCoreType(otDnsBrowseResponse, Dns::Client::BrowseResponse);
896 DefineCoreType(otDnsServiceResponse, Dns::Client::ServiceResponse);
897 DefineCoreType(otDnsServiceInfo, Dns::Client::ServiceInfo);
898 #endif
899 
900 } // namespace ot
901 
902 #endif // OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
903 
904 #endif // DNS_CLIENT_HPP_
905