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 * The @p aLabels buffer may be the same as @p aName for in-place label extraction. In this case, the 1032 * implementation avoids unnecessary character copies. 1033 * 1034 * @param[in] aName The name to extract labels from. 1035 * @param[in] aSuffixName The suffix name (e.g., can be domain name). 1036 * @param[out] aLabels Pointer to buffer to copy the extracted labels. 1037 * @param[in] aLabelsSize Size of @p aLabels buffer. 1038 * 1039 * @retval kErrorNone Successfully extracted the labels, @p aLabels is updated. 1040 * @retval kErrorParse @p aName does not contain @p aSuffixName. 1041 * @retval kErrorNoBufs Could not fit the labels in @p aLabelsSize. 1042 * 1043 */ 1044 static Error ExtractLabels(const char *aName, const char *aSuffixName, char *aLabels, uint16_t aLabelsSize); 1045 1046 /** 1047 * Extracts label(s) from a name by checking that it contains a given suffix name (e.g., suffix name can be 1048 * a domain name) and removing it. 1049 * 1050 * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise 1051 * `kErrorParse` is returned. 1052 * 1053 * The @p aLabels buffer may be the same as @p aName for in-place label extraction. In this case, the 1054 * implementation avoids unnecessary character copies. 1055 * 1056 * @tparam kLabelsBufferSize Size of the buffer string. 1057 * 1058 * @param[in] aName The name to extract labels from. 1059 * @param[in] aSuffixName The suffix name (e.g., can be domain name). 1060 * @param[out] aLabelsBuffer A buffer to copy the extracted labels. 1061 * 1062 * @retval kErrorNone Successfully extracted the labels, @p aLabels is updated. 1063 * @retval kErrorParse @p aName does not contain @p aSuffixName. 1064 * @retval kErrorNoBufs Could not fit the labels in @p aLabels. 1065 * 1066 */ 1067 template <uint16_t kLabelsBufferSize> ExtractLabels(const char * aName,const char * aSuffixName,char (& aLabels)[kLabelsBufferSize])1068 static Error ExtractLabels(const char *aName, const char *aSuffixName, char (&aLabels)[kLabelsBufferSize]) 1069 { 1070 return ExtractLabels(aName, aSuffixName, aLabels, kLabelsBufferSize); 1071 } 1072 1073 /** 1074 * Strips a given suffix name (e.g., a domain name) from a given DNS name string, updating it in place. 1075 * 1076 * First checks that @p Name ends with the given @p aSuffixName, otherwise `kErrorParse` is returned. 1077 * 1078 * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise 1079 * `kErrorParse` is returned. 1080 * 1081 * @tparam kNameBufferSize The size of name buffer. 1082 * 1083 * @param[in] aName The name buffer to strip the @p aSuffixName from. 1084 * @param[in] aSuffixName The suffix name (e.g., can be domain name). 1085 * 1086 * @retval kErrorNone Successfully stripped the suffix name from @p aName. 1087 * @retval kErrorParse @p aName does not contain @p aSuffixName. 1088 * 1089 */ StripName(char (& aName)[kNameBufferSize],const char * aSuffixName)1090 template <uint16_t kNameBufferSize> static Error StripName(char (&aName)[kNameBufferSize], const char *aSuffixName) 1091 { 1092 return ExtractLabels(aName, aSuffixName, aName, kNameBufferSize); 1093 } 1094 1095 /** 1096 * Tests if a DNS name is a sub-domain of a given domain. 1097 * 1098 * Both @p aName and @p aDomain can end without dot ('.'). 1099 * 1100 * @param[in] aName The dot-separated name. 1101 * @param[in] aDomain The dot-separated domain. 1102 * 1103 * @returns TRUE if the name is a sub-domain of @p aDomain, FALSE if is not. 1104 * 1105 */ 1106 static bool IsSubDomainOf(const char *aName, const char *aDomain); 1107 1108 /** 1109 * Tests if the two DNS name are the same domain. 1110 * 1111 * Both @p aDomain1 and @p aDomain2 can end without dot ('.'). 1112 * 1113 * @param[in] aDomain1 The dot-separated name. 1114 * @param[in] aDomain2 The dot-separated domain. 1115 * 1116 * @retval TRUE If the two DNS names are the same domain. 1117 * @retval FALSE If the two DNS names are not the same domain. 1118 * 1119 */ 1120 static bool IsSameDomain(const char *aDomain1, const char *aDomain2); 1121 1122 private: 1123 // The first 2 bits of the encoded label specifies label type. 1124 // 1125 // - Value 00 indicates normal text label (lower 6-bits indicates the label length). 1126 // - Value 11 indicates pointer label type (lower 14-bits indicates the pointer offset). 1127 // - Values 01,10 are reserved (RFC 6891 recommends to not use) 1128 1129 static constexpr uint8_t kLabelTypeMask = 0xc0; // 0b1100_0000 (first two bits) 1130 static constexpr uint8_t kTextLabelType = 0x00; // Text label type (00) 1131 static constexpr uint8_t kPointerLabelType = 0xc0; // Pointer label type - compressed name (11) 1132 1133 static constexpr uint8_t kMaxEncodedLength = 255; ///< Max length of an encoded name. 1134 1135 static constexpr uint16_t kPointerLabelTypeUint16 = 0xc000; // Pointer label type mask (first 2 bits). 1136 static constexpr uint16_t kPointerLabelOffsetMask = 0x3fff; // Mask for offset in a pointer label (lower 14 bits). 1137 1138 static constexpr bool kIsSingleLabel = true; // Used in `LabelIterator::CompareLabel()`. 1139 1140 struct LabelIterator 1141 { 1142 static constexpr uint16_t kUnsetNameEndOffset = 0; // Special value indicating `mNameEndOffset` is not yet set. 1143 LabelIteratorot::Dns::Name::LabelIterator1144 LabelIterator(const Message &aMessage, uint16_t aLabelOffset) 1145 : mMessage(aMessage) 1146 , mNextLabelOffset(aLabelOffset) 1147 , mNameEndOffset(kUnsetNameEndOffset) 1148 , mMinLabelOffset(aLabelOffset) 1149 { 1150 } 1151 IsEndOffsetSetot::Dns::Name::LabelIterator1152 bool IsEndOffsetSet(void) const { return (mNameEndOffset != kUnsetNameEndOffset); } 1153 Error GetNextLabel(void); 1154 Error ReadLabel(char *aLabelBuffer, uint8_t &aLabelLength, bool aAllowDotCharInLabel) const; 1155 bool CompareLabel(const char *&aName, bool aIsSingleLabel) const; 1156 bool CompareLabel(const LabelIterator &aOtherIterator) const; 1157 Error AppendLabel(Message &aMessage) const; 1158 1159 static bool CaseInsensitiveMatch(uint8_t aFirst, uint8_t aSecond); 1160 1161 const Message &mMessage; // Message to read labels from. 1162 uint16_t mLabelStartOffset; // Offset in `mMessage` to the first char of current label text. 1163 uint8_t mLabelLength; // Length of current label (number of chars). 1164 uint16_t mNextLabelOffset; // Offset in `mMessage` to the start of the next label. 1165 uint16_t mNameEndOffset; // Offset in `mMessage` to the byte after the end of domain name field. 1166 uint16_t mMinLabelOffset; // Offset in `mMessage` to the start of the earliest parsed label. 1167 }; 1168 Name(const char * aString,const Message * aMessage,uint16_t aOffset)1169 Name(const char *aString, const Message *aMessage, uint16_t aOffset) 1170 : mString(aString) 1171 , mMessage(aMessage) 1172 , mOffset(aOffset) 1173 { 1174 } 1175 1176 static bool CompareAndSkipLabels(const char *&aNamePtr, const char *aLabels, char aExpectedNextChar); 1177 static Error AppendLabel(const char *aLabel, uint8_t aLength, Message &aMessage); 1178 1179 const char *mString; // String containing the name or `nullptr` if name is not from string. 1180 const Message *mMessage; // Message containing the encoded name, or `nullptr` if `Name` is not from message. 1181 uint16_t mOffset; // Offset in `mMessage` to the start of name (used when name is from `mMessage`). 1182 }; 1183 1184 /** 1185 * Represents a TXT record entry representing a key/value pair (RFC 6763 - section 6.3). 1186 * 1187 */ 1188 class TxtEntry : public otDnsTxtEntry 1189 { 1190 friend class TxtRecord; 1191 1192 public: 1193 /** 1194 * Minimum length of key string (RFC 6763 - section 6.4). 1195 * 1196 */ 1197 static constexpr uint8_t kMinKeyLength = OT_DNS_TXT_KEY_MIN_LENGTH; 1198 1199 /** 1200 * Recommended max length of key string (RFC 6763 - section 6.4). 1201 * 1202 */ 1203 static constexpr uint8_t kMaxKeyLength = OT_DNS_TXT_KEY_MAX_LENGTH; 1204 1205 /** 1206 * Maximum length of TXT key string supported by `Iterator`. 1207 * 1208 * This is selected to be longer than recommended `kMaxKeyLength` to handle cases where longer keys are used. 1209 * 1210 */ 1211 static constexpr uint8_t kMaxIterKeyLength = OT_DNS_TXT_KEY_ITER_MAX_LENGTH; 1212 1213 /** 1214 * Represents an iterator for TXT record entries (key/value pairs). 1215 * 1216 */ 1217 class Iterator : public otDnsTxtEntryIterator 1218 { 1219 friend class TxtEntry; 1220 1221 public: 1222 /** 1223 * Initializes a TXT record iterator. 1224 * 1225 * The buffer pointer @p aTxtData and its content MUST persist and remain unchanged while the iterator object 1226 * is being used. 1227 * 1228 * @param[in] aTxtData A pointer to buffer containing the encoded TXT data. 1229 * @param[in] aTxtDataLength The length (number of bytes) of @p aTxtData. 1230 * 1231 */ 1232 void Init(const uint8_t *aTxtData, uint16_t aTxtDataLength); 1233 1234 /** 1235 * Parses the TXT data from the `Iterator` and gets the next TXT record entry (key/value pair). 1236 * 1237 * The `Iterator` instance MUST be initialized using `Init()` before calling this method and the TXT data 1238 * buffer used to initialize the iterator MUST persist and remain unchanged. 1239 * 1240 * If the parsed key string length is smaller than or equal to `kMaxIterKeyLength` the key string is returned 1241 * in `mKey` in @p aEntry. But if the key is longer, then `mKey` is set to `nullptr` the entire encoded TXT 1242 * entry is returned in `mValue` and `mValueLength`. 1243 * 1244 * @param[out] aEntry A reference to a `TxtEntry` to output the parsed/read entry. 1245 * 1246 * @retval kErrorNone The next entry was parsed successfully. @p aEntry is updated. 1247 * @retval kErrorNotFound No more entries in TXT data. 1248 * @retval kErrorParse The TXT data from `Iterator` is not well-formed. 1249 * 1250 */ 1251 Error GetNextEntry(TxtEntry &aEntry); 1252 1253 private: 1254 static constexpr uint8_t kIndexTxtLength = 0; 1255 static constexpr uint8_t kIndexTxtPosition = 1; 1256 GetTxtData(void) const1257 const char *GetTxtData(void) const { return reinterpret_cast<const char *>(mPtr); } SetTxtData(const uint8_t * aTxtData)1258 void SetTxtData(const uint8_t *aTxtData) { mPtr = aTxtData; } GetTxtDataLength(void) const1259 uint16_t GetTxtDataLength(void) const { return mData[kIndexTxtLength]; } SetTxtDataLength(uint16_t aLength)1260 void SetTxtDataLength(uint16_t aLength) { mData[kIndexTxtLength] = aLength; } GetTxtDataPosition(void) const1261 uint16_t GetTxtDataPosition(void) const { return mData[kIndexTxtPosition]; } SetTxtDataPosition(uint16_t aValue)1262 void SetTxtDataPosition(uint16_t aValue) { mData[kIndexTxtPosition] = aValue; } IncreaseTxtDataPosition(uint16_t aIncrement)1263 void IncreaseTxtDataPosition(uint16_t aIncrement) { mData[kIndexTxtPosition] += aIncrement; } GetKeyBuffer(void)1264 char *GetKeyBuffer(void) { return mChar; } GetTxtDataEnd(void) const1265 const char *GetTxtDataEnd(void) const { return GetTxtData() + GetTxtDataLength(); } 1266 }; 1267 1268 /** 1269 * This is the default constructor for a `TxtEntry` object. 1270 * 1271 */ 1272 TxtEntry(void) = default; 1273 1274 /** 1275 * Initializes a `TxtEntry` object. 1276 * 1277 * @param[in] aKey A pointer to the key string. 1278 * @param[in] aValue A pointer to a buffer containing the value. 1279 * @param[in] aValueLength Number of bytes in @p aValue buffer. 1280 * 1281 */ TxtEntry(const char * aKey,const uint8_t * aValue,uint8_t aValueLength)1282 TxtEntry(const char *aKey, const uint8_t *aValue, uint8_t aValueLength) { Init(aKey, aValue, aValueLength); } 1283 1284 /** 1285 * Initializes a `TxtEntry` object. 1286 * 1287 * @param[in] aKey A pointer to the key string. 1288 * @param[in] aValue A pointer to a buffer containing the value. 1289 * @param[in] aValueLength Number of bytes in @p aValue buffer. 1290 * 1291 */ Init(const char * aKey,const uint8_t * aValue,uint8_t aValueLength)1292 void Init(const char *aKey, const uint8_t *aValue, uint8_t aValueLength) 1293 { 1294 mKey = aKey; 1295 mValue = aValue; 1296 mValueLength = aValueLength; 1297 } 1298 1299 /** 1300 * Encodes and appends the `TxtEntry` to a message. 1301 * 1302 * @param[in] aMessage The message to append to. 1303 * 1304 * @retval kErrorNone Entry was appended successfully to @p aMessage. 1305 * @retval kErrorInvalidArgs The `TxTEntry` info is not valid. 1306 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 1307 * 1308 */ 1309 Error AppendTo(Message &aMessage) const; 1310 1311 /** 1312 * Appends an array of `TxtEntry` items to a message. 1313 * 1314 * @param[in] aEntries A pointer to array of `TxtEntry` items. 1315 * @param[in] aNumEntries The number of entries in @p aEntries array. 1316 * @param[in] aMessage The message to append to. 1317 * 1318 * @retval kErrorNone Entries appended successfully to @p aMessage. 1319 * @retval kErrorInvalidArgs The `TxTEntry` info is not valid. 1320 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 1321 * 1322 */ 1323 static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, Message &aMessage); 1324 1325 /** 1326 * Appends an array of `TxtEntry` items to a `MutableData` buffer. 1327 * 1328 * @param[in] aEntries A pointer to array of `TxtEntry` items. 1329 * @param[in] aNumEntries The number of entries in @p aEntries array. 1330 * @param[in] aData The `MutableData` to append in. 1331 * 1332 * @retval kErrorNone Entries appended successfully . 1333 * @retval kErrorInvalidArgs The `TxTEntry` info is not valid. 1334 * @retval kErrorNoBufs Insufficient available buffers. 1335 * 1336 */ 1337 static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, MutableData<kWithUint16Length> &aData); 1338 1339 private: 1340 Error AppendTo(Appender &aAppender) const; 1341 static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, Appender &aAppender); 1342 1343 static constexpr uint8_t kMaxKeyValueEncodedSize = 255; 1344 static constexpr char kKeyValueSeparator = '='; 1345 }; 1346 1347 /** 1348 * Implements Resource Record (RR) body format. 1349 * 1350 */ 1351 OT_TOOL_PACKED_BEGIN 1352 class ResourceRecord 1353 { 1354 friend class OptRecord; 1355 1356 public: 1357 // Resource Record Types. 1358 static constexpr uint16_t kTypeZero = 0; ///< Zero as special indicator for the SIG RR (SIG(0) from RFC 2931). 1359 static constexpr uint16_t kTypeA = 1; ///< Address record (IPv4). 1360 static constexpr uint16_t kTypeSoa = 6; ///< Start of (zone of) authority. 1361 static constexpr uint16_t kTypeCname = 5; ///< CNAME record. 1362 static constexpr uint16_t kTypePtr = 12; ///< PTR record. 1363 static constexpr uint16_t kTypeTxt = 16; ///< TXT record. 1364 static constexpr uint16_t kTypeSig = 24; ///< SIG record. 1365 static constexpr uint16_t kTypeKey = 25; ///< KEY record. 1366 static constexpr uint16_t kTypeAaaa = 28; ///< IPv6 address record. 1367 static constexpr uint16_t kTypeSrv = 33; ///< SRV locator record. 1368 static constexpr uint16_t kTypeOpt = 41; ///< Option record. 1369 static constexpr uint16_t kTypeNsec = 47; ///< NSEC record. 1370 static constexpr uint16_t kTypeAny = 255; ///< ANY record. 1371 1372 // Resource Record Class Codes. 1373 static constexpr uint16_t kClassInternet = 1; ///< Class code Internet (IN). 1374 static constexpr uint16_t kClassNone = 254; ///< Class code None (NONE) - RFC 2136. 1375 static constexpr uint16_t kClassAny = 255; ///< Class code Any (ANY). 1376 1377 /** 1378 * Initializes the resource record by setting its type and class. 1379 * 1380 * Only sets the type and class fields. Other fields (TTL and length) remain unchanged/uninitialized. 1381 * 1382 * @param[in] aType The type of the resource record. 1383 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1384 * 1385 */ Init(uint16_t aType,uint16_t aClass=kClassInternet)1386 void Init(uint16_t aType, uint16_t aClass = kClassInternet) 1387 { 1388 SetType(aType); 1389 SetClass(aClass); 1390 } 1391 1392 /** 1393 * Indicates whether the resources records matches a given type and class code. 1394 * 1395 * @param[in] aType The resource record type to compare with. 1396 * @param[in] aClass The resource record class code to compare with (default is `kClassInternet`). 1397 * 1398 * @returns TRUE if the resources records matches @p aType and @p aClass, FALSE otherwise. 1399 * 1400 */ Matches(uint16_t aType,uint16_t aClass=kClassInternet) const1401 bool Matches(uint16_t aType, uint16_t aClass = kClassInternet) const 1402 { 1403 return (mType == BigEndian::HostSwap16(aType)) && (mClass == BigEndian::HostSwap16(aClass)); 1404 } 1405 1406 /** 1407 * Returns the type of the resource record. 1408 * 1409 * @returns The type of the resource record. 1410 * 1411 */ GetType(void) const1412 uint16_t GetType(void) const { return BigEndian::HostSwap16(mType); } 1413 1414 /** 1415 * Sets the type of the resource record. 1416 * 1417 * @param[in] aType The type of the resource record. 1418 * 1419 */ SetType(uint16_t aType)1420 void SetType(uint16_t aType) { mType = BigEndian::HostSwap16(aType); } 1421 1422 /** 1423 * Returns the class of the resource record. 1424 * 1425 * @returns The class of the resource record. 1426 * 1427 */ GetClass(void) const1428 uint16_t GetClass(void) const { return BigEndian::HostSwap16(mClass); } 1429 1430 /** 1431 * Sets the class of the resource record. 1432 * 1433 * @param[in] aClass The class of the resource record. 1434 * 1435 */ SetClass(uint16_t aClass)1436 void SetClass(uint16_t aClass) { mClass = BigEndian::HostSwap16(aClass); } 1437 1438 /** 1439 * Returns the time to live field of the resource record. 1440 * 1441 * @returns The time to live field of the resource record. 1442 * 1443 */ GetTtl(void) const1444 uint32_t GetTtl(void) const { return BigEndian::HostSwap32(mTtl); } 1445 1446 /** 1447 * Sets the time to live field of the resource record. 1448 * 1449 * @param[in] aTtl The time to live field of the resource record. 1450 * 1451 */ SetTtl(uint32_t aTtl)1452 void SetTtl(uint32_t aTtl) { mTtl = BigEndian::HostSwap32(aTtl); } 1453 1454 /** 1455 * Returns the length of the resource record data. 1456 * 1457 * @returns The length of the resource record data. 1458 * 1459 */ GetLength(void) const1460 uint16_t GetLength(void) const { return BigEndian::HostSwap16(mLength); } 1461 1462 /** 1463 * Sets the length of the resource record data. 1464 * 1465 * @param[in] aLength The length of the resource record data. 1466 * 1467 */ SetLength(uint16_t aLength)1468 void SetLength(uint16_t aLength) { mLength = BigEndian::HostSwap16(aLength); } 1469 1470 /** 1471 * Returns the size of (number of bytes) in resource record and its data RDATA section (excluding the 1472 * name field). 1473 * 1474 * @returns Size (number of bytes) of resource record and its data section (excluding the name field) 1475 * 1476 */ GetSize(void) const1477 uint32_t GetSize(void) const { return sizeof(ResourceRecord) + GetLength(); } 1478 1479 /** 1480 * Parses and skips over a given number of resource records in a message from a given offset. 1481 * 1482 * @param[in] aMessage The message from which to parse/read the resource records. `aMessage.GetOffset()` 1483 * MUST point to the start of DNS header. 1484 * @param[in,out] aOffset On input the offset in @p aMessage pointing to the start of the first record. 1485 * On exit (when parsed successfully), @p aOffset is updated to point to the byte after 1486 * the last parsed record. 1487 * @param[in] aNumRecords Number of resource records to parse. 1488 * 1489 * @retval kErrorNone Parsed records successfully. @p aOffset is updated. 1490 * @retval kErrorParse Could not parse the records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1491 * 1492 */ 1493 static Error ParseRecords(const Message &aMessage, uint16_t &aOffset, uint16_t aNumRecords); 1494 1495 /** 1496 * Searches in a given message to find the first resource record matching a given record name. 1497 * 1498 * @param[in] aMessage The message in which to search for a matching resource record. 1499 * `aMessage.GetOffset()` MUST point to the start of DNS header. 1500 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the first record. 1501 * On exit, if a matching record is found, @p aOffset is updated to point to the byte 1502 * after the record name. 1503 * If a matching record could not be found, @p aOffset is updated to point to the byte 1504 * after the last record that was checked. 1505 * @param[in,out] aNumRecords On input, the maximum number of records to check (starting from @p aOffset). 1506 * On exit and if a matching record is found, @p aNumRecords is updated to give the 1507 * number of remaining records after @p aOffset (excluding the matching record). 1508 * @param[in] aName The record name to match against. 1509 * 1510 * @retval kErrorNone A matching record was found. @p aOffset, @p aNumRecords are updated. 1511 * @retval kErrorNotFound A matching record could not be found. @p aOffset and @p aNumRecords are updated. 1512 * @retval kErrorParse Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1513 * 1514 */ 1515 static Error FindRecord(const Message &aMessage, uint16_t &aOffset, uint16_t &aNumRecords, const Name &aName); 1516 1517 /** 1518 * This template static method searches in a message to find the i-th occurrence of resource records of specific 1519 * type with a given record name and if found, reads the record from the message. 1520 * 1521 * Searches in @p aMessage starting from @p aOffset up to maximum of @p aNumRecords, for the 1522 * `(aIndex+1)`th occurrence of a resource record of `RecordType` with record name @p aName. 1523 * 1524 * On success (i.e., when a matching record is found and read from the message), @p aOffset is updated to point 1525 * to after the last byte read from the message and copied into @p aRecord. This allows the caller to read any 1526 * remaining fields in the record data. 1527 * 1528 * @tparam RecordType The resource record type (i.e., a sub-class of `ResourceRecord`). 1529 * 1530 * @param[in] aMessage The message to search within for matching resource records. 1531 * `aMessage.GetOffset()` MUST point to the start of DNS header. 1532 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the start of the first record. 1533 * On exit and only if a matching record is found, @p aOffset is updated to point to 1534 * the last read byte in the record (allowing caller to read any remaining fields in 1535 * the record data from the message). 1536 * @param[in] aNumRecords The maximum number of records to check (starting from @p aOffset). 1537 * @param[in] aIndex The matching record index to find. @p aIndex value of zero returns the first 1538 * matching record. 1539 * @param[in] aName The record name to match against. 1540 * @param[in] aRecord A reference to a record object to read a matching record into. 1541 * If a matching record is found, `sizeof(RecordType)` bytes from @p aMessage are 1542 * read and copied into @p aRecord. 1543 * 1544 * @retval kErrorNone A matching record was found. @p aOffset is updated. 1545 * @retval kErrorNotFound A matching record could not be found. 1546 * @retval kErrorParse Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1547 * 1548 */ 1549 template <class RecordType> FindRecord(const Message & aMessage,uint16_t & aOffset,uint16_t aNumRecords,uint16_t aIndex,const Name & aName,RecordType & aRecord)1550 static Error FindRecord(const Message &aMessage, 1551 uint16_t &aOffset, 1552 uint16_t aNumRecords, 1553 uint16_t aIndex, 1554 const Name &aName, 1555 RecordType &aRecord) 1556 { 1557 return FindRecord(aMessage, aOffset, aNumRecords, aIndex, aName, RecordType::kType, aRecord, 1558 sizeof(RecordType)); 1559 } 1560 1561 /** 1562 * This template static method tries to read a resource record of a given type from a message. If the record type 1563 * does not matches the type, it skips over the record. 1564 * 1565 * Requires the record name to be already parsed/read from the message. On input, @p aOffset should 1566 * point to the start of the `ResourceRecord` fields (type, class, TTL, data length) in @p aMessage. 1567 * 1568 * Verifies that the record is well-formed in the message. It then reads the record type and compares 1569 * it with `RecordType::kType` and ensures that the record size is at least `sizeof(RecordType)`. If it all matches, 1570 * the record is read into @p aRecord. 1571 * 1572 * On success (i.e., when a matching record is read from the message), the @p aOffset is updated to point to after 1573 * the last byte read from the message and copied into @p aRecord and not necessarily the end of the record. 1574 * Depending on the `RecordType` format, there may still be more data bytes left in the record to be read. For 1575 * example, when reading a SRV record using `SrvRecord` type, @p aOffset would point to after the last field in 1576 * `SrvRecord` which is the start of "target host domain name" field. 1577 * 1578 * @tparam RecordType The resource record type (i.e., a sub-class of `ResourceRecord`). 1579 * 1580 * @param[in] aMessage The message from which to read the record. 1581 * @param[in,out] aOffset On input, the offset in @p aMessage pointing to the byte after the record name. 1582 * On exit, if a matching record is read, @p aOffset is updated to point to the last 1583 * read byte in the record. 1584 * If a matching record could not be read, @p aOffset is updated to point to the byte 1585 * after the entire record (skipping over the record). 1586 * @param[out] aRecord A reference to a record to read a matching record into. 1587 * If a matching record is found, `sizeof(RecordType)` bytes from @p aMessage are 1588 * read and copied into @p aRecord. 1589 * 1590 * @retval kErrorNone A matching record was read successfully. @p aOffset, and @p aRecord are updated. 1591 * @retval kErrorNotFound A matching record could not be found. @p aOffset is updated. 1592 * @retval kErrorParse Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage). 1593 * 1594 */ ReadRecord(const Message & aMessage,uint16_t & aOffset,RecordType & aRecord)1595 template <class RecordType> static Error ReadRecord(const Message &aMessage, uint16_t &aOffset, RecordType &aRecord) 1596 { 1597 return ReadRecord(aMessage, aOffset, RecordType::kType, aRecord, sizeof(RecordType)); 1598 } 1599 1600 protected: 1601 Error ReadName(const Message &aMessage, 1602 uint16_t &aOffset, 1603 uint16_t aStartOffset, 1604 char *aNameBuffer, 1605 uint16_t aNameBufferSize, 1606 bool aSkipRecord) const; 1607 Error SkipRecord(const Message &aMessage, uint16_t &aOffset) const; 1608 1609 private: 1610 static constexpr uint16_t kType = kTypeAny; // This is intended for used by `ReadRecord<RecordType>()` only. 1611 1612 static Error FindRecord(const Message &aMessage, 1613 uint16_t &aOffset, 1614 uint16_t aNumRecords, 1615 uint16_t aIndex, 1616 const Name &aName, 1617 uint16_t aType, 1618 ResourceRecord &aRecord, 1619 uint16_t aMinRecordSize); 1620 1621 static Error ReadRecord(const Message &aMessage, 1622 uint16_t &aOffset, 1623 uint16_t aType, 1624 ResourceRecord &aRecord, 1625 uint16_t aMinRecordSize); 1626 1627 Error CheckRecord(const Message &aMessage, uint16_t aOffset) const; 1628 Error ReadFrom(const Message &aMessage, uint16_t aOffset); 1629 1630 uint16_t mType; // The type of the data in RDATA section. 1631 uint16_t mClass; // The class of the data in RDATA section. 1632 uint32_t mTtl; // Specifies the maximum time that the resource record may be cached. 1633 uint16_t mLength; // The length of RDATA section in bytes. 1634 1635 } OT_TOOL_PACKED_END; 1636 1637 /** 1638 * Implements Resource Record body format of A type. 1639 * 1640 */ 1641 OT_TOOL_PACKED_BEGIN 1642 class ARecord : public ResourceRecord 1643 { 1644 public: 1645 static constexpr uint16_t kType = kTypeA; ///< The A record type. 1646 1647 /** 1648 * Initializes the A Resource Record by setting its type, class, and length. 1649 * 1650 * Other record fields (TTL, address) remain unchanged/uninitialized. 1651 * 1652 */ Init(void)1653 void Init(void) 1654 { 1655 ResourceRecord::Init(kTypeA); 1656 SetLength(sizeof(Ip4::Address)); 1657 } 1658 1659 /** 1660 * Sets the IPv4 address of the resource record. 1661 * 1662 * @param[in] aAddress The IPv4 address of the resource record. 1663 * 1664 */ SetAddress(const Ip4::Address & aAddress)1665 void SetAddress(const Ip4::Address &aAddress) { mAddress = aAddress; } 1666 1667 /** 1668 * Returns the reference to IPv4 address of the resource record. 1669 * 1670 * @returns The reference to IPv4 address of the resource record. 1671 * 1672 */ GetAddress(void) const1673 const Ip4::Address &GetAddress(void) const { return mAddress; } 1674 1675 private: 1676 Ip4::Address mAddress; // IPv4 Address of A Resource Record. 1677 } OT_TOOL_PACKED_END; 1678 1679 /** 1680 * Implements Resource Record body format of CNAME type. 1681 * 1682 */ 1683 OT_TOOL_PACKED_BEGIN 1684 class CnameRecord : public ResourceRecord 1685 { 1686 public: 1687 static constexpr uint16_t kType = kTypeCname; ///< The CNAME record type. 1688 1689 /** 1690 * Initializes the CNAME Resource Record by setting its type and class. 1691 * 1692 * Other record fields (TTL, length) remain unchanged/uninitialized. 1693 * 1694 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1695 * 1696 */ Init(uint16_t aClass=kClassInternet)1697 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeCname, aClass); } 1698 1699 /** 1700 * Parses and reads the CNAME alias name from a message. 1701 * 1702 * Also verifies that the CNAME record is well-formed (e.g., the record data length `GetLength()` 1703 * matches the CNAME encoded name). 1704 * 1705 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1706 * DNS header. 1707 * @param[in,out] aOffset On input, the offset in @p aMessage to start of CNAME name field. 1708 * On exit when successfully read, @p aOffset is updated to point to the byte 1709 * after the entire PTR record (skipping over the record). 1710 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 1711 * (MUST NOT be `nullptr`). 1712 * @param[in] aNameBufferSize The size of @p aNameBuffer. 1713 * 1714 * @retval kErrorNone The CNAME name was read successfully. @p aOffset and @p aNameBuffer are updated. 1715 * @retval kErrorParse The CNAME record in @p aMessage could not be parsed (invalid format). 1716 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 1717 * 1718 */ ReadCanonicalName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const1719 Error ReadCanonicalName(const Message &aMessage, 1720 uint16_t &aOffset, 1721 char *aNameBuffer, 1722 uint16_t aNameBufferSize) const 1723 { 1724 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(CnameRecord), 1725 aNameBuffer, aNameBufferSize, /* aSkipRecord */ true); 1726 } 1727 1728 } OT_TOOL_PACKED_END; 1729 1730 /** 1731 * Implements Resource Record body format of PTR type. 1732 * 1733 */ 1734 OT_TOOL_PACKED_BEGIN 1735 class PtrRecord : public ResourceRecord 1736 { 1737 public: 1738 static constexpr uint16_t kType = kTypePtr; ///< The PTR record type. 1739 1740 /** 1741 * Initializes the PTR Resource Record by setting its type and class. 1742 * 1743 * Other record fields (TTL, length) remain unchanged/uninitialized. 1744 * 1745 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1746 * 1747 */ Init(uint16_t aClass=kClassInternet)1748 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypePtr, aClass); } 1749 1750 /** 1751 * Parses and reads the PTR name from a message. 1752 * 1753 * Also verifies that the PTR record is well-formed (e.g., the record data length `GetLength()` matches 1754 * the PTR encoded name). 1755 * 1756 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1757 * DNS header. 1758 * @param[in,out] aOffset On input, the offset in @p aMessage to start of PTR name field. 1759 * On exit when successfully read, @p aOffset is updated to point to the byte 1760 * after the entire PTR record (skipping over the record). 1761 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 1762 * (MUST NOT be `nullptr`). 1763 * @param[in] aNameBufferSize The size of @p aNameBuffer. 1764 * 1765 * @retval kErrorNone The PTR name was read successfully. @p aOffset and @p aNameBuffer are updated. 1766 * @retval kErrorParse The PTR record in @p aMessage could not be parsed (invalid format). 1767 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 1768 * 1769 */ ReadPtrName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const1770 Error ReadPtrName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize) const 1771 { 1772 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(PtrRecord), aNameBuffer, 1773 aNameBufferSize, 1774 /* aSkipRecord */ true); 1775 } 1776 1777 /** 1778 * Parses and reads the PTR name from a message. 1779 * 1780 * Also verifies that the PTR record is well-formed (e.g., the record data length `GetLength()` matches 1781 * the PTR encoded name). 1782 * 1783 * Unlike the previous method which reads the entire PTR name into a single char buffer, this method reads the 1784 * first label separately and into a different buffer @p aLabelBuffer and the rest of the name into @p aNameBuffer. 1785 * The @p aNameBuffer can be set to `nullptr` if the caller is only interested in the first label. This method is 1786 * intended for "Service Instance Name" where first label (`<Instance>` portion) can be a user-friendly string and 1787 * can contain dot character. 1788 * 1789 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1790 * DNS header. 1791 * @param[in,out] aOffset On input, the offset in @p aMessage to the start of PTR name field. 1792 * On exit, when successfully read, @p aOffset is updated to point to the byte 1793 * after the entire PTR record (skipping over the record). 1794 * @param[out] aLabelBuffer A pointer to a char array to output the first label as a null-terminated C 1795 * string (MUST NOT be `nullptr`). 1796 * @param[in] aLabelBufferSize The size of @p aLabelBuffer. 1797 * @param[out] aNameBuffer A pointer to a char array to output the rest of name (after first label). Can 1798 * be `nullptr` if caller is only interested in the first label. 1799 * @param[in] aNameBufferSize The size of @p aNameBuffer. 1800 * 1801 * @retval kErrorNone The PTR name was read successfully. @p aOffset, @aLabelBuffer and @aNameBuffer are updated. 1802 * @retval kErrorParse The PTR record in @p aMessage could not be parsed (invalid format). 1803 * @retval kErrorNoBufs Either label or name could not fit in the related char buffers. 1804 * 1805 */ 1806 Error ReadPtrName(const Message &aMessage, 1807 uint16_t &aOffset, 1808 char *aLabelBuffer, 1809 uint8_t aLabelBufferSize, 1810 char *aNameBuffer, 1811 uint16_t aNameBufferSize) const; 1812 1813 /** 1814 * Parses and reads the PTR name from a message. 1815 * 1816 * This is a template variation of the previous method with name and label buffer sizes as template parameters. 1817 * 1818 * @tparam kLabelBufferSize The size of label buffer. 1819 * @tparam kNameBufferSize The size of name buffer. 1820 * 1821 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 1822 * DNS header. 1823 * @param[in,out] aOffset On input, the offset in @p aMessage to the start of PTR name field. 1824 * On exit, when successfully read, @p aOffset is updated to point to the byte 1825 * after the entire PTR record (skipping over the record). 1826 * @param[out] aLabelBuffer A char array buffer to output the first label as a null-terminated C string. 1827 * @param[out] aNameBuffer A char array to output the rest of name (after first label). 1828 * 1829 * @retval kErrorNone The PTR name was read successfully. @p aOffset, @aLabelBuffer and @aNameBuffer are updated. 1830 * @retval kErrorParse The PTR record in @p aMessage could not be parsed (invalid format). 1831 * @retval kErrorNoBufs Either label or name could not fit in the related given buffers. 1832 * 1833 */ 1834 template <uint16_t kLabelBufferSize, uint16_t kNameBufferSize> ReadPtrName(const Message & aMessage,uint16_t & aOffset,char (& aLabelBuffer)[kLabelBufferSize],char (& aNameBuffer)[kNameBufferSize]) const1835 Error ReadPtrName(const Message &aMessage, 1836 uint16_t &aOffset, 1837 char (&aLabelBuffer)[kLabelBufferSize], 1838 char (&aNameBuffer)[kNameBufferSize]) const 1839 { 1840 return ReadPtrName(aMessage, aOffset, aLabelBuffer, kLabelBufferSize, aNameBuffer, kNameBufferSize); 1841 } 1842 1843 } OT_TOOL_PACKED_END; 1844 1845 /** 1846 * Implements Resource Record body format of TXT type. 1847 * 1848 */ 1849 OT_TOOL_PACKED_BEGIN 1850 class TxtRecord : public ResourceRecord 1851 { 1852 public: 1853 static constexpr uint16_t kType = kTypeTxt; ///< The TXT record type. 1854 1855 /** 1856 * Initializes the TXT Resource Record by setting its type and class. 1857 * 1858 * Other record fields (TTL, length) remain unchanged/uninitialized. 1859 * 1860 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1861 * 1862 */ Init(uint16_t aClass=kClassInternet)1863 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeTxt, aClass); } 1864 1865 /** 1866 * Parses and reads the TXT record data from a message. 1867 * 1868 * Also checks if the TXT data is well-formed by calling `VerifyTxtData()` when it is successfully 1869 * read. 1870 * 1871 * @param[in] aMessage The message to read from. 1872 * @param[in,out] aOffset On input, the offset in @p aMessage to start of TXT record data. 1873 * On exit when successfully read, @p aOffset is updated to point to the byte 1874 * after the entire TXT record (skipping over the record). 1875 * @param[out] aTxtBuffer A pointer to a byte array to output the read TXT data. 1876 * @param[in,out] aTxtBufferSize On input, the size of @p aTxtBuffer (max bytes that can be read). 1877 * On exit, @p aTxtBufferSize gives number of bytes written to @p aTxtBuffer. 1878 * 1879 * @retval kErrorNone The TXT data was read successfully. @p aOffset, @p aTxtBuffer and @p aTxtBufferSize 1880 * are updated. 1881 * @retval kErrorParse The TXT record in @p aMessage could not be parsed (invalid format). 1882 * @retval kErrorNoBufs TXT data could not fit in @p aTxtBufferSize bytes. TXT data is still partially read 1883 * into @p aTxtBuffer up to its size and @p aOffset is updated to skip over the full 1884 * TXT record. 1885 * 1886 */ 1887 Error ReadTxtData(const Message &aMessage, uint16_t &aOffset, uint8_t *aTxtBuffer, uint16_t &aTxtBufferSize) const; 1888 1889 /** 1890 * Tests if a buffer contains valid encoded TXT data. 1891 * 1892 * @param[in] aTxtData The TXT data buffer. 1893 * @param[in] aTxtLength The length of the TXT data buffer. 1894 * @param[in] aAllowEmpty True if zero-length TXT data is allowed. 1895 * 1896 * @returns TRUE if @p aTxtData contains valid encoded TXT data, FALSE if not. 1897 * 1898 */ 1899 static bool VerifyTxtData(const uint8_t *aTxtData, uint16_t aTxtLength, bool aAllowEmpty); 1900 1901 } OT_TOOL_PACKED_END; 1902 1903 /** 1904 * Implements Resource Record body format of AAAA type. 1905 * 1906 */ 1907 OT_TOOL_PACKED_BEGIN 1908 class AaaaRecord : public ResourceRecord 1909 { 1910 public: 1911 static constexpr uint16_t kType = kTypeAaaa; ///< The AAAA record type. 1912 1913 /** 1914 * Initializes the AAAA Resource Record by setting its type, class, and length. 1915 * 1916 * Other record fields (TTL, address) remain unchanged/uninitialized. 1917 * 1918 */ Init(void)1919 void Init(void) 1920 { 1921 ResourceRecord::Init(kTypeAaaa); 1922 SetLength(sizeof(Ip6::Address)); 1923 } 1924 1925 /** 1926 * Tells whether this is a valid AAAA record. 1927 * 1928 * @returns A boolean indicates whether this is a valid AAAA record. 1929 * 1930 */ 1931 bool IsValid(void) const; 1932 1933 /** 1934 * Sets the IPv6 address of the resource record. 1935 * 1936 * @param[in] aAddress The IPv6 address of the resource record. 1937 * 1938 */ SetAddress(const Ip6::Address & aAddress)1939 void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; } 1940 1941 /** 1942 * Returns the reference to IPv6 address of the resource record. 1943 * 1944 * @returns The reference to IPv6 address of the resource record. 1945 * 1946 */ GetAddress(void) const1947 const Ip6::Address &GetAddress(void) const { return mAddress; } 1948 1949 private: 1950 Ip6::Address mAddress; // IPv6 Address of AAAA Resource Record. 1951 } OT_TOOL_PACKED_END; 1952 1953 /** 1954 * Implements Resource Record body format of SRV type (RFC 2782). 1955 * 1956 */ 1957 OT_TOOL_PACKED_BEGIN 1958 class SrvRecord : public ResourceRecord 1959 { 1960 public: 1961 static constexpr uint16_t kType = kTypeSrv; ///< The SRV record type. 1962 1963 /** 1964 * Initializes the SRV Resource Record by settings its type and class. 1965 * 1966 * Other record fields (TTL, length, propriety, weight, port, ...) remain unchanged/uninitialized. 1967 * 1968 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 1969 * 1970 */ Init(uint16_t aClass=kClassInternet)1971 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeSrv, aClass); } 1972 1973 /** 1974 * Returns the SRV record's priority value. 1975 * 1976 * @returns The priority value. 1977 * 1978 */ GetPriority(void) const1979 uint16_t GetPriority(void) const { return BigEndian::HostSwap16(mPriority); } 1980 1981 /** 1982 * Sets the SRV record's priority value. 1983 * 1984 * @param[in] aPriority The priority value. 1985 * 1986 */ SetPriority(uint16_t aPriority)1987 void SetPriority(uint16_t aPriority) { mPriority = BigEndian::HostSwap16(aPriority); } 1988 1989 /** 1990 * Returns the SRV record's weight value. 1991 * 1992 * @returns The weight value. 1993 * 1994 */ GetWeight(void) const1995 uint16_t GetWeight(void) const { return BigEndian::HostSwap16(mWeight); } 1996 1997 /** 1998 * Sets the SRV record's weight value. 1999 * 2000 * @param[in] aWeight The weight value. 2001 * 2002 */ SetWeight(uint16_t aWeight)2003 void SetWeight(uint16_t aWeight) { mWeight = BigEndian::HostSwap16(aWeight); } 2004 2005 /** 2006 * Returns the SRV record's port number on the target host for this service. 2007 * 2008 * @returns The port number. 2009 * 2010 */ GetPort(void) const2011 uint16_t GetPort(void) const { return BigEndian::HostSwap16(mPort); } 2012 2013 /** 2014 * Sets the SRV record's port number on the target host for this service. 2015 * 2016 * @param[in] aPort The port number. 2017 * 2018 */ SetPort(uint16_t aPort)2019 void SetPort(uint16_t aPort) { mPort = BigEndian::HostSwap16(aPort); } 2020 2021 /** 2022 * Parses and reads the SRV target host name from a message. 2023 * 2024 * Also verifies that the SRV record is well-formed (e.g., the record data length `GetLength()` matches 2025 * the SRV encoded name). 2026 * 2027 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 2028 * DNS header. 2029 * @param[in,out] aOffset On input, the offset in @p aMessage to start of target host name field. 2030 * On exit when successfully read, @p aOffset is updated to point to the byte 2031 * after the entire SRV record (skipping over the record). 2032 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 2033 * (MUST NOT be `nullptr`). 2034 * @param[in] aNameBufferSize The size of @p aNameBuffer. 2035 * 2036 * @retval kErrorNone The host name was read successfully. @p aOffset and @p aNameBuffer are updated. 2037 * @retval kErrorParse The SRV record in @p aMessage could not be parsed (invalid format). 2038 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 2039 * 2040 */ ReadTargetHostName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const2041 Error ReadTargetHostName(const Message &aMessage, 2042 uint16_t &aOffset, 2043 char *aNameBuffer, 2044 uint16_t aNameBufferSize) const 2045 { 2046 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(SrvRecord), aNameBuffer, 2047 aNameBufferSize, 2048 /* aSkipRecord */ true); 2049 } 2050 2051 /** 2052 * Parses and reads the SRV target host name from a message. 2053 * 2054 * Also verifies that the SRV record is well-formed (e.g., the record data length `GetLength()` matches 2055 * the SRV encoded name). 2056 * 2057 * @tparam kNameBufferSize Size of the name buffer. 2058 * 2059 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of 2060 * DNS header. 2061 * @param[in,out] aOffset On input, the offset in @p aMessage to start of target host name field. 2062 * On exit when successfully read, @p aOffset is updated to point to the byte 2063 * after the entire SRV record (skipping over the record). 2064 * @param[out] aNameBuffer A char array to output the read name as a null-terminated C string 2065 * 2066 * @retval kErrorNone The host name was read successfully. @p aOffset and @p aNameBuffer are updated. 2067 * @retval kErrorParse The SRV record in @p aMessage could not be parsed (invalid format). 2068 * @retval kErrorNoBufs Name could not fit in @p aNameBuffer. 2069 * 2070 */ 2071 template <uint16_t kNameBufferSize> ReadTargetHostName(const Message & aMessage,uint16_t & aOffset,char (& aNameBuffer)[kNameBufferSize]) const2072 Error ReadTargetHostName(const Message &aMessage, uint16_t &aOffset, char (&aNameBuffer)[kNameBufferSize]) const 2073 { 2074 return ReadTargetHostName(aMessage, aOffset, aNameBuffer, kNameBufferSize); 2075 } 2076 2077 private: 2078 uint16_t mPriority; 2079 uint16_t mWeight; 2080 uint16_t mPort; 2081 // Followed by the target host domain name. 2082 2083 } OT_TOOL_PACKED_END; 2084 2085 /** 2086 * Implements Resource Record body format of KEY type (RFC 2535). 2087 * 2088 */ 2089 OT_TOOL_PACKED_BEGIN 2090 class KeyRecord : public ResourceRecord 2091 { 2092 public: 2093 static constexpr uint16_t kType = kTypeKey; ///< The KEY record type. 2094 2095 // Protocol field values (RFC 2535 - section 3.1.3). 2096 static constexpr uint8_t kProtocolTls = 1; ///< TLS protocol code. 2097 static constexpr uint8_t kProtocolDnsSec = 3; ///< DNS security protocol code. 2098 2099 // Algorithm field values (RFC 8624 - section 3.1). 2100 static constexpr uint8_t kAlgorithmEcdsaP256Sha256 = 13; ///< ECDSA-P256-SHA256 algorithm. 2101 static constexpr uint8_t kAlgorithmEcdsaP384Sha384 = 14; ///< ECDSA-P384-SHA384 algorithm. 2102 static constexpr uint8_t kAlgorithmEd25519 = 15; ///< ED25519 algorithm. 2103 static constexpr uint8_t kAlgorithmEd448 = 16; ///< ED448 algorithm. 2104 2105 /** 2106 * Type represents the use (or key type) flags (RFC 2535 - section 3.1.2). 2107 * 2108 */ 2109 enum UseFlags : uint8_t 2110 { 2111 kAuthConfidPermitted = 0x00, ///< Use of the key for authentication and/or confidentiality is permitted. 2112 kAuthPermitted = 0x40, ///< Use of the key is only permitted for authentication. 2113 kConfidPermitted = 0x80, ///< Use of the key is only permitted for confidentiality. 2114 kNoKey = 0xc0, ///< No key value (e.g., can indicate zone is not secure). 2115 }; 2116 2117 /** 2118 * Type represents key owner (or name type) flags (RFC 2535 - section 3.1.2). 2119 * 2120 */ 2121 enum OwnerFlags : uint8_t 2122 { 2123 kOwnerUser = 0x00, ///< Key is associated with a "user" or "account" at end entity. 2124 kOwnerZone = 0x01, ///< Key is a zone key (used for data origin authentication). 2125 kOwnerNonZone = 0x02, ///< Key is associated with a non-zone "entity". 2126 kOwnerReserved = 0x03, ///< Reserved for future use. 2127 }; 2128 2129 // Constants for flag bits for the "signatory" flags (RFC 2137). 2130 // 2131 // The flags defined are for non-zone (`kOwnerNoneZone`) keys (RFC 2137 - section 3.1.3). 2132 2133 /** 2134 * Key is authorized to attach, detach, and move zones. 2135 * 2136 */ 2137 static constexpr uint8_t kSignatoryFlagZone = 1 << 3; 2138 2139 /** 2140 * Key is authorized to add and delete RRs even if RRs auth with other key. 2141 * 2142 */ 2143 static constexpr uint8_t kSignatoryFlagStrong = 1 << 2; 2144 2145 /** 2146 * Key is authorized to add and update RRs for only a single owner name. 2147 * 2148 */ 2149 static constexpr uint8_t kSignatoryFlagUnique = 1 << 1; 2150 2151 /** 2152 * If the other flags are zero, this is used to indicate it is an update key. 2153 * 2154 */ 2155 static constexpr uint8_t kSignatoryFlagGeneral = 1 << 0; 2156 2157 /** 2158 * Initializes the KEY Resource Record by setting its type and class. 2159 * 2160 * Other record fields (TTL, length, flags, protocol, algorithm) remain unchanged/uninitialized. 2161 * 2162 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 2163 * 2164 */ Init(uint16_t aClass=kClassInternet)2165 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeKey, aClass); } 2166 2167 /** 2168 * Tells whether the KEY record is valid. 2169 * 2170 * @returns TRUE if this is a valid KEY record, FALSE if an invalid KEY record. 2171 * 2172 */ 2173 bool IsValid(void) const; 2174 2175 /** 2176 * Gets the key use (or key type) flags. 2177 * 2178 * @returns The key use flags. 2179 * 2180 */ GetUseFlags(void) const2181 UseFlags GetUseFlags(void) const { return static_cast<UseFlags>(mFlags[0] & kUseFlagsMask); } 2182 2183 /** 2184 * Gets the owner (or name type) flags. 2185 * 2186 * @returns The key owner flags. 2187 * 2188 */ GetOwnerFlags(void) const2189 OwnerFlags GetOwnerFlags(void) const { return static_cast<OwnerFlags>(mFlags[0] & kOwnerFlagsMask); } 2190 2191 /** 2192 * Gets the signatory flags. 2193 * 2194 * @returns The signatory flags. 2195 * 2196 */ GetSignatoryFlags(void) const2197 uint8_t GetSignatoryFlags(void) const { return (mFlags[1] & kSignatoryFlagsMask); } 2198 2199 /** 2200 * Sets the flags field. 2201 * 2202 * @param[in] aUseFlags The `UseFlags` value. 2203 * @param[in] aOwnerFlags The `OwnerFlags` value. 2204 * @param[in] aSignatoryFlags The signatory flags. 2205 * 2206 */ SetFlags(UseFlags aUseFlags,OwnerFlags aOwnerFlags,uint8_t aSignatoryFlags)2207 void SetFlags(UseFlags aUseFlags, OwnerFlags aOwnerFlags, uint8_t aSignatoryFlags) 2208 { 2209 mFlags[0] = (static_cast<uint8_t>(aUseFlags) | static_cast<uint8_t>(aOwnerFlags)); 2210 mFlags[1] = (aSignatoryFlags & kSignatoryFlagsMask); 2211 } 2212 2213 /** 2214 * Returns the KEY record's protocol value. 2215 * 2216 * @returns The protocol value. 2217 * 2218 */ GetProtocol(void) const2219 uint8_t GetProtocol(void) const { return mProtocol; } 2220 2221 /** 2222 * Sets the KEY record's protocol value. 2223 * 2224 * @param[in] aProtocol The protocol value. 2225 * 2226 */ SetProtocol(uint8_t aProtocol)2227 void SetProtocol(uint8_t aProtocol) { mProtocol = aProtocol; } 2228 2229 /** 2230 * Returns the KEY record's algorithm value. 2231 * 2232 * @returns The algorithm value. 2233 * 2234 */ GetAlgorithm(void) const2235 uint8_t GetAlgorithm(void) const { return mAlgorithm; } 2236 2237 /** 2238 * Sets the KEY record's algorithm value. 2239 * 2240 * @param[in] aAlgorithm The algorithm value. 2241 * 2242 */ SetAlgorithm(uint8_t aAlgorithm)2243 void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; } 2244 2245 private: 2246 static constexpr uint8_t kUseFlagsMask = 0xc0; // top two bits in the first flag byte. 2247 static constexpr uint8_t kOwnerFlagsMask = 0x03; // lowest two bits in the first flag byte. 2248 static constexpr uint8_t kSignatoryFlagsMask = 0x0f; // lower 4 bits in the second flag byte. 2249 2250 // Flags format: 2251 // 2252 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 2253 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2254 // | Use | Z | XT| Z | Z | Owner | Z | Z | Z | Z | SIG | 2255 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2256 // \ / \ / 2257 // ---------- mFlags[0] --------- -------- mFlags[1] ---------- 2258 2259 uint8_t mFlags[2]; 2260 uint8_t mProtocol; 2261 uint8_t mAlgorithm; 2262 // Followed by the public key 2263 2264 } OT_TOOL_PACKED_END; 2265 2266 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 2267 OT_TOOL_PACKED_BEGIN 2268 class Ecdsa256KeyRecord : public KeyRecord, public Clearable<Ecdsa256KeyRecord>, public Equatable<Ecdsa256KeyRecord> 2269 { 2270 public: 2271 /** 2272 * Initializes the KEY Resource Record to ECDSA with curve P-256. 2273 * 2274 * Other record fields (TTL, length, flags, protocol) remain unchanged/uninitialized. 2275 * 2276 */ 2277 void Init(void); 2278 2279 /** 2280 * Tells whether this is a valid ECDSA DNSKEY with curve P-256. 2281 * 2282 * @returns A boolean that indicates whether this is a valid ECDSA DNSKEY RR with curve P-256. 2283 * 2284 */ 2285 bool IsValid(void) const; 2286 2287 /** 2288 * Returns the ECDSA P-256 public key. 2289 * 2290 * @returns A reference to the public key. 2291 * 2292 */ GetKey(void) const2293 const Crypto::Ecdsa::P256::PublicKey &GetKey(void) const { return mKey; } 2294 2295 /** 2296 * Sets the ECDSA P-256 public key. 2297 * 2298 * @param[in] aKey The public key. 2299 * 2300 */ SetKey(const Crypto::Ecdsa::P256::PublicKey & aKey)2301 void SetKey(const Crypto::Ecdsa::P256::PublicKey &aKey) { mKey = aKey; } 2302 2303 private: 2304 Crypto::Ecdsa::P256::PublicKey mKey; 2305 } OT_TOOL_PACKED_END; 2306 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 2307 2308 /** 2309 * Implements Resource Record body format of SIG type (RFC 2535 - section-4.1). 2310 * 2311 * 2312 */ 2313 OT_TOOL_PACKED_BEGIN 2314 class SigRecord : public ResourceRecord, public Clearable<SigRecord> 2315 { 2316 public: 2317 static constexpr uint16_t kType = kTypeSig; ///< The SIG record type. 2318 2319 /** 2320 * Initializes the SIG Resource Record by setting its type and class. 2321 * 2322 * Other record fields (TTL, length, ...) remain unchanged/uninitialized. 2323 * 2324 * SIG(0) requires SIG RR to set class field as ANY or `kClassAny` (RFC 2931 - section 3). 2325 * 2326 * @param[in] aClass The class of the resource record. 2327 * 2328 */ Init(uint16_t aClass)2329 void Init(uint16_t aClass) { ResourceRecord::Init(kTypeSig, aClass); } 2330 2331 /** 2332 * Tells whether the SIG record is valid. 2333 * 2334 * @returns TRUE if this is a valid SIG record, FALSE if not a valid SIG record. 2335 * 2336 */ 2337 bool IsValid(void) const; 2338 2339 /** 2340 * Returns the SIG record's type-covered value. 2341 * 2342 * @returns The type-covered value. 2343 * 2344 */ GetTypeCovered(void) const2345 uint16_t GetTypeCovered(void) const { return BigEndian::HostSwap16(mTypeCovered); } 2346 2347 /** 2348 * Sets the SIG record's type-covered value. 2349 * 2350 * @param[in] aTypeCovered The type-covered value. 2351 * 2352 */ SetTypeCovered(uint8_t aTypeCovered)2353 void SetTypeCovered(uint8_t aTypeCovered) { mTypeCovered = BigEndian::HostSwap16(aTypeCovered); } 2354 2355 /** 2356 * Returns the SIG record's algorithm value. 2357 * 2358 * @returns The algorithm value. 2359 * 2360 */ GetAlgorithm(void) const2361 uint8_t GetAlgorithm(void) const { return mAlgorithm; } 2362 2363 /** 2364 * Sets the SIG record's algorithm value. 2365 * 2366 * @param[in] aAlgorithm The algorithm value. 2367 * 2368 */ SetAlgorithm(uint8_t aAlgorithm)2369 void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; } 2370 2371 /** 2372 * Returns the SIG record's labels-count (number of labels, not counting null label, in the original 2373 * name of the owner). 2374 * 2375 * @returns The labels-count value. 2376 * 2377 */ GetLabels(void) const2378 uint8_t GetLabels(void) const { return mLabels; } 2379 2380 /** 2381 * Sets the SIG record's labels-count (number of labels, not counting null label, in the original 2382 * name of the owner). 2383 * 2384 * @param[in] aLabels The labels-count value. 2385 * 2386 */ SetLabels(uint8_t aLabels)2387 void SetLabels(uint8_t aLabels) { mLabels = aLabels; } 2388 2389 /** 2390 * Returns the SIG record's original TTL value. 2391 * 2392 * @returns The original TTL value. 2393 * 2394 */ GetOriginalTtl(void) const2395 uint32_t GetOriginalTtl(void) const { return BigEndian::HostSwap32(mOriginalTtl); } 2396 2397 /** 2398 * Sets the SIG record's original TTL value. 2399 * 2400 * @param[in] aOriginalTtl The original TTL value. 2401 * 2402 */ SetOriginalTtl(uint32_t aOriginalTtl)2403 void SetOriginalTtl(uint32_t aOriginalTtl) { mOriginalTtl = BigEndian::HostSwap32(aOriginalTtl); } 2404 2405 /** 2406 * Returns the SIG record's expiration time value. 2407 * 2408 * @returns The expiration time value (seconds since Jan 1, 1970). 2409 * 2410 */ GetExpiration(void) const2411 uint32_t GetExpiration(void) const { return BigEndian::HostSwap32(mExpiration); } 2412 2413 /** 2414 * Sets the SIG record's expiration time value. 2415 * 2416 * @param[in] aExpiration The expiration time value (seconds since Jan 1, 1970). 2417 * 2418 */ SetExpiration(uint32_t aExpiration)2419 void SetExpiration(uint32_t aExpiration) { mExpiration = BigEndian::HostSwap32(aExpiration); } 2420 2421 /** 2422 * Returns the SIG record's inception time value. 2423 * 2424 * @returns The inception time value (seconds since Jan 1, 1970). 2425 * 2426 */ GetInception(void) const2427 uint32_t GetInception(void) const { return BigEndian::HostSwap32(mInception); } 2428 2429 /** 2430 * Sets the SIG record's inception time value. 2431 * 2432 * @param[in] aInception The inception time value (seconds since Jan 1, 1970). 2433 * 2434 */ SetInception(uint32_t aInception)2435 void SetInception(uint32_t aInception) { mInception = BigEndian::HostSwap32(aInception); } 2436 2437 /** 2438 * Returns the SIG record's key tag value. 2439 * 2440 * @returns The key tag value. 2441 * 2442 */ GetKeyTag(void) const2443 uint16_t GetKeyTag(void) const { return BigEndian::HostSwap16(mKeyTag); } 2444 2445 /** 2446 * Sets the SIG record's key tag value. 2447 * 2448 * @param[in] aKeyTag The key tag value. 2449 * 2450 */ SetKeyTag(uint16_t aKeyTag)2451 void SetKeyTag(uint16_t aKeyTag) { mKeyTag = BigEndian::HostSwap16(aKeyTag); } 2452 2453 /** 2454 * Returns a pointer to the start of the record data fields. 2455 * 2456 * @returns A pointer to the start of the record data fields. 2457 * 2458 */ GetRecordData(void) const2459 const uint8_t *GetRecordData(void) const { return reinterpret_cast<const uint8_t *>(&mTypeCovered); } 2460 2461 /** 2462 * Parses and reads the SIG signer name from a message. 2463 * 2464 * @param[in] aMessage The message to read from. `aMessage.GetOffset()` MUST point to the start of DNS 2465 * header. 2466 * @param[in,out] aOffset On input, the offset in @p aMessage to start of signer name field. 2467 * On exit when successfully read, @p aOffset is updated to point to the byte 2468 * after the name field (i.e., start of signature field). 2469 * @param[out] aNameBuffer A pointer to a char array to output the read name as a null-terminated C string 2470 * (MUST NOT be `nullptr`). 2471 * @param[in] aNameBufferSize The size of @p aNameBuffer. 2472 * 2473 * @retval kErrorNone The name was read successfully. @p aOffset and @p aNameBuffer are updated. 2474 * @retval kErrorParse The SIG record in @p aMessage could not be parsed (invalid format). 2475 * @retval kErrorNoBufs Name could not fit in @p aNameBufferSize chars. 2476 * 2477 */ ReadSignerName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const2478 Error ReadSignerName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize) const 2479 { 2480 return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(SigRecord), aNameBuffer, 2481 aNameBufferSize, 2482 /* aSkipRecord */ false); 2483 } 2484 2485 private: 2486 uint16_t mTypeCovered; // type of the other RRs covered by this SIG. set to zero for SIG(0). 2487 uint8_t mAlgorithm; // Algorithm number (see `KeyRecord` enumeration). 2488 uint8_t mLabels; // Number of labels (not counting null label) in the original name of the owner of RR. 2489 uint32_t mOriginalTtl; // Original time-to-live (should set to zero for SIG(0)). 2490 uint32_t mExpiration; // Signature expiration time (seconds since Jan 1, 1970). 2491 uint32_t mInception; // Signature inception time (seconds since Jan 1, 1970). 2492 uint16_t mKeyTag; // Key tag. 2493 // Followed by signer name fields and signature fields 2494 } OT_TOOL_PACKED_END; 2495 2496 /** 2497 * Implements DNS OPT Pseudo Resource Record header for EDNS(0) (RFC 6891 - Section 6.1). 2498 * 2499 */ 2500 OT_TOOL_PACKED_BEGIN 2501 class OptRecord : public ResourceRecord 2502 { 2503 public: 2504 static constexpr uint16_t kType = kTypeOpt; ///< The OPT record type. 2505 2506 /** 2507 * Initializes the OPT Resource Record by setting its type and clearing extended Response Code, version 2508 * and all flags. 2509 * 2510 * Other record fields (UDP payload size, length) remain unchanged/uninitialized. 2511 * 2512 */ Init(void)2513 void Init(void) 2514 { 2515 SetType(kTypeOpt); 2516 SetTtl(0); 2517 } 2518 2519 /** 2520 * Gets the requester's UDP payload size (the number of bytes of the largest UDP payload that can be 2521 * delivered in the requester's network). 2522 * 2523 * The field is encoded in the CLASS field. 2524 * 2525 * @returns The UDP payload size. 2526 * 2527 */ GetUdpPayloadSize(void) const2528 uint16_t GetUdpPayloadSize(void) const { return GetClass(); } 2529 2530 /** 2531 * Gets the requester's UDP payload size (the number of bytes of the largest UDP payload that can be 2532 * delivered in the requester's network). 2533 * 2534 * @param[in] aPayloadSize The UDP payload size. 2535 * 2536 */ SetUdpPayloadSize(uint16_t aPayloadSize)2537 void SetUdpPayloadSize(uint16_t aPayloadSize) { SetClass(aPayloadSize); } 2538 2539 /** 2540 * Gets the upper 8-bit of the extended 12-bit Response Code. 2541 * 2542 * Value of 0 indicates that an unextended Response code is in use. 2543 * 2544 * @return The upper 8-bit of the extended 12-bit Response Code. 2545 * 2546 */ GetExtendedResponseCode(void) const2547 uint8_t GetExtendedResponseCode(void) const { return GetTtlByteAt(kExtRCodeByteIndex); } 2548 2549 /** 2550 * Sets the upper 8-bit of the extended 12-bit Response Code. 2551 * 2552 * Value of 0 indicates that an unextended Response code is in use. 2553 * 2554 * @param[in] aExtendedResponse The upper 8-bit of the extended 12-bit Response Code. 2555 * 2556 */ SetExtendedResponseCode(uint8_t aExtendedResponse)2557 void SetExtendedResponseCode(uint8_t aExtendedResponse) { GetTtlByteAt(kExtRCodeByteIndex) = aExtendedResponse; } 2558 2559 /** 2560 * Gets the Version field. 2561 * 2562 * @returns The version. 2563 * 2564 */ GetVersion(void) const2565 uint8_t GetVersion(void) const { return GetTtlByteAt(kVersionByteIndex); } 2566 2567 /** 2568 * Set the Version field. 2569 * 2570 * @param[in] aVersion The version. 2571 * 2572 */ SetVersion(uint8_t aVersion)2573 void SetVersion(uint8_t aVersion) { GetTtlByteAt(kVersionByteIndex) = aVersion; } 2574 2575 /** 2576 * Indicates whether the DNSSEC OK flag is set or not. 2577 * 2578 * @returns True if DNSSEC OK flag is set in the header, false otherwise. 2579 * 2580 */ IsDnsSecurityFlagSet(void) const2581 bool IsDnsSecurityFlagSet(void) const { return (GetTtlByteAt(kFlagByteIndex) & kDnsSecFlag) != 0; } 2582 2583 /** 2584 * Clears the DNSSEC OK bit flag. 2585 * 2586 */ ClearDnsSecurityFlag(void)2587 void ClearDnsSecurityFlag(void) { GetTtlByteAt(kFlagByteIndex) &= ~kDnsSecFlag; } 2588 2589 /** 2590 * Sets the DNSSEC OK bit flag. 2591 * 2592 */ SetDnsSecurityFlag(void)2593 void SetDnsSecurityFlag(void) { GetTtlByteAt(kFlagByteIndex) |= kDnsSecFlag; } 2594 2595 private: 2596 // The OPT RR re-purposes the existing CLASS and TTL fields in the 2597 // RR. The CLASS field (`uint16_t`) is used for requester UDP 2598 // payload size. The TTL field is used for extended Response Code, 2599 // version and flags as follows: 2600 // 2601 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 2602 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2603 // | EXTENDED-RCODE | VERSION | 2604 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2605 // | DO| Z | Z | 2606 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 2607 // 2608 // The variable data part of OPT RR can contain zero of more `Option`. 2609 2610 static constexpr uint8_t kExtRCodeByteIndex = 0; // Byte index of Extended RCODE within the TTL field. 2611 static constexpr uint8_t kVersionByteIndex = 1; // Byte index of Version within the TTL field. 2612 static constexpr uint8_t kFlagByteIndex = 2; // Byte index of flag byte within the TTL field. 2613 static constexpr uint8_t kDnsSecFlag = 1 << 7; // DNSSec OK bit flag. 2614 GetTtlByteAt(uint8_t aIndex) const2615 uint8_t GetTtlByteAt(uint8_t aIndex) const { return reinterpret_cast<const uint8_t *>(&mTtl)[aIndex]; } GetTtlByteAt(uint8_t aIndex)2616 uint8_t &GetTtlByteAt(uint8_t aIndex) { return reinterpret_cast<uint8_t *>(&mTtl)[aIndex]; } 2617 2618 } OT_TOOL_PACKED_END; 2619 2620 /** 2621 * Implements the body of an Option in OPT Pseudo Resource Record (RFC 6981 - Section 6.1). 2622 * 2623 */ 2624 OT_TOOL_PACKED_BEGIN 2625 class Option 2626 { 2627 public: 2628 static constexpr uint16_t kUpdateLease = 2; ///< Update lease option code. 2629 2630 /** 2631 * Returns the option code value. 2632 * 2633 * @returns The option code value. 2634 * 2635 */ GetOptionCode(void) const2636 uint16_t GetOptionCode(void) const { return BigEndian::HostSwap16(mOptionCode); } 2637 2638 /** 2639 * Sets the option code value. 2640 * 2641 * @param[in] aOptionCode The option code value. 2642 * 2643 */ SetOptionCode(uint16_t aOptionCode)2644 void SetOptionCode(uint16_t aOptionCode) { mOptionCode = BigEndian::HostSwap16(aOptionCode); } 2645 2646 /** 2647 * Returns the option length value. 2648 * 2649 * @returns The option length (size of option data in bytes). 2650 * 2651 */ GetOptionLength(void) const2652 uint16_t GetOptionLength(void) const { return BigEndian::HostSwap16(mOptionLength); } 2653 2654 /** 2655 * Sets the option length value. 2656 * 2657 * @param[in] aOptionLength The option length (size of option data in bytes). 2658 * 2659 */ SetOptionLength(uint16_t aOptionLength)2660 void SetOptionLength(uint16_t aOptionLength) { mOptionLength = BigEndian::HostSwap16(aOptionLength); } 2661 2662 /** 2663 * Returns the size of (number of bytes) in the Option and its data. 2664 * 2665 * @returns Size (number of bytes) of the Option its data section. 2666 * 2667 */ GetSize(void) const2668 uint32_t GetSize(void) const { return sizeof(Option) + GetOptionLength(); } 2669 2670 private: 2671 uint16_t mOptionCode; 2672 uint16_t mOptionLength; 2673 // Followed by Option data (varies per option code). 2674 2675 } OT_TOOL_PACKED_END; 2676 2677 /** 2678 * Implements an Update Lease Option body. 2679 * 2680 * This implementation is intended for use in Dynamic DNS Update Lease Requests and Responses as specified in 2681 * https://tools.ietf.org/html/draft-sekar-dns-ul-02. 2682 * 2683 */ 2684 OT_TOOL_PACKED_BEGIN 2685 class LeaseOption : public Option 2686 { 2687 public: 2688 /** 2689 * Initializes the Update Lease Option using the short variant format which contains lease interval 2690 * only. 2691 * 2692 * @param[in] aLeaseInterval The lease interval in seconds. 2693 * 2694 */ 2695 void InitAsShortVariant(uint32_t aLeaseInterval); 2696 2697 /** 2698 * Initializes the Update Lease Option using the long variant format which contains both lease and 2699 * key lease intervals. 2700 * 2701 * @param[in] aLeaseInterval The lease interval in seconds. 2702 * @param[in] aKeyLeaseInterval The key lease interval in seconds. 2703 * 2704 */ 2705 void InitAsLongVariant(uint32_t aLeaseInterval, uint32_t aKeyLeaseInterval); 2706 2707 /** 2708 * Indicates whether or not the Update Lease Option follows the short variant format which contains 2709 * only the lease interval. 2710 * 2711 * @retval TRUE The Update Lease Option follows the short variant format. 2712 * @retval FALSE The Update Lease Option follows the long variant format. 2713 * 2714 */ IsShortVariant(void) const2715 bool IsShortVariant(void) const { return (GetOptionLength() == kShortLength); } 2716 2717 /** 2718 * Tells whether this is a valid Lease Option. 2719 * 2720 * Validates that option follows either short or long variant format. 2721 * 2722 * @returns TRUE if this is a valid Lease Option, FALSE if not a valid Lease Option. 2723 * 2724 */ 2725 bool IsValid(void) const; 2726 2727 /** 2728 * Returns the Update Lease OPT record's lease interval value. 2729 * 2730 * @returns The lease interval value (in seconds). 2731 * 2732 */ GetLeaseInterval(void) const2733 uint32_t GetLeaseInterval(void) const { return BigEndian::HostSwap32(mLeaseInterval); } 2734 2735 /** 2736 * Returns the Update Lease OPT record's key lease interval value. 2737 * 2738 * If the Update Lease Option follows the short variant format the lease interval is returned as key lease interval. 2739 * 2740 * @returns The key lease interval value (in seconds). 2741 * 2742 */ GetKeyLeaseInterval(void) const2743 uint32_t GetKeyLeaseInterval(void) const 2744 { 2745 return IsShortVariant() ? GetLeaseInterval() : BigEndian::HostSwap32(mKeyLeaseInterval); 2746 } 2747 2748 /** 2749 * Searches among the Options is a given message and reads and validates the Update Lease Option if 2750 * found. 2751 * 2752 * Reads the Update Lease Option whether it follows the short or long variant formats. 2753 * 2754 * @param[in] aMessage The message to read the Option from. 2755 * @param[in] aOffset Offset in @p aMessage to the start of Options (start of OPT Record data). 2756 * @param[in] aLength Length of Option data in OPT record. 2757 * 2758 * @retval kErrorNone Successfully read and validated the Update Lease Option from @p aMessage. 2759 * @retval kErrorNotFound Did not find any Update Lease Option. 2760 * @retval kErrorParse Failed to parse the Options. 2761 * 2762 */ 2763 Error ReadFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength); 2764 2765 private: 2766 static constexpr uint16_t kShortLength = sizeof(uint32_t); // lease only. 2767 static constexpr uint16_t kLongLength = sizeof(uint32_t) + sizeof(uint32_t); // lease and key lease values 2768 SetLeaseInterval(uint32_t aLeaseInterval)2769 void SetLeaseInterval(uint32_t aLeaseInterval) { mLeaseInterval = BigEndian::HostSwap32(aLeaseInterval); } SetKeyLeaseInterval(uint32_t aKeyLeaseInterval)2770 void SetKeyLeaseInterval(uint32_t aKeyLeaseInterval) 2771 { 2772 mKeyLeaseInterval = BigEndian::HostSwap32(aKeyLeaseInterval); 2773 } 2774 2775 uint32_t mLeaseInterval; 2776 uint32_t mKeyLeaseInterval; 2777 } OT_TOOL_PACKED_END; 2778 2779 /** 2780 * Implements body format of NSEC record (RFC 3845) for use with mDNS. 2781 * 2782 */ 2783 OT_TOOL_PACKED_BEGIN 2784 class NsecRecord : public ResourceRecord 2785 { 2786 public: 2787 static constexpr uint16_t kType = kTypeNsec; ///< The NSEC record type. 2788 2789 /** 2790 * Represents NSEC Type Bit Map field (RFC 3845 - section 2.1.2) 2791 * 2792 */ 2793 OT_TOOL_PACKED_BEGIN 2794 class TypeBitMap : public Clearable<TypeBitMap> 2795 { 2796 public: 2797 static constexpr uint8_t kMinSize = 2; ///< Minimum size of a valid `TypeBitMap` (with zero length). 2798 2799 static constexpr uint8_t kMaxLength = 32; ///< Maximum BitmapLength value. 2800 2801 /** 2802 * Gets the Window Block Number 2803 * 2804 * @returns The Window Block Number. 2805 * 2806 */ GetBlockNumber(void) const2807 uint8_t GetBlockNumber(void) const { return mBlockNumber; } 2808 2809 /** 2810 * Sets the Window Block Number 2811 * 2812 * @param[in] aBlockNumber The Window Block Number. 2813 * 2814 */ SetBlockNumber(uint8_t aBlockNumber)2815 void SetBlockNumber(uint8_t aBlockNumber) { mBlockNumber = aBlockNumber; } 2816 2817 /** 2818 * Gets the Bitmap length 2819 * 2820 * @returns The Bitmap length 2821 * 2822 */ GetBitmapLength(void)2823 uint8_t GetBitmapLength(void) { return mBitmapLength; } 2824 2825 /** 2826 * Gets the total size (number of bytes) of the `TypeBitMap` field. 2827 * 2828 * @returns The size of the `TypeBitMap` 2829 * 2830 */ GetSize(void) const2831 uint16_t GetSize(void) const { return (sizeof(mBlockNumber) + sizeof(mBitmapLength) + mBitmapLength); } 2832 2833 /** 2834 * Adds a resource record type to the Bitmap. 2835 * 2836 * As the types are added to the Bitmap the Bitmap length gets updated accordingly. 2837 * 2838 * The type space is split into 256 window blocks, each representing the low-order 8 bits of the 16-bit type 2839 * value. If @p aType does not match the currently set Window Block Number, no action is performed. 2840 * 2841 * @param[in] aType The resource record type to add. 2842 * 2843 */ 2844 void AddType(uint16_t aType); 2845 2846 /** 2847 * Indicates whether a given resource record type is present in the Bitmap. 2848 * 2849 * If @p aType does not match the currently set Window Block Number, this method returns `false`.. 2850 * 2851 * @param[in] aType The resource record type to check. 2852 * 2853 * @retval TRUE The @p aType is present in the Bitmap. 2854 * @retval FALSE The @p aType is not present in the Bitmap. 2855 * 2856 */ 2857 bool ContainsType(uint16_t aType) const; 2858 2859 private: 2860 uint8_t mBlockNumber; 2861 uint8_t mBitmapLength; 2862 uint8_t mBitmaps[kMaxLength]; 2863 } OT_TOOL_PACKED_END; 2864 2865 /** 2866 * Initializes the NSEC Resource Record by setting its type and class. 2867 * 2868 * Other record fields (TTL, length remain unchanged/uninitialized. 2869 * 2870 * @param[in] aClass The class of the resource record (default is `kClassInternet`). 2871 * 2872 */ Init(uint16_t aClass=kClassInternet)2873 void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeNsec, aClass); } 2874 2875 } OT_TOOL_PACKED_END; 2876 2877 /** 2878 * Implements Question format. 2879 * 2880 */ 2881 OT_TOOL_PACKED_BEGIN 2882 class Question 2883 { 2884 public: 2885 /** 2886 * Default constructor for Question 2887 * 2888 */ 2889 Question(void) = default; 2890 2891 /** 2892 * Constructor for Question. 2893 * 2894 */ Question(uint16_t aType,uint16_t aClass=ResourceRecord::kClassInternet)2895 explicit Question(uint16_t aType, uint16_t aClass = ResourceRecord::kClassInternet) 2896 { 2897 SetType(aType); 2898 SetClass(aClass); 2899 } 2900 2901 /** 2902 * Returns the type of the question. 2903 * 2904 * @returns The type of the question. 2905 * 2906 */ GetType(void) const2907 uint16_t GetType(void) const { return BigEndian::HostSwap16(mType); } 2908 2909 /** 2910 * Sets the type of the question. 2911 * 2912 * @param[in] aType The type of the question. 2913 * 2914 */ SetType(uint16_t aType)2915 void SetType(uint16_t aType) { mType = BigEndian::HostSwap16(aType); } 2916 2917 /** 2918 * Returns the class of the question. 2919 * 2920 * @returns The class of the question. 2921 * 2922 */ GetClass(void) const2923 uint16_t GetClass(void) const { return BigEndian::HostSwap16(mClass); } 2924 2925 /** 2926 * Sets the class of the question. 2927 * 2928 * @param[in] aClass The class of the question. 2929 * 2930 */ SetClass(uint16_t aClass)2931 void SetClass(uint16_t aClass) { mClass = BigEndian::HostSwap16(aClass); } 2932 2933 private: 2934 uint16_t mType; // The type of the data in question section. 2935 uint16_t mClass; // The class of the data in question section. 2936 } OT_TOOL_PACKED_END; 2937 2938 /** 2939 * Implements Zone section body for DNS Update (RFC 2136 - section 2.3). 2940 * 2941 */ 2942 OT_TOOL_PACKED_BEGIN 2943 class Zone : public Question 2944 { 2945 public: 2946 /** 2947 * Constructor for Zone. 2948 * 2949 * @param[in] aClass The class of the zone (default is `kClassInternet`). 2950 * 2951 */ Zone(uint16_t aClass=ResourceRecord::kClassInternet)2952 explicit Zone(uint16_t aClass = ResourceRecord::kClassInternet) 2953 : Question(ResourceRecord::kTypeSoa, aClass) 2954 { 2955 } 2956 } OT_TOOL_PACKED_END; 2957 2958 /** 2959 * @} 2960 * 2961 */ 2962 2963 } // namespace Dns 2964 2965 DefineCoreType(otDnsTxtEntry, Dns::TxtEntry); 2966 DefineCoreType(otDnsTxtEntryIterator, Dns::TxtEntry::Iterator); 2967 2968 } // namespace ot 2969 2970 #endif // DNS_HEADER_HPP_ 2971