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