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