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