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