1 /* 2 * Copyright (c) 2017, 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 /** 30 * @file 31 * This file includes definitions for generating and processing DNS headers. 32 */ 33 34 #ifndef DNS_HEADER_HPP_ 35 #define DNS_HEADER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include <openthread/dns.h> 40 #include <openthread/dns_client.h> 41 42 #include "common/appender.hpp" 43 #include "common/as_core_type.hpp" 44 #include "common/clearable.hpp" 45 #include "common/encoding.hpp" 46 #include "common/equatable.hpp" 47 #include "common/message.hpp" 48 #include "crypto/ecdsa.hpp" 49 #include "net/ip4_types.hpp" 50 #include "net/ip6_address.hpp" 51 52 namespace ot { 53 54 /** 55 * @namespace ot::Dns 56 * @brief 57 * This namespace includes definitions for DNS. 58 * 59 */ 60 namespace Dns { 61 62 /** 63 * @addtogroup core-dns 64 * 65 * @brief 66 * This module includes definitions for DNS. 67 * 68 * @{ 69 * 70 */ 71 72 /** 73 * Implements DNS header generation and parsing. 74 * 75 */ 76 OT_TOOL_PACKED_BEGIN 77 class Header : public Clearable<Header> 78 { 79 public: 80 /** 81 * Default constructor for DNS Header. 82 * 83 */ Header(void)84 Header(void) { Clear(); } 85 86 /** 87 * Returns the Message ID. 88 * 89 * @returns The Message ID value. 90 * 91 */ GetMessageId(void) const92 uint16_t GetMessageId(void) const { return BigEndian::HostSwap16(mMessageId); } 93 94 /** 95 * Sets the Message ID. 96 * 97 * @param[in] aMessageId The Message ID value. 98 * 99 */ SetMessageId(uint16_t aMessageId)100 void SetMessageId(uint16_t aMessageId) { mMessageId = BigEndian::HostSwap16(aMessageId); } 101 102 /** 103 * Sets the Message ID to a crypto-secure randomly generated number. 104 * 105 * @retval kErrorNone Successfully generated random Message ID. 106 * @retval kErrorFailed Could not generate random Message ID. 107 * 108 */ 109 Error SetRandomMessageId(void); 110 111 /** 112 * Defines types of DNS message. 113 * 114 */ 115 enum Type : uint8_t 116 { 117 kTypeQuery = 0, 118 kTypeResponse = 1, 119 }; 120 121 /** 122 * Returns the type of the message. 123 * 124 * @returns The type of the message. 125 * 126 */ GetType(void) const127 Type GetType(void) const { return static_cast<Type>((mFlags[0] & kQrFlagMask) >> kQrFlagOffset); } 128 129 /** 130 * Sets the type of the message. 131 * 132 * @param[in] aType The type of the message. 133 * 134 */ SetType(Type aType)135 void SetType(Type aType) 136 { 137 mFlags[0] &= ~kQrFlagMask; 138 mFlags[0] |= static_cast<uint8_t>(aType) << kQrFlagOffset; 139 } 140 141 /** 142 * Defines types of query. 143 * 144 */ 145 enum QueryType : uint8_t 146 { 147 kQueryTypeStandard = 0, 148 kQueryTypeInverse = 1, 149 kQueryTypeStatus = 2, 150 kQueryTypeNotify = 4, 151 kQueryTypeUpdate = 5, 152 kQueryTypeDso = 6, 153 }; 154 155 /** 156 * Returns the type of the query. 157 * 158 * @returns The type of the query. 159 * 160 */ GetQueryType(void) const161 QueryType GetQueryType(void) const { return static_cast<QueryType>((mFlags[0] & kOpCodeMask) >> kOpCodeOffset); } 162 163 /** 164 * Sets the type of the query. 165 * 166 * @param[in] aType The type of the query. 167 * 168 */ SetQueryType(QueryType aType)169 void SetQueryType(QueryType aType) 170 { 171 mFlags[0] &= ~kOpCodeMask; 172 mFlags[0] |= static_cast<uint8_t>(aType) << kOpCodeOffset; 173 } 174 175 /** 176 * Specifies in response message if the responding name server is an 177 * authority for the domain name in question section. 178 * 179 * @returns True if Authoritative Answer flag (AA) is set in the header, false otherwise. 180 * 181 */ IsAuthoritativeAnswerFlagSet(void) const182 bool IsAuthoritativeAnswerFlagSet(void) const { return (mFlags[0] & kAaFlagMask) == kAaFlagMask; } 183 184 /** 185 * Clears the Authoritative Answer flag (AA) in the header. 186 * 187 */ ClearAuthoritativeAnswerFlag(void)188 void ClearAuthoritativeAnswerFlag(void) { mFlags[0] &= ~kAaFlagMask; } 189 190 /** 191 * Sets the Authoritative Answer flag (AA) in the header. 192 * 193 */ SetAuthoritativeAnswerFlag(void)194 void SetAuthoritativeAnswerFlag(void) { mFlags[0] |= kAaFlagMask; } 195 196 /** 197 * Specifies if message is truncated. 198 * 199 * @returns True if Truncation flag (TC) is set in the header, false otherwise. 200 * 201 */ IsTruncationFlagSet(void) const202 bool IsTruncationFlagSet(void) const { return (mFlags[0] & kTcFlagMask) == kTcFlagMask; } 203 204 /** 205 * Clears the Truncation flag (TC) in the header. 206 * 207 */ ClearTruncationFlag(void)208 void ClearTruncationFlag(void) { mFlags[0] &= ~kTcFlagMask; } 209 210 /** 211 * Sets the Truncation flag (TC) in the header. 212 * 213 */ SetTruncationFlag(void)214 void SetTruncationFlag(void) { mFlags[0] |= kTcFlagMask; } 215 216 /** 217 * Specifies if resolver wants to direct the name server to pursue 218 * the query recursively. 219 * 220 * @returns True if Recursion Desired flag (RD) is set in the header, false otherwise. 221 * 222 */ IsRecursionDesiredFlagSet(void) const223 bool IsRecursionDesiredFlagSet(void) const { return (mFlags[0] & kRdFlagMask) == kRdFlagMask; } 224 225 /** 226 * Clears the Recursion Desired flag (RD) in the header. 227 * 228 */ ClearRecursionDesiredFlag(void)229 void ClearRecursionDesiredFlag(void) { mFlags[0] &= ~kRdFlagMask; } 230 231 /** 232 * Sets the Recursion Desired flag (RD) in the header. 233 * 234 */ SetRecursionDesiredFlag(void)235 void SetRecursionDesiredFlag(void) { mFlags[0] |= kRdFlagMask; } 236 237 /** 238 * Denotes whether recursive query support is available in the name server. 239 * 240 * @returns True if Recursion Available flag (RA) is set in the header, false otherwise. 241 * 242 */ IsRecursionAvailableFlagSet(void) const243 bool IsRecursionAvailableFlagSet(void) const { return (mFlags[1] & kRaFlagMask) == kRaFlagMask; } 244 245 /** 246 * Clears the Recursion Available flag (RA) in the header. 247 * 248 */ ClearRecursionAvailableFlag(void)249 void ClearRecursionAvailableFlag(void) { mFlags[1] &= ~kRaFlagMask; } 250 251 /** 252 * Sets the Recursion Available flag (RA) in the header. 253 * 254 */ SetRecursionAvailableFlag(void)255 void SetRecursionAvailableFlag(void) { mFlags[1] |= kRaFlagMask; } 256 257 /** 258 * Defines response codes. 259 * 260 */ 261 enum Response : uint8_t 262 { 263 kResponseSuccess = 0, ///< Success (no error condition). 264 kResponseFormatError = 1, ///< Server unable to interpret request due to format error. 265 kResponseServerFailure = 2, ///< Server encountered an internal failure. 266 kResponseNameError = 3, ///< Name that ought to exist, does not exists. 267 kResponseNotImplemented = 4, ///< Server does not support the query type (OpCode). 268 kResponseRefused = 5, ///< Server refused to perform operation for policy or security reasons. 269 kResponseNameExists = 6, ///< Some name that ought not to exist, does exist. 270 kResponseRecordExists = 7, ///< Some RRset that ought not to exist, does exist. 271 kResponseRecordNotExists = 8, ///< Some RRset that ought to exist, does not exist. 272 kResponseNotAuth = 9, ///< Service is not authoritative for zone. 273 kResponseNotZone = 10, ///< A name is not in the zone. 274 kDsoTypeNotImplemented = 11, ///< DSO TLV TYPE is not implemented. 275 kResponseBadName = 20, ///< Bad name. 276 kResponseBadAlg = 21, ///< Bad algorithm. 277 kResponseBadTruncation = 22, ///< Bad truncation. 278 }; 279 280 /** 281 * Returns the response code. 282 * 283 * @returns The response code from the header. 284 * 285 */ GetResponseCode(void) const286 Response GetResponseCode(void) const { return static_cast<Response>((mFlags[1] & kRCodeMask) >> kRCodeOffset); } 287 288 /** 289 * Sets the response code. 290 * 291 * @param[in] aResponse The type of the response. 292 * 293 */ SetResponseCode(Response aResponse)294 void SetResponseCode(Response aResponse) 295 { 296 mFlags[1] &= ~kRCodeMask; 297 mFlags[1] |= static_cast<uint8_t>(aResponse) << kRCodeOffset; 298 } 299 300 /** 301 * Converts a Response Code into a related `Error`. 302 * 303 * - kResponseSuccess (0) : Success (no error condition) -> kErrorNone 304 * - kResponseFormatError (1) : Server unable to interpret due to format error -> kErrorParse 305 * - kResponseServerFailure (2) : Server encountered an internal failure -> kErrorFailed 306 * - kResponseNameError (3) : Name that ought to exist, does not exists -> kErrorNotFound 307 * - kResponseNotImplemented (4) : Server does not support the query type (OpCode) -> kErrorNotImplemented 308 * - kResponseRefused (5) : Server refused for policy/security reasons -> kErrorSecurity 309 * - kResponseNameExists (6) : Some name that ought not to exist, does exist -> kErrorDuplicated 310 * - kResponseRecordExists (7) : Some RRset that ought not to exist, does exist -> kErrorDuplicated 311 * - kResponseRecordNotExists (8) : Some RRset that ought to exist, does not exist -> kErrorNotFound 312 * - kResponseNotAuth (9) : Service is not authoritative for zone -> kErrorSecurity 313 * - kResponseNotZone (10) : A name is not in the zone -> kErrorParse 314 * - kDsoTypeNotImplemented (11) : DSO TLV Type is not implemented -> kErrorNotImplemented 315 * - kResponseBadName (20) : Bad name -> kErrorParse 316 * - kResponseBadAlg (21) : Bad algorithm -> kErrorSecurity 317 * - kResponseBadTruncation (22) : Bad truncation -> kErrorParse 318 * - Other error -> kErrorFailed 319 * 320 * @param[in] aResponse The response code to convert. 321 * 322 */ 323 static Error ResponseCodeToError(Response aResponse); 324 325 /** 326 * Returns the number of entries in question section. 327 * 328 * @returns The number of entries in question section. 329 * 330 */ GetQuestionCount(void) const331 uint16_t GetQuestionCount(void) const { return BigEndian::HostSwap16(mQdCount); } 332 333 /** 334 * Sets the number of entries in question section. 335 * 336 * @param[in] aCount The number of entries in question section. 337 * 338 */ SetQuestionCount(uint16_t aCount)339 void SetQuestionCount(uint16_t aCount) { mQdCount = BigEndian::HostSwap16(aCount); } 340 341 /** 342 * Returns the number of entries in answer section. 343 * 344 * @returns The number of entries in answer section. 345 * 346 */ GetAnswerCount(void) const347 uint16_t GetAnswerCount(void) const { return BigEndian::HostSwap16(mAnCount); } 348 349 /** 350 * Sets the number of entries in answer section. 351 * 352 * @param[in] aCount The number of entries in answer section. 353 * 354 */ SetAnswerCount(uint16_t aCount)355 void SetAnswerCount(uint16_t aCount) { mAnCount = BigEndian::HostSwap16(aCount); } 356 357 /** 358 * Returns the number of entries in authority records section. 359 * 360 * @returns The number of entries in authority records section. 361 * 362 */ GetAuthorityRecordCount(void) const363 uint16_t GetAuthorityRecordCount(void) const { return BigEndian::HostSwap16(mNsCount); } 364 365 /** 366 * Sets the number of entries in authority records section. 367 * 368 * @param[in] aCount The number of entries in authority records section. 369 * 370 */ SetAuthorityRecordCount(uint16_t aCount)371 void SetAuthorityRecordCount(uint16_t aCount) { mNsCount = BigEndian::HostSwap16(aCount); } 372 373 /** 374 * Returns the number of entries in additional records section. 375 * 376 * @returns The number of entries in additional records section. 377 * 378 */ GetAdditionalRecordCount(void) const379 uint16_t GetAdditionalRecordCount(void) const { return BigEndian::HostSwap16(mArCount); } 380 381 /** 382 * Sets the number of entries in additional records section. 383 * 384 * @param[in] aCount The number of entries in additional records section. 385 * 386 */ SetAdditionalRecordCount(uint16_t aCount)387 void SetAdditionalRecordCount(uint16_t aCount) { mArCount = BigEndian::HostSwap16(aCount); } 388 389 private: 390 // Protocol Constants (RFC 1035). 391 static constexpr uint8_t kQrFlagOffset = 7; // QR Flag offset. 392 static constexpr uint8_t kQrFlagMask = 0x01 << kQrFlagOffset; // QR Flag mask. 393 static constexpr uint8_t kOpCodeOffset = 3; // OpCode field offset. 394 static constexpr uint8_t kOpCodeMask = 0x0f << kOpCodeOffset; // OpCode field mask. 395 static constexpr uint8_t kAaFlagOffset = 2; // AA Flag offset. 396 static constexpr uint8_t kAaFlagMask = 0x01 << kAaFlagOffset; // AA Flag mask. 397 static constexpr uint8_t kTcFlagOffset = 1; // TC Flag offset. 398 static constexpr uint8_t kTcFlagMask = 0x01 << kTcFlagOffset; // TC Flag mask. 399 static constexpr uint8_t kRdFlagOffset = 0; // RD Flag offset. 400 static constexpr uint8_t kRdFlagMask = 0x01 << kRdFlagOffset; // RD Flag mask. 401 static constexpr uint8_t kRaFlagOffset = 7; // RA Flag offset. 402 static constexpr uint8_t kRaFlagMask = 0x01 << kRaFlagOffset; // RA Flag mask. 403 static constexpr uint8_t kRCodeOffset = 0; // RCODE field offset. 404 static constexpr uint8_t kRCodeMask = 0x0f << kRCodeOffset; // RCODE field mask. 405 406 uint16_t mMessageId; // Message identifier for requester to match up replies to outstanding queries. 407 uint8_t mFlags[2]; // DNS header flags. 408 uint16_t mQdCount; // Number of entries in the question section. 409 uint16_t mAnCount; // Number of entries in the answer section. 410 uint16_t mNsCount; // Number of entries in the authority records section. 411 uint16_t mArCount; // Number of entries in the additional records section. 412 413 } OT_TOOL_PACKED_END; 414 415 /** 416 * Implements DNS Update message header generation and parsing. 417 * 418 * The DNS header specifies record counts for its four sections: Question, Answer, Authority, and Additional. A DNS 419 * Update header uses the same fields, and the same section formats, but the naming and use of these sections differs: 420 * DNS Update header uses Zone, Prerequisite, Update, Additional Data sections. 421 * 422 */ 423 OT_TOOL_PACKED_BEGIN 424 class UpdateHeader : public Header 425 { 426 public: 427 /** 428 * Default constructor for DNS Update message header. 429 * 430 */ UpdateHeader(void)431 UpdateHeader(void) { SetQueryType(kQueryTypeUpdate); } 432 433 /** 434 * Returns the number of records in Zone section. 435 * 436 * @returns The number of records in Zone section. 437 * 438 */ GetZoneRecordCount(void) const439 uint16_t GetZoneRecordCount(void) const { return GetQuestionCount(); } 440 441 /** 442 * Sets the number of records in Zone section. 443 * 444 * @param[in] aCount The number of records in Zone section. 445 * 446 */ SetZoneRecordCount(uint16_t aCount)447 void SetZoneRecordCount(uint16_t aCount) { SetQuestionCount(aCount); } 448 449 /** 450 * Returns the number of records in Prerequisite section. 451 * 452 * @returns The number of records in Prerequisite section. 453 * 454 */ GetPrerequisiteRecordCount(void) const455 uint16_t GetPrerequisiteRecordCount(void) const { return GetAnswerCount(); } 456 457 /** 458 * Sets the number of records in Prerequisite section. 459 * 460 * @param[in] aCount The number of records in Prerequisite section. 461 * 462 */ SetPrerequisiteRecordCount(uint16_t aCount)463 void SetPrerequisiteRecordCount(uint16_t aCount) { SetAnswerCount(aCount); } 464 465 /** 466 * Returns the number of records in Update section. 467 * 468 * @returns The number of records in Update section. 469 * 470 */ GetUpdateRecordCount(void) const471 uint16_t GetUpdateRecordCount(void) const { return GetAuthorityRecordCount(); } 472 473 /** 474 * Sets the number of records in Update section. 475 * 476 * @param[in] aCount The number of records in Update section. 477 * 478 */ SetUpdateRecordCount(uint16_t aCount)479 void SetUpdateRecordCount(uint16_t aCount) { SetAuthorityRecordCount(aCount); } 480 481 } OT_TOOL_PACKED_END; 482 483 /** 484 * Represents a DNS name and implements helper methods for encoding/decoding of DNS Names. 485 * 486 */ 487 class Name : public Clearable<Name> 488 { 489 public: 490 /** 491 * Max size (number of chars) in a name string array (includes null char at the end of string). 492 * 493 */ 494 static constexpr uint8_t kMaxNameSize = OT_DNS_MAX_NAME_SIZE; 495 496 /** 497 * Maximum length in a name string (does not include null char at the end of string). 498 * 499 */ 500 static constexpr uint8_t kMaxNameLength = kMaxNameSize - 1; 501 502 /** 503 * Max size (number of chars) in a label string array (includes null char at the end of the string). 504 * 505 */ 506 static constexpr uint8_t kMaxLabelSize = OT_DNS_MAX_LABEL_SIZE; 507 508 /** 509 * Maximum length in a label string (does not include null char at the end of string). 510 * 511 */ 512 static constexpr uint8_t kMaxLabelLength = kMaxLabelSize - 1; 513 514 /** 515 * Dot character separating labels in a name. 516 * 517 */ 518 static constexpr char kLabelSeparatorChar = '.'; 519 520 /** 521 * Represents a string buffer (with `kMaxNameSize`) intended to hold a DNS name. 522 * 523 */ 524 typedef char Buffer[kMaxNameSize]; 525 526 /** 527 * Represents a string buffer (with `kMaxLabelSize`) intended to hold a DNS label. 528 * 529 */ 530 typedef char LabelBuffer[kMaxLabelSize]; 531 532 /** 533 * Represents the name type. 534 * 535 */ 536 enum Type : uint8_t 537 { 538 kTypeEmpty, ///< The name is empty (not specified). 539 kTypeCString, ///< The name is given as a C string (dot '.' separated sequence of labels). 540 kTypeMessage, ///< The name is specified from a message at a given offset (encoded in the message). 541 }; 542 543 /** 544 * Initializes the `Name` object as empty (not specified). 545 * 546 */ Name(void)547 Name(void) 548 : Name(nullptr, nullptr, 0) 549 { 550 } 551 552 /** 553 * Initializes the `Name` object with a given string. 554 * 555 * @param[in] aString A C string specifying the name (dot '.' separated sequence of labels'). 556 * 557 */ Name(const char * aString)558 explicit Name(const char *aString) 559 : Name(aString, nullptr, 0) 560 { 561 } 562 563 /** 564 * Initializes the `Name` object from a message at a given offset. 565 * 566 * @param[in] aMessage The message containing the encoded name. `aMessage.GetOffset()` MUST point to the start of 567 * the DNS header in the message (used to parse compressed name). 568 * @param[in] aOffset The offset in @p aMessage pointing to the start of the name. 569 * 570 */ Name(const Message & aMessage,uint16_t aOffset)571 Name(const Message &aMessage, uint16_t aOffset) 572 : Name(nullptr, &aMessage, aOffset) 573 { 574 } 575 576 /** 577 * Indicates whether the name is empty (not specified). 578 * 579 * @returns TRUE if the name is empty, FALSE otherwise. 580 * 581 */ IsEmpty(void) const582 bool IsEmpty(void) const { return (mString == nullptr) && (mMessage == nullptr); } 583 584 /** 585 * Indicates whether the name is specified from a C string. 586 * 587 * @returns TRUE if the name is specified from a string, FALSE otherwise. 588 * 589 */ IsFromCString(void) const590 bool IsFromCString(void) const { return mString != nullptr; } 591 592 /** 593 * Indicates whether the name is specified from a message. 594 * 595 * @returns TRUE if the name is specified from a message, FALSE otherwise. 596 * 597 */ IsFromMessage(void) const598 bool IsFromMessage(void) const { return mMessage != nullptr; } 599 600 /** 601 * Gets the type of `Name` object indicating whether it is empty, specified by a C string or from a 602 * message 603 * 604 * @returns The name type. 605 * 606 */ GetFromType(void) const607 Type GetFromType(void) const 608 { 609 return IsFromCString() ? kTypeCString : (IsFromMessage() ? kTypeMessage : kTypeEmpty); 610 } 611 612 /** 613 * Sets the name from a given C string. 614 * 615 * @param[in] aString A C string specifying the name (dot '.' separated sequence of labels). 616 * 617 */ Set(const char * aString)618 void Set(const char *aString) 619 { 620 mString = aString; 621 mMessage = nullptr; 622 } 623 624 /** 625 * Sets the name from a message at a given offset. 626 * 627 * @param[in] aMessage The message containing the encoded name. `aMessage.GetOffset()` MUST point to the start of 628 * the DNS header in the message (used to parse compressed name). 629 * @param[in] aOffset The offset in @p aMessage pointing to the start of the name. 630 * 631 */ SetFromMessage(const Message & aMessage,uint16_t aOffset)632 void SetFromMessage(const Message &aMessage, uint16_t aOffset) 633 { 634 mString = nullptr; 635 mMessage = &aMessage; 636 mOffset = aOffset; 637 } 638 639 /** 640 * Gets the name as a C string. 641 * 642 * MUST be used only when the type is `kTypeString`. Otherwise its behavior is undefined. 643 * 644 * @returns A pointer to the C string. 645 * 646 */ GetAsCString(void) const647 const char *GetAsCString(void) const { return mString; } 648 649 /** 650 * Gets the name message and offset. 651 * 652 * MUST be used only when the type is `kTypeMessage`. Otherwise its behavior is undefined. 653 * 654 * @param[out] aOffset A reference to a variable to output the offset of the start of the name in the message. 655 * 656 * @returns A reference to the message containing the name. 657 * 658 */ GetAsMessage(uint16_t & aOffset) const659 const Message &GetAsMessage(uint16_t &aOffset) const 660 { 661 aOffset = mOffset; 662 return *mMessage; 663 } 664 665 /** 666 * Matches the `Name` with a given set of labels and domain name. 667 * 668 * This method allows the caller to specify name components separately, enabling scenarios like comparing "service 669 * instance name" with separate instance label (which can include dot character), service type, and domain strings. 670 * 671 * @p aFirstLabel can be `nullptr` if not needed. But if non-null, it is treated as a single label and can itself 672 * include dot `.` character. 673 * 674 * The @p aLabels MUST NOT be `nullptr` and MUST follow "<label1>.<label2>.<label3>", i.e., a sequence of one or 675 * more labels separated by dot '.' char, and it MUST NOT end with dot `.`. 676 * 677 * @p aDomain MUST NOT be `nullptr` and MUST have at least one label and MUST always end with a dot `.` character. 678 * 679 * If the above conditions are not satisfied, the behavior of this method is undefined. 680 * 681 * @param[in] aFirstLabel A first label to check. Can be `nullptr`. 682 * @param[in] aLabels A string of dot separated labels, MUST NOT end with dot. 683 * @param[in] aDomain Domain name. MUST end with dot. 684 * 685 * @retval TRUE The name matches the given components. 686 * @retval FALSE The name does not match the given components. 687 * 688 */ 689 bool Matches(const char *aFirstLabel, const char *aLabels, const char *aDomain) const; 690 691 /** 692 * Encodes and appends the name to a message. 693 * 694 * If the name is empty (not specified), then root "." is appended to @p aMessage. If the name is from a C string 695 * then the string is checked and appended (similar to static `AppendName(const char *aName, Message &)` method). 696 * If the the name is from a message, then it is read from the message and appended to @p aMessage. Note that in 697 * this case independent of whether the name is compressed or not in its original message, the name is appended 698 * as full (uncompressed) in @p aMessage. 699 * 700 * @param[in] aMessage The message to append to. 701 * 702 * @retval kErrorNone Successfully encoded and appended the name to @p aMessage. 703 * @retval kErrorInvalidArgs Name is not valid. 704 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 705 * 706 */ 707 Error AppendTo(Message &aMessage) const; 708 709 /** 710 * Encodes and appends a single name label to a message. 711 * 712 * The @p aLabel is assumed to contain a single name label as a C string (null-terminated). Unlike 713 * `AppendMultipleLabels()` which parses the label string and treats it as sequence of multiple (dot-separated) 714 * labels, this method always appends @p aLabel as a single whole label. This allows the label string to even 715 * contain dot '.' character, which, for example, is useful for "Service Instance Names" where <Instance> portion 716 * is a user-friendly name and can contain dot characters. 717 * 718 * @param[in] aLabel The label string to append. MUST NOT be `nullptr`. 719 * @param[in] aMessage The message to append to. 720 * 721 * @retval kErrorNone Successfully encoded and appended the name label to @p aMessage. 722 * @retval kErrorInvalidArgs @p aLabel is not valid (e.g., label length is not within valid range). 723 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 724 * 725 */ 726 static Error AppendLabel(const char *aLabel, Message &aMessage); 727 728 /** 729 * Encodes and appends a sequence of name labels to a given message. 730 * 731 * The @p aLabels must follow "<label1>.<label2>.<label3>", i.e., a sequence of labels separated by dot '.' char. 732 * E.g., "_http._tcp", "_http._tcp." (same as previous one), "host-1.test". 733 * 734 * Validates that the @p aLabels is a valid name format, i.e., no empty label, and labels are 735 * `kMaxLabelLength` (63) characters or less. 736 * 737 * @note This method NEVER adds a label terminator (empty label) to the message, even in the case where @p aLabels 738 * ends with a dot character, e.g., "host-1.test." is treated same as "host-1.test". 739 * 740 * @param[in] aLabels A name label string. Can be `nullptr` (then treated as ""). 741 * @param[in] aMessage The message to which to append the encoded name. 742 * 743 * @retval kErrorNone Successfully encoded and appended the name label(s) to @p aMessage. 744 * @retval kErrorInvalidArgs Name label @p aLabels is not valid. 745 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 746 * 747 */ 748 static Error AppendMultipleLabels(const char *aLabels, Message &aMessage); 749 750 /** 751 * Appends a name label terminator to a message. 752 * 753 * An encoded name is terminated by an empty label (a zero byte). 754 * 755 * @param[in] aMessage The message to append to. 756 * 757 * @retval kErrorNone Successfully encoded and appended the terminator label to @p aMessage. 758 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 759 * 760 */ 761 static Error AppendTerminator(Message &aMessage); 762 763 /** 764 * Appends a pointer type name label to a message. 765 * 766 * Pointer label is used for name compression. It allows an entire name or a list of labels at the end of an 767 * encoded name to be replaced with a pointer to a prior occurrence of the same name within the message. 768 * 769 * @param[in] aOffset The offset from the start of DNS header to use for pointer value. 770 * @param[in] aMessage The message to append to. 771 * 772 * @retval kErrorNone Successfully encoded and appended the pointer label to @p aMessage. 773 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 774 * 775 */ 776 static Error AppendPointerLabel(uint16_t aOffset, Message &aMessage); 777 778 /** 779 * Encodes and appends a full name to a message. 780 * 781 * The @p aName must follow "<label1>.<label2>.<label3>", i.e., a sequence of labels separated by dot '.' char. 782 * E.g., "example.com", "example.com." (same as previous one), "local.", "default.service.arpa", "." or "" (root). 783 * 784 * Validates that the @p aName is a valid name format, i.e. no empty labels, and labels are 785 * `kMaxLabelLength` (63) characters or less, and the name is `kMaxLength` (255) characters or less. 786 * 787 * @param[in] aName A name string. Can be `nullptr` (then treated as "." or root). 788 * @param[in] aMessage The message to append to. 789 * 790 * @retval kErrorNone Successfully encoded and appended the name to @p aMessage. 791 * @retval kErrorInvalidArgs Name @p aName is not valid. 792 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 793 * 794 */ 795 static Error AppendName(const char *aName, Message &aMessage); 796 797 /** 798 * Parses and skips over a full name in a message. 799 * 800 * @param[in] aMessage The message to parse the name from. `aMessage.GetOffset()` MUST point to 801 * the start of DNS header (this is used to handle compressed names). 802 * @param[in,out] aOffset On input the offset in @p aMessage pointing to the start of the name field. 803 * On exit (when parsed successfully), @p aOffset is updated to point to the byte 804 * after the end of name field. 805 * 806 * @retval kErrorNone Successfully parsed and skipped over name, @p Offset is updated. 807 * @retval kErrorParse Name could not be parsed (invalid format). 808 * 809 */ 810 static Error ParseName(const Message &aMessage, uint16_t &aOffset); 811 812 /** 813 * Reads a name label from a message. 814 * 815 * Can be used to read labels one by one in a name. After a successful label read, @p aOffset is 816 * updated to point to the start of the next label. When we reach the end of the name, kErrorNotFound is 817 * returned. This method handles compressed names which use pointer labels. So as the labels in a name are read, 818 * the @p aOffset may jump back in the message and at the end the @p aOffset does not necessarily point to the end 819 * of the original name field. 820 * 821 * Unlike `ReadName()` which requires and verifies that the read label to contain no dot '.' character, this method 822 * allows the read label to include any character. 823 * 824 * @param[in] aMessage The message to read the label from. `aMessage.GetOffset()` MUST point to 825 * the start of DNS header (this is used to handle compressed names). 826 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the label to read. 827 * On exit, when successfully read, @p aOffset is updated to point to the start of 828 * the next label. 829 * @param[out] aLabelBuffer A pointer to a char array to output the read label as a null-terminated C string. 830 * @param[in,out] aLabelLength On input, the maximum number chars in @p aLabelBuffer array. 831 * On output, when label is successfully read, @p aLabelLength is updated to return 832 * the label's length (number of chars in the label string, excluding the null char). 833 * 834 * @retval kErrorNone Successfully read the label and updated @p aLabelBuffer, @p aLabelLength, and @p aOffset. 835 * @retval kErrorNotFound Reached the end of name and no more label to read. 836 * @retval kErrorParse Name could not be parsed (invalid format). 837 * @retval kErrorNoBufs Label could not fit in @p aLabelLength chars. 838 * 839 */ 840 static Error ReadLabel(const Message &aMessage, uint16_t &aOffset, char *aLabelBuffer, uint8_t &aLabelLength); 841 842 /** 843 * Reads a full name from a message. 844 * 845 * On successful read, the read name follows "<label1>.<label2>.<label3>.", i.e., a sequence of labels separated by 846 * dot '.' character. The read name will ALWAYS end with a dot. 847 * 848 * Verifies that the labels after the first label in message do not contain any dot character. If they do, 849 * returns `kErrorParse`. 850 * 851 * @param[in] aMessage The message to read the name from. `aMessage.GetOffset()` MUST point to 852 * the start of DNS header (this is used to handle compressed names). 853 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the name field. 854 * On exit (when parsed successfully), @p aOffset is updated to point to the byte 855 * after the end of name field. 856 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string. 857 * @param[in,out] aNameBufferSize The maximum number of chars in @p aNameBuffer array. 858 * 859 * @retval kErrorNone Successfully read the name, @p aNameBuffer and @p Offset are updated. 860 * @retval kErrorParse Name could not be parsed (invalid format). 861 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 862 * 863 */ 864 static Error ReadName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize); 865 866 /** 867 * Reads a full name from a message. 868 * 869 * On successful read, the read name follows "<label1>.<label2>.<label3>.", i.e., a sequence of labels separated by 870 * dot '.' character. The read name will ALWAYS end with a dot. 871 * 872 * Verifies that the labels after the first label in message do not contain any dot character. If they do, 873 * returns `kErrorParse`. 874 * 875 * @tparam kNameBufferSize Size of the string buffer array. 876 * 877 * @param[in] aMessage The message to read the name from. `aMessage.GetOffset()` MUST point to 878 * the start of DNS header (this is used to handle compressed names). 879 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the name field. 880 * On exit (when parsed successfully), @p aOffset is updated to point to the byte 881 * after the end of name field. 882 * @param[out] aNameBuffer Reference to a name string buffer to output the read name. 883 * 884 * @retval kErrorNone Successfully read the name, @p aNameBuffer and @p Offset are updated. 885 * @retval kErrorParse Name could not be parsed (invalid format). 886 * @retval kErrorNoBufs Name could not fit in @p aNameBuffer. 887 * 888 */ 889 template <uint16_t kNameBufferSize> ReadName(const Message & aMessage,uint16_t & aOffset,char (& aNameBuffer)[kNameBufferSize])890 static Error ReadName(const Message &aMessage, uint16_t &aOffset, char (&aNameBuffer)[kNameBufferSize]) 891 { 892 return ReadName(aMessage, aOffset, aNameBuffer, kNameBufferSize); 893 } 894 895 /** 896 * Compares a single name label from a message with a given label string. 897 * 898 * Can be used to compare labels one by one. It checks whether the label read from @p aMessage matches 899 * @p aLabel string (case-insensitive comparison). 900 * 901 * Unlike `CompareName()` which requires the labels in the the name string to contain no dot '.' character, this 902 * method allows @p aLabel to include any character. 903 * 904 * @param[in] aMessage The message to read the label from to compare. `aMessage.GetOffset()` MUST point 905 * to the start of DNS header (this is used to handle compressed names). 906 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the label to read. 907 * On exit and only when label is successfully read and does match @p aLabel, 908 * @p aOffset is updated to point to the start of the next label. 909 * @param[in] aLabel A pointer to a null terminated string containing the label to compare with. 910 * 911 * @retval kErrorNone The label from @p aMessage matches @p aLabel. @p aOffset is updated. 912 * @retval kErrorNotFound The label from @p aMessage does not match @p aLabel (note that @p aOffset is not 913 * updated in this case). 914 * @retval kErrorParse Name could not be parsed (invalid format). 915 * 916 */ 917 static Error CompareLabel(const Message &aMessage, uint16_t &aOffset, const char *aLabel); 918 919 /** 920 * Parses and compares multiple name labels from a message. 921 * 922 * Can be used to read and compare a group of labels from an encoded DNS name in a message with possibly more 923 * labels remaining to read. 924 * 925 * The @p aLabels must follow "<label1>.<label2>.<label3>", i.e., a sequence of labels separated by dot '.' char. 926 * 927 * @param[in] aMessage The message to read the labels from to compare. `aMessage.GetOffset()` MUST point 928 * to the start of DNS header (this is used to handle compressed names). 929 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the labels to read. 930 * On exit and only when all labels are successfully read and match @p aLabels, 931 * @p aOffset is updated to point to the start of the next label. 932 * @param[in] aLabels A pointer to a null terminated string containing the labels to compare with. 933 * 934 * @retval kErrorNone The labels from @p aMessage matches @p aLabels. @p aOffset is updated. 935 * @retval kErrorNotFound The labels from @p aMessage does not match @p aLabel (note that @p aOffset is not 936 * updated in this case). 937 * @retval kErrorParse Name could not be parsed (invalid format). 938 * 939 */ 940 static Error CompareMultipleLabels(const Message &aMessage, uint16_t &aOffset, const char *aLabels); 941 942 /** 943 * Parses and compares a full name from a message with a given name. 944 * 945 * Checks whether the encoded name in a message matches a given name string (using case-insensitive 946 * comparison). It checks the name in the message in place and handles compressed names. If the name read from the 947 * message does not match @p aName, it returns `kErrorNotFound`. `kErrorNone` indicates that the name matches 948 * @p aName. 949 * 950 * The @p aName must follow "<label1>.<label2>.<label3>", i.e., a sequence of labels separated by dot '.' char. 951 * E.g., "example.com", "example.com." (same as previous one), "local.", "default.service.arpa", "." or "" (root). 952 * 953 * @param[in] aMessage The message to read the name from and compare with @p aName. 954 * `aMessage.GetOffset()` MUST point to the start of DNS header (this is used to 955 * handle compressed names). 956 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the name field. 957 * On exit (when parsed successfully independent of whether the read name matches 958 * @p aName or not), @p aOffset is updated to point to the byte after the end of 959 * the name field. 960 * @param[in] aName A pointer to a null terminated string containing the name to compare with. 961 * 962 * @retval kErrorNone The name from @p aMessage matches @p aName. @p aOffset is updated. 963 * @retval kErrorNotFound The name from @p aMessage does not match @p aName. @p aOffset is updated. 964 * @retval kErrorParse Name could not be parsed (invalid format). 965 * @retval kErrorInvalidArgs The @p aName is not a valid name (e.g. back to back "." chars) 966 * 967 */ 968 static Error CompareName(const Message &aMessage, uint16_t &aOffset, const char *aName); 969 970 /** 971 * Parses and compares a full name from a message with a name from another message. 972 * 973 * Checks whether the encoded name in @p aMessage matches the name from @p aMessage2 (using 974 * case-insensitive comparison). It compares the names in both messages in place and handles compressed names. Note 975 * that this method works correctly even when the same message instance is used for both @p aMessage and 976 * @p aMessage2 (e.g., at different offsets). 977 * 978 * Only the name in @p aMessage is fully parsed and checked for parse errors. This method assumes that the name in 979 * @p aMessage2 was previously parsed and validated before calling this method (if there is a parse error in 980 * @p aMessage2, it is treated as a name mismatch with @p aMessage). 981 * 982 * If the name in @p aMessage can be parsed fully (independent of whether the name matches or not with the name 983 * from @p aMessage2), the @p aOffset is updated (note that @p aOffset2 for @p aMessage2 is not changed). 984 * 985 * @param[in] aMessage The message to read the name from and compare. `aMessage.GetOffset()` MUST point 986 * to the start of DNS header (this is used to handle compressed names). 987 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the name field. 988 * On exit (when parsed successfully independent of whether the read name matches 989 * or not), @p aOffset is updated to point to the byte after the end of the name 990 * field. 991 * @param[in] aMessage2 The second message to read the name from and compare with name from @p aMessage. 992 * `aMessage2.GetOffset()` MUST point to the start of DNS header. 993 * @param[in] aOffset2 The offset in @p aMessage2 pointing to the start of the name field. 994 * 995 * @retval kErrorNone The name from @p aMessage matches the name from @p aMessage2. @p aOffset is updated. 996 * @retval kErrorNotFound The name from @p aMessage does not match the name from @p aMessage2. @p aOffset is 997 * updated. 998 * @retval kErrorParse Name in @p aMessage could not be parsed (invalid format). 999 * 1000 */ 1001 static Error CompareName(const Message &aMessage, uint16_t &aOffset, const Message &aMessage2, uint16_t aOffset2); 1002 1003 /** 1004 * Parses and compares a full name from a message with a given name (using case-insensitive 1005 * comparison). 1006 * 1007 * If @p aName is empty (not specified), then any name in @p aMessage is considered a match to it. 1008 * 1009 * @param[in] aMessage The message to read the name from and compare. `aMessage.GetOffset()` MUST point 1010 * to the start of DNS header (this is used to handle compressed names). 1011 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the name field. 1012 * On exit (when parsed successfully independent of whether the read name matches 1013 * or not), @p aOffset is updated to point to the byte after the end of the name 1014 * field. 1015 * @param[in] aName A reference to a name to compare with. 1016 * 1017 * @retval kErrorNone The name from @p aMessage matches @p aName. @p aOffset is updated. 1018 * @retval kErrorNotFound The name from @p aMessage does not match @p aName. @p aOffset is updated. 1019 * @retval kErrorParse Name in @p aMessage could not be parsed (invalid format). 1020 * 1021 */ 1022 static Error CompareName(const Message &aMessage, uint16_t &aOffset, const Name &aName); 1023 1024 /** 1025 * Extracts label(s) from a name by checking that it contains a given suffix name (e.g., suffix name can be 1026 * a domain name) and removing it. 1027 * 1028 * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise 1029 * `kErrorParse` is returned. 1030 * 1031 * @param[in] aName The name to extract labels from. 1032 * @param[in] aSuffixName The suffix name (e.g., can be domain name). 1033 * @param[out] aLabels Pointer to buffer to copy the extracted labels. 1034 * @param[in] aLabelsSize Size of @p aLabels buffer. 1035 * 1036 * @retval kErrorNone Successfully extracted the labels, @p aLabels is updated. 1037 * @retval kErrorParse @p aName does not contain @p aSuffixName. 1038 * @retval kErrorNoBufs Could not fit the labels in @p aLabelsSize. 1039 * 1040 */ 1041 static Error ExtractLabels(const char *aName, const char *aSuffixName, char *aLabels, uint16_t aLabelsSize); 1042 1043 /** 1044 * Extracts label(s) from a name by checking that it contains a given suffix name (e.g., suffix name can be 1045 * a domain name) and removing it. 1046 * 1047 * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise 1048 * `kErrorParse` is returned. 1049 * 1050 * @tparam kLabelsBufferSize Size of the buffer string. 1051 * 1052 * @param[in] aName The name to extract labels from. 1053 * @param[in] aSuffixName The suffix name (e.g., can be domain name). 1054 * @param[out] aLabelsBuffer A buffer to copy the extracted labels. 1055 * 1056 * @retval kErrorNone Successfully extracted the labels, @p aLabels is updated. 1057 * @retval kErrorParse @p aName does not contain @p aSuffixName. 1058 * @retval kErrorNoBufs Could not fit the labels in @p aLabels. 1059 * 1060 */ 1061 template <uint16_t kLabelsBufferSize> ExtractLabels(const char * aName,const char * aSuffixName,char (& aLabels)[kLabelsBufferSize])1062 static Error ExtractLabels(const char *aName, const char *aSuffixName, char (&aLabels)[kLabelsBufferSize]) 1063 { 1064 return ExtractLabels(aName, aSuffixName, aLabels, kLabelsBufferSize); 1065 } 1066 1067 /** 1068 * Tests if a DNS name is a sub-domain of a given domain. 1069 * 1070 * Both @p aName and @p aDomain can end without dot ('.'). 1071 * 1072 * @param[in] aName The dot-separated name. 1073 * @param[in] aDomain The dot-separated domain. 1074 * 1075 * @returns TRUE if the name is a sub-domain of @p aDomain, FALSE if is not. 1076 * 1077 */ 1078 static bool IsSubDomainOf(const char *aName, const char *aDomain); 1079 1080 /** 1081 * Tests if the two DNS name are the same domain. 1082 * 1083 * Both @p aDomain1 and @p aDomain2 can end without dot ('.'). 1084 * 1085 * @param[in] aDomain1 The dot-separated name. 1086 * @param[in] aDomain2 The dot-separated domain. 1087 * 1088 * @retval TRUE If the two DNS names are the same domain. 1089 * @retval FALSE If the two DNS names are not the same domain. 1090 * 1091 */ 1092 static bool IsSameDomain(const char *aDomain1, const char *aDomain2); 1093 1094 private: 1095 // The first 2 bits of the encoded label specifies label type. 1096 // 1097 // - Value 00 indicates normal text label (lower 6-bits indicates the label length). 1098 // - Value 11 indicates pointer label type (lower 14-bits indicates the pointer offset). 1099 // - Values 01,10 are reserved (RFC 6891 recommends to not use) 1100 1101 static constexpr uint8_t kLabelTypeMask = 0xc0; // 0b1100_0000 (first two bits) 1102 static constexpr uint8_t kTextLabelType = 0x00; // Text label type (00) 1103 static constexpr uint8_t kPointerLabelType = 0xc0; // Pointer label type - compressed name (11) 1104 1105 static constexpr uint8_t kMaxEncodedLength = 255; ///< Max length of an encoded name. 1106 1107 static constexpr uint16_t kPointerLabelTypeUint16 = 0xc000; // Pointer label type mask (first 2 bits). 1108 static constexpr uint16_t kPointerLabelOffsetMask = 0x3fff; // Mask for offset in a pointer label (lower 14 bits). 1109 1110 static constexpr bool kIsSingleLabel = true; // Used in `LabelIterator::CompareLabel()`. 1111 1112 struct LabelIterator 1113 { 1114 static constexpr uint16_t kUnsetNameEndOffset = 0; // Special value indicating `mNameEndOffset` is not yet set. 1115 LabelIteratorot::Dns::Name::LabelIterator1116 LabelIterator(const Message &aMessage, uint16_t aLabelOffset) 1117 : mMessage(aMessage) 1118 , mNextLabelOffset(aLabelOffset) 1119 , mNameEndOffset(kUnsetNameEndOffset) 1120 { 1121 } 1122 IsEndOffsetSetot::Dns::Name::LabelIterator1123 bool IsEndOffsetSet(void) const { return (mNameEndOffset != kUnsetNameEndOffset); } 1124 Error GetNextLabel(void); 1125 Error ReadLabel(char *aLabelBuffer, uint8_t &aLabelLength, bool aAllowDotCharInLabel) const; 1126 bool CompareLabel(const char *&aName, bool aIsSingleLabel) const; 1127 bool CompareLabel(const LabelIterator &aOtherIterator) const; 1128 Error AppendLabel(Message &aMessage) const; 1129 1130 static bool CaseInsensitiveMatch(uint8_t aFirst, uint8_t aSecond); 1131 1132 const Message &mMessage; // Message to read labels from. 1133 uint16_t mLabelStartOffset; // Offset in `mMessage` to the first char of current label text. 1134 uint8_t mLabelLength; // Length of current label (number of chars). 1135 uint16_t mNextLabelOffset; // Offset in `mMessage` to the start of the next label. 1136 uint16_t mNameEndOffset; // Offset in `mMessage` to the byte after the end of domain name field. 1137 }; 1138 Name(const char * aString,const Message * aMessage,uint16_t aOffset)1139 Name(const char *aString, const Message *aMessage, uint16_t aOffset) 1140 : mString(aString) 1141 , mMessage(aMessage) 1142 , mOffset(aOffset) 1143 { 1144 } 1145 1146 static bool CompareAndSkipLabels(const char *&aNamePtr, const char *aLabels, char aExpectedNextChar); 1147 static Error AppendLabel(const char *aLabel, uint8_t aLength, Message &aMessage); 1148 1149 const char *mString; // String containing the name or `nullptr` if name is not from string. 1150 const Message *mMessage; // Message containing the encoded name, or `nullptr` if `Name` is not from message. 1151 uint16_t mOffset; // Offset in `mMessage` to the start of name (used when name is from `mMessage`). 1152 }; 1153 1154 /** 1155 * Represents a TXT record entry representing a key/value pair (RFC 6763 - section 6.3). 1156 * 1157 */ 1158 class TxtEntry : public otDnsTxtEntry 1159 { 1160 friend class TxtRecord; 1161 1162 public: 1163 /** 1164 * Minimum length of key string (RFC 6763 - section 6.4). 1165 * 1166 */ 1167 static constexpr uint8_t kMinKeyLength = OT_DNS_TXT_KEY_MIN_LENGTH; 1168 1169 /** 1170 * Recommended max length of key string (RFC 6763 - section 6.4). 1171 * 1172 */ 1173 static constexpr uint8_t kMaxKeyLength = OT_DNS_TXT_KEY_MAX_LENGTH; 1174 1175 /** 1176 * Maximum length of TXT key string supported by `Iterator`. 1177 * 1178 * This is selected to be longer than recommended `kMaxKeyLength` to handle cases where longer keys are used. 1179 * 1180 */ 1181 static constexpr uint8_t kMaxIterKeyLength = OT_DNS_TXT_KEY_ITER_MAX_LENGTH; 1182 1183 /** 1184 * Represents an iterator for TXT record entries (key/value pairs). 1185 * 1186 */ 1187 class Iterator : public otDnsTxtEntryIterator 1188 { 1189 friend class TxtEntry; 1190 1191 public: 1192 /** 1193 * Initializes a TXT record iterator. 1194 * 1195 * The buffer pointer @p aTxtData and its content MUST persist and remain unchanged while the iterator object 1196 * is being used. 1197 * 1198 * @param[in] aTxtData A pointer to buffer containing the encoded TXT data. 1199 * @param[in] aTxtDataLength The length (number of bytes) of @p aTxtData. 1200 * 1201 */ 1202 void Init(const uint8_t *aTxtData, uint16_t aTxtDataLength); 1203 1204 /** 1205 * Parses the TXT data from the `Iterator` and gets the next TXT record entry (key/value pair). 1206 * 1207 * The `Iterator` instance MUST be initialized using `Init()` before calling this method and the TXT data 1208 * buffer used to initialize the iterator MUST persist and remain unchanged. 1209 * 1210 * If the parsed key string length is smaller than or equal to `kMaxIterKeyLength` the key string is returned 1211 * in `mKey` in @p aEntry. But if the key is longer, then `mKey` is set to `nullptr` the entire encoded TXT 1212 * entry is returned in `mValue` and `mValueLength`. 1213 * 1214 * @param[out] aEntry A reference to a `TxtEntry` to output the parsed/read entry. 1215 * 1216 * @retval kErrorNone The next entry was parsed successfully. @p aEntry is updated. 1217 * @retval kErrorNotFound No more entries in TXT data. 1218 * @retval kErrorParse The TXT data from `Iterator` is not well-formed. 1219 * 1220 */ 1221 Error GetNextEntry(TxtEntry &aEntry); 1222 1223 private: 1224 static constexpr uint8_t kIndexTxtLength = 0; 1225 static constexpr uint8_t kIndexTxtPosition = 1; 1226 GetTxtData(void) const1227 const char *GetTxtData(void) const { return reinterpret_cast<const char *>(mPtr); } SetTxtData(const uint8_t * aTxtData)1228 void SetTxtData(const uint8_t *aTxtData) { mPtr = aTxtData; } GetTxtDataLength(void) const1229 uint16_t GetTxtDataLength(void) const { return mData[kIndexTxtLength]; } SetTxtDataLength(uint16_t aLength)1230 void SetTxtDataLength(uint16_t aLength) { mData[kIndexTxtLength] = aLength; } GetTxtDataPosition(void) const1231 uint16_t GetTxtDataPosition(void) const { return mData[kIndexTxtPosition]; } SetTxtDataPosition(uint16_t aValue)1232 void SetTxtDataPosition(uint16_t aValue) { mData[kIndexTxtPosition] = aValue; } IncreaseTxtDataPosition(uint16_t aIncrement)1233 void IncreaseTxtDataPosition(uint16_t aIncrement) { mData[kIndexTxtPosition] += aIncrement; } GetKeyBuffer(void)1234 char *GetKeyBuffer(void) { return mChar; } GetTxtDataEnd(void) const1235 const char *GetTxtDataEnd(void) const { return GetTxtData() + GetTxtDataLength(); } 1236 }; 1237 1238 /** 1239 * This is the default constructor for a `TxtEntry` object. 1240 * 1241 */ 1242 TxtEntry(void) = default; 1243 1244 /** 1245 * Initializes a `TxtEntry` object. 1246 * 1247 * @param[in] aKey A pointer to the key string. 1248 * @param[in] aValue A pointer to a buffer containing the value. 1249 * @param[in] aValueLength Number of bytes in @p aValue buffer. 1250 * 1251 */ TxtEntry(const char * aKey,const uint8_t * aValue,uint8_t aValueLength)1252 TxtEntry(const char *aKey, const uint8_t *aValue, uint8_t aValueLength) { Init(aKey, aValue, aValueLength); } 1253 1254 /** 1255 * Initializes a `TxtEntry` object. 1256 * 1257 * @param[in] aKey A pointer to the key string. 1258 * @param[in] aValue A pointer to a buffer containing the value. 1259 * @param[in] aValueLength Number of bytes in @p aValue buffer. 1260 * 1261 */ Init(const char * aKey,const uint8_t * aValue,uint8_t aValueLength)1262 void Init(const char *aKey, const uint8_t *aValue, uint8_t aValueLength) 1263 { 1264 mKey = aKey; 1265 mValue = aValue; 1266 mValueLength = aValueLength; 1267 } 1268 1269 /** 1270 * Encodes and appends the `TxtEntry` to a message. 1271 * 1272 * @param[in] aMessage The message to append to. 1273 * 1274 * @retval kErrorNone Entry was appended successfully to @p aMessage. 1275 * @retval kErrorInvalidArgs The `TxTEntry` info is not valid. 1276 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 1277 * 1278 */ 1279 Error AppendTo(Message &aMessage) const; 1280 1281 /** 1282 * Appends an array of `TxtEntry` items to a message. 1283 * 1284 * @param[in] aEntries A pointer to array of `TxtEntry` items. 1285 * @param[in] aNumEntries The number of entries in @p aEntries array. 1286 * @param[in] aMessage The message to append to. 1287 * 1288 * @retval kErrorNone Entries appended successfully to @p aMessage. 1289 * @retval kErrorInvalidArgs The `TxTEntry` info is not valid. 1290 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 1291 * 1292 */ 1293 static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, Message &aMessage); 1294 1295 /** 1296 * Appends an array of `TxtEntry` items to a `MutableData` buffer. 1297 * 1298 * @param[in] aEntries A pointer to array of `TxtEntry` items. 1299 * @param[in] aNumEntries The number of entries in @p aEntries array. 1300 * @param[in] aData The `MutableData` to append in. 1301 * 1302 * @retval kErrorNone Entries appended successfully . 1303 * @retval kErrorInvalidArgs The `TxTEntry` info is not valid. 1304 * @retval kErrorNoBufs Insufficient available buffers. 1305 * 1306 */ 1307 static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, MutableData<kWithUint16Length> &aData); 1308 1309 private: 1310 Error AppendTo(Appender &aAppender) const; 1311 static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, Appender &aAppender); 1312 1313 static constexpr uint8_t kMaxKeyValueEncodedSize = 255; 1314 static constexpr char kKeyValueSeparator = '='; 1315 }; 1316 1317 /** 1318 * Implements Resource Record (RR) body format. 1319 * 1320 */ 1321 OT_TOOL_PACKED_BEGIN 1322 class ResourceRecord 1323 { 1324 friend class OptRecord; 1325 1326 public: 1327 // Resource Record Types. 1328 static constexpr uint16_t kTypeZero = 0; ///< Zero as special indicator for the SIG RR (SIG(0) from RFC 2931). 1329 static constexpr uint16_t kTypeA = 1; ///< Address record (IPv4). 1330 static constexpr uint16_t kTypeSoa = 6; ///< Start of (zone of) authority. 1331 static constexpr uint16_t kTypeCname = 5; ///< CNAME record. 1332 static constexpr uint16_t kTypePtr = 12; ///< PTR record. 1333 static constexpr uint16_t kTypeTxt = 16; ///< TXT record. 1334 static constexpr uint16_t kTypeSig = 24; ///< SIG record. 1335 static constexpr uint16_t kTypeKey = 25; ///< KEY record. 1336 static constexpr uint16_t kTypeAaaa = 28; ///< IPv6 address record. 1337 static constexpr uint16_t kTypeSrv = 33; ///< SRV locator record. 1338 static constexpr uint16_t kTypeOpt = 41; ///< Option record. 1339 static constexpr uint16_t kTypeAny = 255; ///< ANY record. 1340 1341 // Resource Record Class Codes. 1342 static constexpr uint16_t kClassInternet = 1; ///< Class code Internet (IN). 1343 static constexpr uint16_t kClassNone = 254; ///< Class code None (NONE) - RFC 2136. 1344 static constexpr uint16_t kClassAny = 255; ///< Class code Any (ANY). 1345 1346 /** 1347 * Initializes the resource record by setting its type and class. 1348 * 1349 * Only sets the type and class fields. Other fields (TTL and length) remain unchanged/uninitialized. 1350 * 1351 * @param[in] aType The type of the resource record. 1352 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1353 * 1354 */ Init(uint16_t aType,uint16_t aClass=kClassInternet)1355 void Init(uint16_t aType, uint16_t aClass = kClassInternet) 1356 { 1357 SetType(aType); 1358 SetClass(aClass); 1359 } 1360 1361 /** 1362 * Indicates whether the resources records matches a given type and class code. 1363 * 1364 * @param[in] aType The resource record type to compare with. 1365 * @param[in] aClass The resource record class code to compare with (default is `kClassInternet`). 1366 * 1367 * @returns TRUE if the resources records matches @p aType and @p aClass, FALSE otherwise. 1368 * 1369 */ Matches(uint16_t aType,uint16_t aClass=kClassInternet) const1370 bool Matches(uint16_t aType, uint16_t aClass = kClassInternet) const 1371 { 1372 return (mType == BigEndian::HostSwap16(aType)) && (mClass == BigEndian::HostSwap16(aClass)); 1373 } 1374 1375 /** 1376 * Returns the type of the resource record. 1377 * 1378 * @returns The type of the resource record. 1379 * 1380 */ GetType(void) const1381 uint16_t GetType(void) const { return BigEndian::HostSwap16(mType); } 1382 1383 /** 1384 * Sets the type of the resource record. 1385 * 1386 * @param[in] aType The type of the resource record. 1387 * 1388 */ SetType(uint16_t aType)1389 void SetType(uint16_t aType) { mType = BigEndian::HostSwap16(aType); } 1390 1391 /** 1392 * Returns the class of the resource record. 1393 * 1394 * @returns The class of the resource record. 1395 * 1396 */ GetClass(void) const1397 uint16_t GetClass(void) const { return BigEndian::HostSwap16(mClass); } 1398 1399 /** 1400 * Sets the class of the resource record. 1401 * 1402 * @param[in] aClass The class of the resource record. 1403 * 1404 */ SetClass(uint16_t aClass)1405 void SetClass(uint16_t aClass) { mClass = BigEndian::HostSwap16(aClass); } 1406 1407 /** 1408 * Returns the time to live field of the resource record. 1409 * 1410 * @returns The time to live field of the resource record. 1411 * 1412 */ GetTtl(void) const1413 uint32_t GetTtl(void) const { return BigEndian::HostSwap32(mTtl); } 1414 1415 /** 1416 * Sets the time to live field of the resource record. 1417 * 1418 * @param[in] aTtl The time to live field of the resource record. 1419 * 1420 */ SetTtl(uint32_t aTtl)1421 void SetTtl(uint32_t aTtl) { mTtl = BigEndian::HostSwap32(aTtl); } 1422 1423 /** 1424 * Returns the length of the resource record data. 1425 * 1426 * @returns The length of the resource record data. 1427 * 1428 */ GetLength(void) const1429 uint16_t GetLength(void) const { return BigEndian::HostSwap16(mLength); } 1430 1431 /** 1432 * Sets the length of the resource record data. 1433 * 1434 * @param[in] aLength The length of the resource record data. 1435 * 1436 */ SetLength(uint16_t aLength)1437 void SetLength(uint16_t aLength) { mLength = BigEndian::HostSwap16(aLength); } 1438 1439 /** 1440 * Returns the size of (number of bytes) in resource record and its data RDATA section (excluding the 1441 * name field). 1442 * 1443 * @returns Size (number of bytes) of resource record and its data section (excluding the name field) 1444 * 1445 */ GetSize(void) const1446 uint32_t GetSize(void) const { return sizeof(ResourceRecord) + GetLength(); } 1447 1448 /** 1449 * Parses and skips over a given number of resource records in a message from a given offset. 1450 * 1451 * @param[in] aMessage The message from which to parse/read the resource records. `aMessage.GetOffset()` 1452 * MUST point to the start of DNS header. 1453 * @param[in,out] aOffset On input the offset in @p aMessage pointing to the start of the first record. 1454 * On exit (when parsed successfully), @p aOffset is updated to point to the byte after 1455 * the last parsed record. 1456 * @param[in] aNumRecords Number of resource records to parse. 1457 * 1458 * @retval kErrorNone Parsed records successfully. @p aOffset is updated. 1459 * @retval kErrorParse Could not parse the records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1460 * 1461 */ 1462 static Error ParseRecords(const Message &aMessage, uint16_t &aOffset, uint16_t aNumRecords); 1463 1464 /** 1465 * Searches in a given message to find the first resource record matching a given record name. 1466 * 1467 * @param[in] aMessage The message in which to search for a matching resource record. 1468 * `aMessage.GetOffset()` MUST point to the start of DNS header. 1469 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the first record. 1470 * On exit, if a matching record is found, @p aOffset is updated to point to the byte 1471 * after the record name. 1472 * If a matching record could not be found, @p aOffset is updated to point to the byte 1473 * after the last record that was checked. 1474 * @param[in,out] aNumRecords On input, the maximum number of records to check (starting from @p aOffset). 1475 * On exit and if a matching record is found, @p aNumRecords is updated to give the 1476 * number of remaining records after @p aOffset (excluding the matching record). 1477 * @param[in] aName The record name to match against. 1478 * 1479 * @retval kErrorNone A matching record was found. @p aOffset, @p aNumRecords are updated. 1480 * @retval kErrorNotFound A matching record could not be found. @p aOffset and @p aNumRecords are updated. 1481 * @retval kErrorParse Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1482 * 1483 */ 1484 static Error FindRecord(const Message &aMessage, uint16_t &aOffset, uint16_t &aNumRecords, const Name &aName); 1485 1486 /** 1487 * This template static method searches in a message to find the i-th occurrence of resource records of specific 1488 * type with a given record name and if found, reads the record from the message. 1489 * 1490 * Searches in @p aMessage starting from @p aOffset up to maximum of @p aNumRecords, for the 1491 * `(aIndex+1)`th occurrence of a resource record of `RecordType` with record name @p aName. 1492 * 1493 * On success (i.e., when a matching record is found and read from the message), @p aOffset is updated to point 1494 * to after the last byte read from the message and copied into @p aRecord. This allows the caller to read any 1495 * remaining fields in the record data. 1496 * 1497 * @tparam RecordType The resource record type (i.e., a sub-class of `ResourceRecord`). 1498 * 1499 * @param[in] aMessage The message to search within for matching resource records. 1500 * `aMessage.GetOffset()` MUST point to the start of DNS header. 1501 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the first record. 1502 * On exit and only if a matching record is found, @p aOffset is updated to point to 1503 * the last read byte in the record (allowing caller to read any remaining fields in 1504 * the record data from the message). 1505 * @param[in] aNumRecords The maximum number of records to check (starting from @p aOffset). 1506 * @param[in] aIndex The matching record index to find. @p aIndex value of zero returns the first 1507 * matching record. 1508 * @param[in] aName The record name to match against. 1509 * @param[in] aRecord A reference to a record object to read a matching record into. 1510 * If a matching record is found, `sizeof(RecordType)` bytes from @p aMessage are 1511 * read and copied into @p aRecord. 1512 * 1513 * @retval kErrorNone A matching record was found. @p aOffset is updated. 1514 * @retval kErrorNotFound A matching record could not be found. 1515 * @retval kErrorParse Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1516 * 1517 */ 1518 template <class RecordType> FindRecord(const Message & aMessage,uint16_t & aOffset,uint16_t aNumRecords,uint16_t aIndex,const Name & aName,RecordType & aRecord)1519 static Error FindRecord(const Message &aMessage, 1520 uint16_t &aOffset, 1521 uint16_t aNumRecords, 1522 uint16_t aIndex, 1523 const Name &aName, 1524 RecordType &aRecord) 1525 { 1526 return FindRecord(aMessage, aOffset, aNumRecords, aIndex, aName, RecordType::kType, aRecord, 1527 sizeof(RecordType)); 1528 } 1529 1530 /** 1531 * This template static method tries to read a resource record of a given type from a message. If the record type 1532 * does not matches the type, it skips over the record. 1533 * 1534 * Requires the record name to be already parsed/read from the message. On input, @p aOffset should 1535 * point to the start of the `ResourceRecord` fields (type, class, TTL, data length) in @p aMessage. 1536 * 1537 * Verifies that the record is well-formed in the message. It then reads the record type and compares 1538 * it with `RecordType::kType` and ensures that the record size is at least `sizeof(RecordType)`. If it all matches, 1539 * the record is read into @p aRecord. 1540 * 1541 * On success (i.e., when a matching record is read from the message), the @p aOffset is updated to point to after 1542 * the last byte read from the message and copied into @p aRecord and not necessarily the end of the record. 1543 * Depending on the `RecordType` format, there may still be more data bytes left in the record to be read. For 1544 * example, when reading a SRV record using `SrvRecord` type, @p aOffset would point to after the last field in 1545 * `SrvRecord` which is the start of "target host domain name" field. 1546 * 1547 * @tparam RecordType The resource record type (i.e., a sub-class of `ResourceRecord`). 1548 * 1549 * @param[in] aMessage The message from which to read the record. 1550 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the byte after the record name. 1551 * On exit, if a matching record is read, @p aOffset is updated to point to the last 1552 * read byte in the record. 1553 * If a matching record could not be read, @p aOffset is updated to point to the byte 1554 * after the entire record (skipping over the record). 1555 * @param[out] aRecord A reference to a record to read a matching record into. 1556 * If a matching record is found, `sizeof(RecordType)` bytes from @p aMessage are 1557 * read and copied into @p aRecord. 1558 * 1559 * @retval kErrorNone A matching record was read successfully. @p aOffset, and @p aRecord are updated. 1560 * @retval kErrorNotFound A matching record could not be found. @p aOffset is updated. 1561 * @retval kErrorParse Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1562 * 1563 */ ReadRecord(const Message & aMessage,uint16_t & aOffset,RecordType & aRecord)1564 template <class RecordType> static Error ReadRecord(const Message &aMessage, uint16_t &aOffset, RecordType &aRecord) 1565 { 1566 return ReadRecord(aMessage, aOffset, RecordType::kType, aRecord, sizeof(RecordType)); 1567 } 1568 1569 protected: 1570 Error ReadName(const Message &aMessage, 1571 uint16_t &aOffset, 1572 uint16_t aStartOffset, 1573 char *aNameBuffer, 1574 uint16_t aNameBufferSize, 1575 bool aSkipRecord) const; 1576 Error SkipRecord(const Message &aMessage, uint16_t &aOffset) const; 1577 1578 private: 1579 static constexpr uint16_t kType = kTypeAny; // This is intended for used by `ReadRecord<RecordType>()` only. 1580 1581 static Error FindRecord(const Message &aMessage, 1582 uint16_t &aOffset, 1583 uint16_t aNumRecords, 1584 uint16_t aIndex, 1585 const Name &aName, 1586 uint16_t aType, 1587 ResourceRecord &aRecord, 1588 uint16_t aMinRecordSize); 1589 1590 static Error ReadRecord(const Message &aMessage, 1591 uint16_t &aOffset, 1592 uint16_t aType, 1593 ResourceRecord &aRecord, 1594 uint16_t aMinRecordSize); 1595 1596 Error CheckRecord(const Message &aMessage, uint16_t aOffset) const; 1597 Error ReadFrom(const Message &aMessage, uint16_t aOffset); 1598 1599 uint16_t mType; // The type of the data in RDATA section. 1600 uint16_t mClass; // The class of the data in RDATA section. 1601 uint32_t mTtl; // Specifies the maximum time that the resource record may be cached. 1602 uint16_t mLength; // The length of RDATA section in bytes. 1603 1604 } OT_TOOL_PACKED_END; 1605 1606 /** 1607 * Implements Resource Record body format of A type. 1608 * 1609 */ 1610 OT_TOOL_PACKED_BEGIN 1611 class ARecord : public ResourceRecord 1612 { 1613 public: 1614 static constexpr uint16_t kType = kTypeA; ///< The A record type. 1615 1616 /** 1617 * Initializes the A Resource Record by setting its type, class, and length. 1618 * 1619 * Other record fields (TTL, address) remain unchanged/uninitialized. 1620 * 1621 */ Init(void)1622 void Init(void) 1623 { 1624 ResourceRecord::Init(kTypeA); 1625 SetLength(sizeof(Ip4::Address)); 1626 } 1627 1628 /** 1629 * Sets the IPv4 address of the resource record. 1630 * 1631 * @param[in] aAddress The IPv4 address of the resource record. 1632 * 1633 */ SetAddress(const Ip4::Address & aAddress)1634 void SetAddress(const Ip4::Address &aAddress) { mAddress = aAddress; } 1635 1636 /** 1637 * Returns the reference to IPv4 address of the resource record. 1638 * 1639 * @returns The reference to IPv4 address of the resource record. 1640 * 1641 */ GetAddress(void) const1642 const Ip4::Address &GetAddress(void) const { return mAddress; } 1643 1644 private: 1645 Ip4::Address mAddress; // IPv4 Address of A Resource Record. 1646 } OT_TOOL_PACKED_END; 1647 1648 /** 1649 * Implements Resource Record body format of CNAME type. 1650 * 1651 */ 1652 OT_TOOL_PACKED_BEGIN 1653 class CnameRecord : public ResourceRecord 1654 { 1655 public: 1656 static constexpr uint16_t kType = kTypeCname; ///< The CNAME record type. 1657 1658 /** 1659 * Initializes the CNAME Resource Record by setting its type and class. 1660 * 1661 * Other record fields (TTL, length) remain unchanged/uninitialized. 1662 * 1663 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1664 * 1665 */ Init(uint16_t aClass=kClassInternet)1666 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeCname, aClass); } 1667 1668 /** 1669 * Parses and reads the CNAME alias name from a message. 1670 * 1671 * Also verifies that the CNAME record is well-formed (e.g., the record data length `GetLength()` 1672 * matches the CNAME encoded name). 1673 * 1674 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1675 * DNS header. 1676 * @param[in,out] aOffset On input, the offset in @p aMessage to start of CNAME name field. 1677 * On exit when successfully read, @p aOffset is updated to point to the byte 1678 * after the entire PTR record (skipping over the record). 1679 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 1680 * (MUST NOT be `nullptr`). 1681 * @param[in] aNameBufferSize The size of @p aNameBuffer. 1682 * 1683 * @retval kErrorNone The CNAME name was read successfully. @p aOffset and @p aNameBuffer are updated. 1684 * @retval kErrorParse The CNAME record in @p aMessage could not be parsed (invalid format). 1685 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 1686 * 1687 */ ReadCanonicalName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const1688 Error ReadCanonicalName(const Message &aMessage, 1689 uint16_t &aOffset, 1690 char *aNameBuffer, 1691 uint16_t aNameBufferSize) const 1692 { 1693 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(CnameRecord), 1694 aNameBuffer, aNameBufferSize, /* aSkipRecord */ true); 1695 } 1696 1697 } OT_TOOL_PACKED_END; 1698 1699 /** 1700 * Implements Resource Record body format of PTR type. 1701 * 1702 */ 1703 OT_TOOL_PACKED_BEGIN 1704 class PtrRecord : public ResourceRecord 1705 { 1706 public: 1707 static constexpr uint16_t kType = kTypePtr; ///< The PTR record type. 1708 1709 /** 1710 * Initializes the PTR Resource Record by setting its type and class. 1711 * 1712 * Other record fields (TTL, length) remain unchanged/uninitialized. 1713 * 1714 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1715 * 1716 */ Init(uint16_t aClass=kClassInternet)1717 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypePtr, aClass); } 1718 1719 /** 1720 * Parses and reads the PTR name from a message. 1721 * 1722 * Also verifies that the PTR record is well-formed (e.g., the record data length `GetLength()` matches 1723 * the PTR encoded name). 1724 * 1725 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1726 * DNS header. 1727 * @param[in,out] aOffset On input, the offset in @p aMessage to start of PTR name field. 1728 * On exit when successfully read, @p aOffset is updated to point to the byte 1729 * after the entire PTR record (skipping over the record). 1730 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 1731 * (MUST NOT be `nullptr`). 1732 * @param[in] aNameBufferSize The size of @p aNameBuffer. 1733 * 1734 * @retval kErrorNone The PTR name was read successfully. @p aOffset and @p aNameBuffer are updated. 1735 * @retval kErrorParse The PTR record in @p aMessage could not be parsed (invalid format). 1736 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 1737 * 1738 */ ReadPtrName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const1739 Error ReadPtrName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize) const 1740 { 1741 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(PtrRecord), aNameBuffer, 1742 aNameBufferSize, 1743 /* aSkipRecord */ true); 1744 } 1745 1746 /** 1747 * Parses and reads the PTR name from a message. 1748 * 1749 * Also verifies that the PTR record is well-formed (e.g., the record data length `GetLength()` matches 1750 * the PTR encoded name). 1751 * 1752 * Unlike the previous method which reads the entire PTR name into a single char buffer, this method reads the 1753 * first label separately and into a different buffer @p aLabelBuffer and the rest of the name into @p aNameBuffer. 1754 * The @p aNameBuffer can be set to `nullptr` if the caller is only interested in the first label. This method is 1755 * intended for "Service Instance Name" where first label (`<Instance>` portion) can be a user-friendly string and 1756 * can contain dot character. 1757 * 1758 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1759 * DNS header. 1760 * @param[in,out] aOffset On input, the offset in @p aMessage to the start of PTR name field. 1761 * On exit, when successfully read, @p aOffset is updated to point to the byte 1762 * after the entire PTR record (skipping over the record). 1763 * @param[out] aLabelBuffer A pointer to a char array to output the first label as a null-terminated C 1764 * string (MUST NOT be `nullptr`). 1765 * @param[in] aLabelBufferSize The size of @p aLabelBuffer. 1766 * @param[out] aNameBuffer A pointer to a char array to output the rest of name (after first label). Can 1767 * be `nullptr` if caller is only interested in the first label. 1768 * @param[in] aNameBufferSize The size of @p aNameBuffer. 1769 * 1770 * @retval kErrorNone The PTR name was read successfully. @p aOffset, @aLabelBuffer and @aNameBuffer are updated. 1771 * @retval kErrorParse The PTR record in @p aMessage could not be parsed (invalid format). 1772 * @retval kErrorNoBufs Either label or name could not fit in the related char buffers. 1773 * 1774 */ 1775 Error ReadPtrName(const Message &aMessage, 1776 uint16_t &aOffset, 1777 char *aLabelBuffer, 1778 uint8_t aLabelBufferSize, 1779 char *aNameBuffer, 1780 uint16_t aNameBufferSize) const; 1781 1782 /** 1783 * Parses and reads the PTR name from a message. 1784 * 1785 * This is a template variation of the previous method with name and label buffer sizes as template parameters. 1786 * 1787 * @tparam kLabelBufferSize The size of label buffer. 1788 * @tparam kNameBufferSize The size of name buffer. 1789 * 1790 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1791 * DNS header. 1792 * @param[in,out] aOffset On input, the offset in @p aMessage to the start of PTR name field. 1793 * On exit, when successfully read, @p aOffset is updated to point to the byte 1794 * after the entire PTR record (skipping over the record). 1795 * @param[out] aLabelBuffer A char array buffer to output the first label as a null-terminated C string. 1796 * @param[out] aNameBuffer A char array to output the rest of name (after first label). 1797 * 1798 * @retval kErrorNone The PTR name was read successfully. @p aOffset, @aLabelBuffer and @aNameBuffer are updated. 1799 * @retval kErrorParse The PTR record in @p aMessage could not be parsed (invalid format). 1800 * @retval kErrorNoBufs Either label or name could not fit in the related given buffers. 1801 * 1802 */ 1803 template <uint16_t kLabelBufferSize, uint16_t kNameBufferSize> ReadPtrName(const Message & aMessage,uint16_t & aOffset,char (& aLabelBuffer)[kLabelBufferSize],char (& aNameBuffer)[kNameBufferSize]) const1804 Error ReadPtrName(const Message &aMessage, 1805 uint16_t &aOffset, 1806 char (&aLabelBuffer)[kLabelBufferSize], 1807 char (&aNameBuffer)[kNameBufferSize]) const 1808 { 1809 return ReadPtrName(aMessage, aOffset, aLabelBuffer, kLabelBufferSize, aNameBuffer, kNameBufferSize); 1810 } 1811 1812 } OT_TOOL_PACKED_END; 1813 1814 /** 1815 * Implements Resource Record body format of TXT type. 1816 * 1817 */ 1818 OT_TOOL_PACKED_BEGIN 1819 class TxtRecord : public ResourceRecord 1820 { 1821 public: 1822 static constexpr uint16_t kType = kTypeTxt; ///< The TXT record type. 1823 1824 /** 1825 * Initializes the TXT Resource Record by setting its type and class. 1826 * 1827 * Other record fields (TTL, length) remain unchanged/uninitialized. 1828 * 1829 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1830 * 1831 */ Init(uint16_t aClass=kClassInternet)1832 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeTxt, aClass); } 1833 1834 /** 1835 * Parses and reads the TXT record data from a message. 1836 * 1837 * Also checks if the TXT data is well-formed by calling `VerifyTxtData()` when it is successfully 1838 * read. 1839 * 1840 * @param[in] aMessage The message to read from. 1841 * @param[in,out] aOffset On input, the offset in @p aMessage to start of TXT record data. 1842 * On exit when successfully read, @p aOffset is updated to point to the byte 1843 * after the entire TXT record (skipping over the record). 1844 * @param[out] aTxtBuffer A pointer to a byte array to output the read TXT data. 1845 * @param[in,out] aTxtBufferSize On input, the size of @p aTxtBuffer (max bytes that can be read). 1846 * On exit, @p aTxtBufferSize gives number of bytes written to @p aTxtBuffer. 1847 * 1848 * @retval kErrorNone The TXT data was read successfully. @p aOffset, @p aTxtBuffer and @p aTxtBufferSize 1849 * are updated. 1850 * @retval kErrorParse The TXT record in @p aMessage could not be parsed (invalid format). 1851 * @retval kErrorNoBufs TXT data could not fit in @p aTxtBufferSize bytes. TXT data is still partially read 1852 * into @p aTxtBuffer up to its size and @p aOffset is updated to skip over the full 1853 * TXT record. 1854 * 1855 */ 1856 Error ReadTxtData(const Message &aMessage, uint16_t &aOffset, uint8_t *aTxtBuffer, uint16_t &aTxtBufferSize) const; 1857 1858 /** 1859 * Tests if a buffer contains valid encoded TXT data. 1860 * 1861 * @param[in] aTxtData The TXT data buffer. 1862 * @param[in] aTxtLength The length of the TXT data buffer. 1863 * @param[in] aAllowEmpty True if zero-length TXT data is allowed. 1864 * 1865 * @returns TRUE if @p aTxtData contains valid encoded TXT data, FALSE if not. 1866 * 1867 */ 1868 static bool VerifyTxtData(const uint8_t *aTxtData, uint16_t aTxtLength, bool aAllowEmpty); 1869 1870 } OT_TOOL_PACKED_END; 1871 1872 /** 1873 * Implements Resource Record body format of AAAA type. 1874 * 1875 */ 1876 OT_TOOL_PACKED_BEGIN 1877 class AaaaRecord : public ResourceRecord 1878 { 1879 public: 1880 static constexpr uint16_t kType = kTypeAaaa; ///< The AAAA record type. 1881 1882 /** 1883 * Initializes the AAAA Resource Record by setting its type, class, and length. 1884 * 1885 * Other record fields (TTL, address) remain unchanged/uninitialized. 1886 * 1887 */ Init(void)1888 void Init(void) 1889 { 1890 ResourceRecord::Init(kTypeAaaa); 1891 SetLength(sizeof(Ip6::Address)); 1892 } 1893 1894 /** 1895 * Tells whether this is a valid AAAA record. 1896 * 1897 * @returns A boolean indicates whether this is a valid AAAA record. 1898 * 1899 */ 1900 bool IsValid(void) const; 1901 1902 /** 1903 * Sets the IPv6 address of the resource record. 1904 * 1905 * @param[in] aAddress The IPv6 address of the resource record. 1906 * 1907 */ SetAddress(const Ip6::Address & aAddress)1908 void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; } 1909 1910 /** 1911 * Returns the reference to IPv6 address of the resource record. 1912 * 1913 * @returns The reference to IPv6 address of the resource record. 1914 * 1915 */ GetAddress(void) const1916 const Ip6::Address &GetAddress(void) const { return mAddress; } 1917 1918 private: 1919 Ip6::Address mAddress; // IPv6 Address of AAAA Resource Record. 1920 } OT_TOOL_PACKED_END; 1921 1922 /** 1923 * Implements Resource Record body format of SRV type (RFC 2782). 1924 * 1925 */ 1926 OT_TOOL_PACKED_BEGIN 1927 class SrvRecord : public ResourceRecord 1928 { 1929 public: 1930 static constexpr uint16_t kType = kTypeSrv; ///< The SRV record type. 1931 1932 /** 1933 * Initializes the SRV Resource Record by settings its type and class. 1934 * 1935 * Other record fields (TTL, length, propriety, weight, port, ...) remain unchanged/uninitialized. 1936 * 1937 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1938 * 1939 */ Init(uint16_t aClass=kClassInternet)1940 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeSrv, aClass); } 1941 1942 /** 1943 * Returns the SRV record's priority value. 1944 * 1945 * @returns The priority value. 1946 * 1947 */ GetPriority(void) const1948 uint16_t GetPriority(void) const { return BigEndian::HostSwap16(mPriority); } 1949 1950 /** 1951 * Sets the SRV record's priority value. 1952 * 1953 * @param[in] aPriority The priority value. 1954 * 1955 */ SetPriority(uint16_t aPriority)1956 void SetPriority(uint16_t aPriority) { mPriority = BigEndian::HostSwap16(aPriority); } 1957 1958 /** 1959 * Returns the SRV record's weight value. 1960 * 1961 * @returns The weight value. 1962 * 1963 */ GetWeight(void) const1964 uint16_t GetWeight(void) const { return BigEndian::HostSwap16(mWeight); } 1965 1966 /** 1967 * Sets the SRV record's weight value. 1968 * 1969 * @param[in] aWeight The weight value. 1970 * 1971 */ SetWeight(uint16_t aWeight)1972 void SetWeight(uint16_t aWeight) { mWeight = BigEndian::HostSwap16(aWeight); } 1973 1974 /** 1975 * Returns the SRV record's port number on the target host for this service. 1976 * 1977 * @returns The port number. 1978 * 1979 */ GetPort(void) const1980 uint16_t GetPort(void) const { return BigEndian::HostSwap16(mPort); } 1981 1982 /** 1983 * Sets the SRV record's port number on the target host for this service. 1984 * 1985 * @param[in] aPort The port number. 1986 * 1987 */ SetPort(uint16_t aPort)1988 void SetPort(uint16_t aPort) { mPort = BigEndian::HostSwap16(aPort); } 1989 1990 /** 1991 * Parses and reads the SRV target host name from a message. 1992 * 1993 * Also verifies that the SRV record is well-formed (e.g., the record data length `GetLength()` matches 1994 * the SRV encoded name). 1995 * 1996 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1997 * DNS header. 1998 * @param[in,out] aOffset On input, the offset in @p aMessage to start of target host name field. 1999 * On exit when successfully read, @p aOffset is updated to point to the byte 2000 * after the entire SRV record (skipping over the record). 2001 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 2002 * (MUST NOT be `nullptr`). 2003 * @param[in] aNameBufferSize The size of @p aNameBuffer. 2004 * 2005 * @retval kErrorNone The host name was read successfully. @p aOffset and @p aNameBuffer are updated. 2006 * @retval kErrorParse The SRV record in @p aMessage could not be parsed (invalid format). 2007 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 2008 * 2009 */ ReadTargetHostName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const2010 Error ReadTargetHostName(const Message &aMessage, 2011 uint16_t &aOffset, 2012 char *aNameBuffer, 2013 uint16_t aNameBufferSize) const 2014 { 2015 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(SrvRecord), aNameBuffer, 2016 aNameBufferSize, 2017 /* aSkipRecord */ true); 2018 } 2019 2020 /** 2021 * Parses and reads the SRV target host name from a message. 2022 * 2023 * Also verifies that the SRV record is well-formed (e.g., the record data length `GetLength()` matches 2024 * the SRV encoded name). 2025 * 2026 * @tparam kNameBufferSize Size of the name buffer. 2027 * 2028 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 2029 * DNS header. 2030 * @param[in,out] aOffset On input, the offset in @p aMessage to start of target host name field. 2031 * On exit when successfully read, @p aOffset is updated to point to the byte 2032 * after the entire SRV record (skipping over the record). 2033 * @param[out] aNameBuffer A char array to output the read name as a null-terminated C string 2034 * 2035 * @retval kErrorNone The host name was read successfully. @p aOffset and @p aNameBuffer are updated. 2036 * @retval kErrorParse The SRV record in @p aMessage could not be parsed (invalid format). 2037 * @retval kErrorNoBufs Name could not fit in @p aNameBuffer. 2038 * 2039 */ 2040 template <uint16_t kNameBufferSize> ReadTargetHostName(const Message & aMessage,uint16_t & aOffset,char (& aNameBuffer)[kNameBufferSize]) const2041 Error ReadTargetHostName(const Message &aMessage, uint16_t &aOffset, char (&aNameBuffer)[kNameBufferSize]) const 2042 { 2043 return ReadTargetHostName(aMessage, aOffset, aNameBuffer, kNameBufferSize); 2044 } 2045 2046 private: 2047 uint16_t mPriority; 2048 uint16_t mWeight; 2049 uint16_t mPort; 2050 // Followed by the target host domain name. 2051 2052 } OT_TOOL_PACKED_END; 2053 2054 /** 2055 * Implements Resource Record body format of KEY type (RFC 2535). 2056 * 2057 */ 2058 OT_TOOL_PACKED_BEGIN 2059 class KeyRecord : public ResourceRecord 2060 { 2061 public: 2062 static constexpr uint16_t kType = kTypeKey; ///< The KEY record type. 2063 2064 // Protocol field values (RFC 2535 - section 3.1.3). 2065 static constexpr uint8_t kProtocolTls = 1; ///< TLS protocol code. 2066 static constexpr uint8_t kProtocolDnsSec = 3; ///< DNS security protocol code. 2067 2068 // Algorithm field values (RFC 8624 - section 3.1). 2069 static constexpr uint8_t kAlgorithmEcdsaP256Sha256 = 13; ///< ECDSA-P256-SHA256 algorithm. 2070 static constexpr uint8_t kAlgorithmEcdsaP384Sha384 = 14; ///< ECDSA-P384-SHA384 algorithm. 2071 static constexpr uint8_t kAlgorithmEd25519 = 15; ///< ED25519 algorithm. 2072 static constexpr uint8_t kAlgorithmEd448 = 16; ///< ED448 algorithm. 2073 2074 /** 2075 * Type represents the use (or key type) flags (RFC 2535 - section 3.1.2). 2076 * 2077 */ 2078 enum UseFlags : uint8_t 2079 { 2080 kAuthConfidPermitted = 0x00, ///< Use of the key for authentication and/or confidentiality is permitted. 2081 kAuthPermitted = 0x40, ///< Use of the key is only permitted for authentication. 2082 kConfidPermitted = 0x80, ///< Use of the key is only permitted for confidentiality. 2083 kNoKey = 0xc0, ///< No key value (e.g., can indicate zone is not secure). 2084 }; 2085 2086 /** 2087 * Type represents key owner (or name type) flags (RFC 2535 - section 3.1.2). 2088 * 2089 */ 2090 enum OwnerFlags : uint8_t 2091 { 2092 kOwnerUser = 0x00, ///< Key is associated with a "user" or "account" at end entity. 2093 kOwnerZone = 0x01, ///< Key is a zone key (used for data origin authentication). 2094 kOwnerNonZone = 0x02, ///< Key is associated with a non-zone "entity". 2095 kOwnerReserved = 0x03, ///< Reserved for future use. 2096 }; 2097 2098 // Constants for flag bits for the "signatory" flags (RFC 2137). 2099 // 2100 // The flags defined are for non-zone (`kOwnerNoneZone`) keys (RFC 2137 - section 3.1.3). 2101 2102 /** 2103 * Key is authorized to attach, detach, and move zones. 2104 * 2105 */ 2106 static constexpr uint8_t kSignatoryFlagZone = 1 << 3; 2107 2108 /** 2109 * Key is authorized to add and delete RRs even if RRs auth with other key. 2110 * 2111 */ 2112 static constexpr uint8_t kSignatoryFlagStrong = 1 << 2; 2113 2114 /** 2115 * Key is authorized to add and update RRs for only a single owner name. 2116 * 2117 */ 2118 static constexpr uint8_t kSignatoryFlagUnique = 1 << 1; 2119 2120 /** 2121 * If the other flags are zero, this is used to indicate it is an update key. 2122 * 2123 */ 2124 static constexpr uint8_t kSignatoryFlagGeneral = 1 << 0; 2125 2126 /** 2127 * Initializes the KEY Resource Record by setting its type and class. 2128 * 2129 * Other record fields (TTL, length, flags, protocol, algorithm) remain unchanged/uninitialized. 2130 * 2131 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 2132 * 2133 */ Init(uint16_t aClass=kClassInternet)2134 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeKey, aClass); } 2135 2136 /** 2137 * Tells whether the KEY record is valid. 2138 * 2139 * @returns TRUE if this is a valid KEY record, FALSE if an invalid KEY record. 2140 * 2141 */ 2142 bool IsValid(void) const; 2143 2144 /** 2145 * Gets the key use (or key type) flags. 2146 * 2147 * @returns The key use flags. 2148 * 2149 */ GetUseFlags(void) const2150 UseFlags GetUseFlags(void) const { return static_cast<UseFlags>(mFlags[0] & kUseFlagsMask); } 2151 2152 /** 2153 * Gets the owner (or name type) flags. 2154 * 2155 * @returns The key owner flags. 2156 * 2157 */ GetOwnerFlags(void) const2158 OwnerFlags GetOwnerFlags(void) const { return static_cast<OwnerFlags>(mFlags[0] & kOwnerFlagsMask); } 2159 2160 /** 2161 * Gets the signatory flags. 2162 * 2163 * @returns The signatory flags. 2164 * 2165 */ GetSignatoryFlags(void) const2166 uint8_t GetSignatoryFlags(void) const { return (mFlags[1] & kSignatoryFlagsMask); } 2167 2168 /** 2169 * Sets the flags field. 2170 * 2171 * @param[in] aUseFlags The `UseFlags` value. 2172 * @param[in] aOwnerFlags The `OwnerFlags` value. 2173 * @param[in] aSignatoryFlags The signatory flags. 2174 * 2175 */ SetFlags(UseFlags aUseFlags,OwnerFlags aOwnerFlags,uint8_t aSignatoryFlags)2176 void SetFlags(UseFlags aUseFlags, OwnerFlags aOwnerFlags, uint8_t aSignatoryFlags) 2177 { 2178 mFlags[0] = (static_cast<uint8_t>(aUseFlags) | static_cast<uint8_t>(aOwnerFlags)); 2179 mFlags[1] = (aSignatoryFlags & kSignatoryFlagsMask); 2180 } 2181 2182 /** 2183 * Returns the KEY record's protocol value. 2184 * 2185 * @returns The protocol value. 2186 * 2187 */ GetProtocol(void) const2188 uint8_t GetProtocol(void) const { return mProtocol; } 2189 2190 /** 2191 * Sets the KEY record's protocol value. 2192 * 2193 * @param[in] aProtocol The protocol value. 2194 * 2195 */ SetProtocol(uint8_t aProtocol)2196 void SetProtocol(uint8_t aProtocol) { mProtocol = aProtocol; } 2197 2198 /** 2199 * Returns the KEY record's algorithm value. 2200 * 2201 * @returns The algorithm value. 2202 * 2203 */ GetAlgorithm(void) const2204 uint8_t GetAlgorithm(void) const { return mAlgorithm; } 2205 2206 /** 2207 * Sets the KEY record's algorithm value. 2208 * 2209 * @param[in] aAlgorithm The algorithm value. 2210 * 2211 */ SetAlgorithm(uint8_t aAlgorithm)2212 void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; } 2213 2214 private: 2215 static constexpr uint8_t kUseFlagsMask = 0xc0; // top two bits in the first flag byte. 2216 static constexpr uint8_t kOwnerFlagsMask = 0x03; // lowest two bits in the first flag byte. 2217 static constexpr uint8_t kSignatoryFlagsMask = 0x0f; // lower 4 bits in the second flag byte. 2218 2219 // Flags format: 2220 // 2221 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 2222 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2223 // | Use | Z | XT| Z | Z | Owner | Z | Z | Z | Z | SIG | 2224 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2225 // \ / \ / 2226 // ---------- mFlags[0] --------- -------- mFlags[1] ---------- 2227 2228 uint8_t mFlags[2]; 2229 uint8_t mProtocol; 2230 uint8_t mAlgorithm; 2231 // Followed by the public key 2232 2233 } OT_TOOL_PACKED_END; 2234 2235 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 2236 OT_TOOL_PACKED_BEGIN 2237 class Ecdsa256KeyRecord : public KeyRecord, public Clearable<Ecdsa256KeyRecord>, public Equatable<Ecdsa256KeyRecord> 2238 { 2239 public: 2240 /** 2241 * Initializes the KEY Resource Record to ECDSA with curve P-256. 2242 * 2243 * Other record fields (TTL, length, flags, protocol) remain unchanged/uninitialized. 2244 * 2245 */ 2246 void Init(void); 2247 2248 /** 2249 * Tells whether this is a valid ECDSA DNSKEY with curve P-256. 2250 * 2251 * @returns A boolean that indicates whether this is a valid ECDSA DNSKEY RR with curve P-256. 2252 * 2253 */ 2254 bool IsValid(void) const; 2255 2256 /** 2257 * Returns the ECDSA P-256 public kek. 2258 * 2259 * @returns A reference to the public key. 2260 * 2261 */ GetKey(void) const2262 const Crypto::Ecdsa::P256::PublicKey &GetKey(void) const { return mKey; } 2263 2264 private: 2265 Crypto::Ecdsa::P256::PublicKey mKey; 2266 } OT_TOOL_PACKED_END; 2267 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 2268 2269 /** 2270 * Implements Resource Record body format of SIG type (RFC 2535 - section-4.1). 2271 * 2272 * 2273 */ 2274 OT_TOOL_PACKED_BEGIN 2275 class SigRecord : public ResourceRecord, public Clearable<SigRecord> 2276 { 2277 public: 2278 static constexpr uint16_t kType = kTypeSig; ///< The SIG record type. 2279 2280 /** 2281 * Initializes the SIG Resource Record by setting its type and class. 2282 * 2283 * Other record fields (TTL, length, ...) remain unchanged/uninitialized. 2284 * 2285 * SIG(0) requires SIG RR to set class field as ANY or `kClassAny` (RFC 2931 - section 3). 2286 * 2287 * @param[in] aClass The class of the resource record. 2288 * 2289 */ Init(uint16_t aClass)2290 void Init(uint16_t aClass) { ResourceRecord::Init(kTypeSig, aClass); } 2291 2292 /** 2293 * Tells whether the SIG record is valid. 2294 * 2295 * @returns TRUE if this is a valid SIG record, FALSE if not a valid SIG record. 2296 * 2297 */ 2298 bool IsValid(void) const; 2299 2300 /** 2301 * Returns the SIG record's type-covered value. 2302 * 2303 * @returns The type-covered value. 2304 * 2305 */ GetTypeCovered(void) const2306 uint16_t GetTypeCovered(void) const { return BigEndian::HostSwap16(mTypeCovered); } 2307 2308 /** 2309 * Sets the SIG record's type-covered value. 2310 * 2311 * @param[in] aTypeCovered The type-covered value. 2312 * 2313 */ SetTypeCovered(uint8_t aTypeCovered)2314 void SetTypeCovered(uint8_t aTypeCovered) { mTypeCovered = BigEndian::HostSwap16(aTypeCovered); } 2315 2316 /** 2317 * Returns the SIG record's algorithm value. 2318 * 2319 * @returns The algorithm value. 2320 * 2321 */ GetAlgorithm(void) const2322 uint8_t GetAlgorithm(void) const { return mAlgorithm; } 2323 2324 /** 2325 * Sets the SIG record's algorithm value. 2326 * 2327 * @param[in] aAlgorithm The algorithm value. 2328 * 2329 */ SetAlgorithm(uint8_t aAlgorithm)2330 void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; } 2331 2332 /** 2333 * Returns the SIG record's labels-count (number of labels, not counting null label, in the original 2334 * name of the owner). 2335 * 2336 * @returns The labels-count value. 2337 * 2338 */ GetLabels(void) const2339 uint8_t GetLabels(void) const { return mLabels; } 2340 2341 /** 2342 * Sets the SIG record's labels-count (number of labels, not counting null label, in the original 2343 * name of the owner). 2344 * 2345 * @param[in] aLabels The labels-count value. 2346 * 2347 */ SetLabels(uint8_t aLabels)2348 void SetLabels(uint8_t aLabels) { mLabels = aLabels; } 2349 2350 /** 2351 * Returns the SIG record's original TTL value. 2352 * 2353 * @returns The original TTL value. 2354 * 2355 */ GetOriginalTtl(void) const2356 uint32_t GetOriginalTtl(void) const { return BigEndian::HostSwap32(mOriginalTtl); } 2357 2358 /** 2359 * Sets the SIG record's original TTL value. 2360 * 2361 * @param[in] aOriginalTtl The original TTL value. 2362 * 2363 */ SetOriginalTtl(uint32_t aOriginalTtl)2364 void SetOriginalTtl(uint32_t aOriginalTtl) { mOriginalTtl = BigEndian::HostSwap32(aOriginalTtl); } 2365 2366 /** 2367 * Returns the SIG record's expiration time value. 2368 * 2369 * @returns The expiration time value (seconds since Jan 1, 1970). 2370 * 2371 */ GetExpiration(void) const2372 uint32_t GetExpiration(void) const { return BigEndian::HostSwap32(mExpiration); } 2373 2374 /** 2375 * Sets the SIG record's expiration time value. 2376 * 2377 * @param[in] aExpiration The expiration time value (seconds since Jan 1, 1970). 2378 * 2379 */ SetExpiration(uint32_t aExpiration)2380 void SetExpiration(uint32_t aExpiration) { mExpiration = BigEndian::HostSwap32(aExpiration); } 2381 2382 /** 2383 * Returns the SIG record's inception time value. 2384 * 2385 * @returns The inception time value (seconds since Jan 1, 1970). 2386 * 2387 */ GetInception(void) const2388 uint32_t GetInception(void) const { return BigEndian::HostSwap32(mInception); } 2389 2390 /** 2391 * Sets the SIG record's inception time value. 2392 * 2393 * @param[in] aInception The inception time value (seconds since Jan 1, 1970). 2394 * 2395 */ SetInception(uint32_t aInception)2396 void SetInception(uint32_t aInception) { mInception = BigEndian::HostSwap32(aInception); } 2397 2398 /** 2399 * Returns the SIG record's key tag value. 2400 * 2401 * @returns The key tag value. 2402 * 2403 */ GetKeyTag(void) const2404 uint16_t GetKeyTag(void) const { return BigEndian::HostSwap16(mKeyTag); } 2405 2406 /** 2407 * Sets the SIG record's key tag value. 2408 * 2409 * @param[in] aKeyTag The key tag value. 2410 * 2411 */ SetKeyTag(uint16_t aKeyTag)2412 void SetKeyTag(uint16_t aKeyTag) { mKeyTag = BigEndian::HostSwap16(aKeyTag); } 2413 2414 /** 2415 * Returns a pointer to the start of the record data fields. 2416 * 2417 * @returns A pointer to the start of the record data fields. 2418 * 2419 */ GetRecordData(void) const2420 const uint8_t *GetRecordData(void) const { return reinterpret_cast<const uint8_t *>(&mTypeCovered); } 2421 2422 /** 2423 * Parses and reads the SIG signer name from a message. 2424 * 2425 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of DNS 2426 * header. 2427 * @param[in,out] aOffset On input, the offset in @p aMessage to start of signer name field. 2428 * On exit when successfully read, @p aOffset is updated to point to the byte 2429 * after the name field (i.e., start of signature field). 2430 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 2431 * (MUST NOT be `nullptr`). 2432 * @param[in] aNameBufferSize The size of @p aNameBuffer. 2433 * 2434 * @retval kErrorNone The name was read successfully. @p aOffset and @p aNameBuffer are updated. 2435 * @retval kErrorParse The SIG record in @p aMessage could not be parsed (invalid format). 2436 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 2437 * 2438 */ ReadSignerName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const2439 Error ReadSignerName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize) const 2440 { 2441 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(SigRecord), aNameBuffer, 2442 aNameBufferSize, 2443 /* aSkipRecord */ false); 2444 } 2445 2446 private: 2447 uint16_t mTypeCovered; // type of the other RRs covered by this SIG. set to zero for SIG(0). 2448 uint8_t mAlgorithm; // Algorithm number (see `KeyRecord` enumeration). 2449 uint8_t mLabels; // Number of labels (not counting null label) in the original name of the owner of RR. 2450 uint32_t mOriginalTtl; // Original time-to-live (should set to zero for SIG(0)). 2451 uint32_t mExpiration; // Signature expiration time (seconds since Jan 1, 1970). 2452 uint32_t mInception; // Signature inception time (seconds since Jan 1, 1970). 2453 uint16_t mKeyTag; // Key tag. 2454 // Followed by signer name fields and signature fields 2455 } OT_TOOL_PACKED_END; 2456 2457 /** 2458 * Implements DNS OPT Pseudo Resource Record header for EDNS(0) (RFC 6891 - Section 6.1). 2459 * 2460 */ 2461 OT_TOOL_PACKED_BEGIN 2462 class OptRecord : public ResourceRecord 2463 { 2464 public: 2465 static constexpr uint16_t kType = kTypeOpt; ///< The OPT record type. 2466 2467 /** 2468 * Initializes the OPT Resource Record by setting its type and clearing extended Response Code, version 2469 * and all flags. 2470 * 2471 * Other record fields (UDP payload size, length) remain unchanged/uninitialized. 2472 * 2473 */ Init(void)2474 void Init(void) 2475 { 2476 SetType(kTypeOpt); 2477 SetTtl(0); 2478 } 2479 2480 /** 2481 * Gets the requester's UDP payload size (the number of bytes of the largest UDP payload that can be 2482 * delivered in the requester's network). 2483 * 2484 * The field is encoded in the CLASS field. 2485 * 2486 * @returns The UDP payload size. 2487 * 2488 */ GetUdpPayloadSize(void) const2489 uint16_t GetUdpPayloadSize(void) const { return GetClass(); } 2490 2491 /** 2492 * Gets the requester's UDP payload size (the number of bytes of the largest UDP payload that can be 2493 * delivered in the requester's network). 2494 * 2495 * @param[in] aPayloadSize The UDP payload size. 2496 * 2497 */ SetUdpPayloadSize(uint16_t aPayloadSize)2498 void SetUdpPayloadSize(uint16_t aPayloadSize) { SetClass(aPayloadSize); } 2499 2500 /** 2501 * Gets the upper 8-bit of the extended 12-bit Response Code. 2502 * 2503 * Value of 0 indicates that an unextended Response code is in use. 2504 * 2505 * @return The upper 8-bit of the extended 12-bit Response Code. 2506 * 2507 */ GetExtendedResponseCode(void) const2508 uint8_t GetExtendedResponseCode(void) const { return GetTtlByteAt(kExtRCodeByteIndex); } 2509 2510 /** 2511 * Sets the upper 8-bit of the extended 12-bit Response Code. 2512 * 2513 * Value of 0 indicates that an unextended Response code is in use. 2514 * 2515 * @param[in] aExtendedResponse The upper 8-bit of the extended 12-bit Response Code. 2516 * 2517 */ SetExtendedResponseCode(uint8_t aExtendedResponse)2518 void SetExtendedResponseCode(uint8_t aExtendedResponse) { GetTtlByteAt(kExtRCodeByteIndex) = aExtendedResponse; } 2519 2520 /** 2521 * Gets the Version field. 2522 * 2523 * @returns The version. 2524 * 2525 */ GetVersion(void) const2526 uint8_t GetVersion(void) const { return GetTtlByteAt(kVersionByteIndex); } 2527 2528 /** 2529 * Set the Version field. 2530 * 2531 * @param[in] aVersion The version. 2532 * 2533 */ SetVersion(uint8_t aVersion)2534 void SetVersion(uint8_t aVersion) { GetTtlByteAt(kVersionByteIndex) = aVersion; } 2535 2536 /** 2537 * Indicates whether the DNSSEC OK flag is set or not. 2538 * 2539 * @returns True if DNSSEC OK flag is set in the header, false otherwise. 2540 * 2541 */ IsDnsSecurityFlagSet(void) const2542 bool IsDnsSecurityFlagSet(void) const { return (GetTtlByteAt(kFlagByteIndex) & kDnsSecFlag) != 0; } 2543 2544 /** 2545 * Clears the DNSSEC OK bit flag. 2546 * 2547 */ ClearDnsSecurityFlag(void)2548 void ClearDnsSecurityFlag(void) { GetTtlByteAt(kFlagByteIndex) &= ~kDnsSecFlag; } 2549 2550 /** 2551 * Sets the DNSSEC OK bit flag. 2552 * 2553 */ SetDnsSecurityFlag(void)2554 void SetDnsSecurityFlag(void) { GetTtlByteAt(kFlagByteIndex) |= kDnsSecFlag; } 2555 2556 private: 2557 // The OPT RR re-purposes the existing CLASS and TTL fields in the 2558 // RR. The CLASS field (`uint16_t`) is used for requester UDP 2559 // payload size. The TTL field is used for extended Response Code, 2560 // version and flags as follows: 2561 // 2562 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 2563 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2564 // | EXTENDED-RCODE | VERSION | 2565 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2566 // | DO| Z | Z | 2567 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2568 // 2569 // The variable data part of OPT RR can contain zero of more `Option`. 2570 2571 static constexpr uint8_t kExtRCodeByteIndex = 0; // Byte index of Extended RCODE within the TTL field. 2572 static constexpr uint8_t kVersionByteIndex = 1; // Byte index of Version within the TTL field. 2573 static constexpr uint8_t kFlagByteIndex = 2; // Byte index of flag byte within the TTL field. 2574 static constexpr uint8_t kDnsSecFlag = 1 << 7; // DNSSec OK bit flag. 2575 GetTtlByteAt(uint8_t aIndex) const2576 uint8_t GetTtlByteAt(uint8_t aIndex) const { return reinterpret_cast<const uint8_t *>(&mTtl)[aIndex]; } GetTtlByteAt(uint8_t aIndex)2577 uint8_t &GetTtlByteAt(uint8_t aIndex) { return reinterpret_cast<uint8_t *>(&mTtl)[aIndex]; } 2578 2579 } OT_TOOL_PACKED_END; 2580 2581 /** 2582 * Implements the body of an Option in OPT Pseudo Resource Record (RFC 6981 - Section 6.1). 2583 * 2584 */ 2585 OT_TOOL_PACKED_BEGIN 2586 class Option 2587 { 2588 public: 2589 static constexpr uint16_t kUpdateLease = 2; ///< Update lease option code. 2590 2591 /** 2592 * Returns the option code value. 2593 * 2594 * @returns The option code value. 2595 * 2596 */ GetOptionCode(void) const2597 uint16_t GetOptionCode(void) const { return BigEndian::HostSwap16(mOptionCode); } 2598 2599 /** 2600 * Sets the option code value. 2601 * 2602 * @param[in] aOptionCode The option code value. 2603 * 2604 */ SetOptionCode(uint16_t aOptionCode)2605 void SetOptionCode(uint16_t aOptionCode) { mOptionCode = BigEndian::HostSwap16(aOptionCode); } 2606 2607 /** 2608 * Returns the option length value. 2609 * 2610 * @returns The option length (size of option data in bytes). 2611 * 2612 */ GetOptionLength(void) const2613 uint16_t GetOptionLength(void) const { return BigEndian::HostSwap16(mOptionLength); } 2614 2615 /** 2616 * Sets the option length value. 2617 * 2618 * @param[in] aOptionLength The option length (size of option data in bytes). 2619 * 2620 */ SetOptionLength(uint16_t aOptionLength)2621 void SetOptionLength(uint16_t aOptionLength) { mOptionLength = BigEndian::HostSwap16(aOptionLength); } 2622 2623 /** 2624 * Returns the size of (number of bytes) in the Option and its data. 2625 * 2626 * @returns Size (number of bytes) of the Option its data section. 2627 * 2628 */ GetSize(void) const2629 uint32_t GetSize(void) const { return sizeof(Option) + GetOptionLength(); } 2630 2631 private: 2632 uint16_t mOptionCode; 2633 uint16_t mOptionLength; 2634 // Followed by Option data (varies per option code). 2635 2636 } OT_TOOL_PACKED_END; 2637 2638 /** 2639 * Implements an Update Lease Option body. 2640 * 2641 * This implementation is intended for use in Dynamic DNS Update Lease Requests and Responses as specified in 2642 * https://tools.ietf.org/html/draft-sekar-dns-ul-02. 2643 * 2644 */ 2645 OT_TOOL_PACKED_BEGIN 2646 class LeaseOption : public Option 2647 { 2648 public: 2649 /** 2650 * Initializes the Update Lease Option using the short variant format which contains lease interval 2651 * only. 2652 * 2653 * @param[in] aLeaseInterval The lease interval in seconds. 2654 * 2655 */ 2656 void InitAsShortVariant(uint32_t aLeaseInterval); 2657 2658 /** 2659 * Initializes the Update Lease Option using the long variant format which contains both lease and 2660 * key lease intervals. 2661 * 2662 * @param[in] aLeaseInterval The lease interval in seconds. 2663 * @param[in] aKeyLeaseInterval The key lease interval in seconds. 2664 * 2665 */ 2666 void InitAsLongVariant(uint32_t aLeaseInterval, uint32_t aKeyLeaseInterval); 2667 2668 /** 2669 * Indicates whether or not the Update Lease Option follows the short variant format which contains 2670 * only the lease interval. 2671 * 2672 * @retval TRUE The Update Lease Option follows the short variant format. 2673 * @retval FALSE The Update Lease Option follows the long variant format. 2674 * 2675 */ IsShortVariant(void) const2676 bool IsShortVariant(void) const { return (GetOptionLength() == kShortLength); } 2677 2678 /** 2679 * Tells whether this is a valid Lease Option. 2680 * 2681 * Validates that option follows either short or long variant format. 2682 * 2683 * @returns TRUE if this is a valid Lease Option, FALSE if not a valid Lease Option. 2684 * 2685 */ 2686 bool IsValid(void) const; 2687 2688 /** 2689 * Returns the Update Lease OPT record's lease interval value. 2690 * 2691 * @returns The lease interval value (in seconds). 2692 * 2693 */ GetLeaseInterval(void) const2694 uint32_t GetLeaseInterval(void) const { return BigEndian::HostSwap32(mLeaseInterval); } 2695 2696 /** 2697 * Returns the Update Lease OPT record's key lease interval value. 2698 * 2699 * If the Update Lease Option follows the short variant format the lease interval is returned as key lease interval. 2700 * 2701 * @returns The key lease interval value (in seconds). 2702 * 2703 */ GetKeyLeaseInterval(void) const2704 uint32_t GetKeyLeaseInterval(void) const 2705 { 2706 return IsShortVariant() ? GetLeaseInterval() : BigEndian::HostSwap32(mKeyLeaseInterval); 2707 } 2708 2709 /** 2710 * Searches among the Options is a given message and reads and validates the Update Lease Option if 2711 * found. 2712 * 2713 * Reads the Update Lease Option whether it follows the short or long variant formats. 2714 * 2715 * @param[in] aMessage The message to read the Option from. 2716 * @param[in] aOffset Offset in @p aMessage to the start of Options (start of OPT Record data). 2717 * @param[in] aLength Length of Option data in OPT record. 2718 * 2719 * @retval kErrorNone Successfully read and validated the Update Lease Option from @p aMessage. 2720 * @retval kErrorNotFound Did not find any Update Lease Option. 2721 * @retval kErrorParse Failed to parse the Options. 2722 * 2723 */ 2724 Error ReadFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength); 2725 2726 private: 2727 static constexpr uint16_t kShortLength = sizeof(uint32_t); // lease only. 2728 static constexpr uint16_t kLongLength = sizeof(uint32_t) + sizeof(uint32_t); // lease and key lease values 2729 SetLeaseInterval(uint32_t aLeaseInterval)2730 void SetLeaseInterval(uint32_t aLeaseInterval) { mLeaseInterval = BigEndian::HostSwap32(aLeaseInterval); } SetKeyLeaseInterval(uint32_t aKeyLeaseInterval)2731 void SetKeyLeaseInterval(uint32_t aKeyLeaseInterval) 2732 { 2733 mKeyLeaseInterval = BigEndian::HostSwap32(aKeyLeaseInterval); 2734 } 2735 2736 uint32_t mLeaseInterval; 2737 uint32_t mKeyLeaseInterval; 2738 } OT_TOOL_PACKED_END; 2739 2740 /** 2741 * Implements Question format. 2742 * 2743 */ 2744 OT_TOOL_PACKED_BEGIN 2745 class Question 2746 { 2747 public: 2748 /** 2749 * Default constructor for Question 2750 * 2751 */ 2752 Question(void) = default; 2753 2754 /** 2755 * Constructor for Question. 2756 * 2757 */ Question(uint16_t aType,uint16_t aClass=ResourceRecord::kClassInternet)2758 explicit Question(uint16_t aType, uint16_t aClass = ResourceRecord::kClassInternet) 2759 { 2760 SetType(aType); 2761 SetClass(aClass); 2762 } 2763 2764 /** 2765 * Returns the type of the question. 2766 * 2767 * @returns The type of the question. 2768 * 2769 */ GetType(void) const2770 uint16_t GetType(void) const { return BigEndian::HostSwap16(mType); } 2771 2772 /** 2773 * Sets the type of the question. 2774 * 2775 * @param[in] aType The type of the question. 2776 * 2777 */ SetType(uint16_t aType)2778 void SetType(uint16_t aType) { mType = BigEndian::HostSwap16(aType); } 2779 2780 /** 2781 * Returns the class of the question. 2782 * 2783 * @returns The class of the question. 2784 * 2785 */ GetClass(void) const2786 uint16_t GetClass(void) const { return BigEndian::HostSwap16(mClass); } 2787 2788 /** 2789 * Sets the class of the question. 2790 * 2791 * @param[in] aClass The class of the question. 2792 * 2793 */ SetClass(uint16_t aClass)2794 void SetClass(uint16_t aClass) { mClass = BigEndian::HostSwap16(aClass); } 2795 2796 private: 2797 uint16_t mType; // The type of the data in question section. 2798 uint16_t mClass; // The class of the data in question section. 2799 } OT_TOOL_PACKED_END; 2800 2801 /** 2802 * Implements Zone section body for DNS Update (RFC 2136 - section 2.3). 2803 * 2804 */ 2805 OT_TOOL_PACKED_BEGIN 2806 class Zone : public Question 2807 { 2808 public: 2809 /** 2810 * Constructor for Zone. 2811 * 2812 * @param[in] aClass The class of the zone (default is `kClassInternet`). 2813 * 2814 */ Zone(uint16_t aClass=ResourceRecord::kClassInternet)2815 explicit Zone(uint16_t aClass = ResourceRecord::kClassInternet) 2816 : Question(ResourceRecord::kTypeSoa, aClass) 2817 { 2818 } 2819 } OT_TOOL_PACKED_END; 2820 2821 /** 2822 * @} 2823 * 2824 */ 2825 2826 } // namespace Dns 2827 2828 DefineCoreType(otDnsTxtEntry, Dns::TxtEntry); 2829 DefineCoreType(otDnsTxtEntryIterator, Dns::TxtEntry::Iterator); 2830 2831 } // namespace ot 2832 2833 #endif // DNS_HEADER_HPP_ 2834