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