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