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