• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      * Encodes and appends the `TxtEntry` to an Appender object.
1216      *
1217      * @param[in] aAppender  The appender to append to.
1218      *
1219      * @retval kErrorNone          Entry was appended successfully to @p aAppender.
1220      * @retval kErrorInvalidArgs   The `TxTEntry` info is not valid.
1221      * @retval kErrorNoBufs        Insufficient available space in @p aAppender.
1222      */
1223     Error AppendTo(Appender &aAppender) const;
1224 
1225     /**
1226      * Appends an array of `TxtEntry` items to a message.
1227      *
1228      * @param[in] aEntries     A pointer to array of `TxtEntry` items.
1229      * @param[in] aNumEntries  The number of entries in @p aEntries array.
1230      * @param[in] aMessage     The message to append to.
1231      *
1232      * @retval kErrorNone          Entries appended successfully to @p aMessage.
1233      * @retval kErrorInvalidArgs   The `TxTEntry` info is not valid.
1234      * @retval kErrorNoBufs        Insufficient available buffers to grow the message.
1235      */
1236     static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, Message &aMessage);
1237 
1238     /**
1239      * Appends an array of `TxtEntry` items to a `MutableData` buffer.
1240      *
1241      * @param[in] aEntries     A pointer to array of `TxtEntry` items.
1242      * @param[in] aNumEntries  The number of entries in @p aEntries array.
1243      * @param[in] aData        The `MutableData` to append in.
1244      *
1245      * @retval kErrorNone          Entries appended successfully .
1246      * @retval kErrorInvalidArgs   The `TxTEntry` info is not valid.
1247      * @retval kErrorNoBufs        Insufficient available buffers.
1248      */
1249     static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, MutableData<kWithUint16Length> &aData);
1250 
1251 private:
1252     static Error AppendEntries(const TxtEntry *aEntries, uint16_t aNumEntries, Appender &aAppender);
1253 
1254     static constexpr uint8_t kMaxKeyValueEncodedSize = 255;
1255     static constexpr char    kKeyValueSeparator      = '=';
1256 };
1257 
1258 /**
1259  * Implements Resource Record (RR) body format.
1260  */
1261 OT_TOOL_PACKED_BEGIN
1262 class ResourceRecord
1263 {
1264     friend class OptRecord;
1265 
1266 public:
1267     // Resource Record Types.
1268     static constexpr uint16_t kTypeZero  = 0;   ///< Zero as special indicator for the SIG RR (SIG(0) from RFC 2931).
1269     static constexpr uint16_t kTypeA     = 1;   ///< Address record (IPv4).
1270     static constexpr uint16_t kTypeSoa   = 6;   ///< Start of (zone of) authority.
1271     static constexpr uint16_t kTypeCname = 5;   ///< CNAME record.
1272     static constexpr uint16_t kTypePtr   = 12;  ///< PTR record.
1273     static constexpr uint16_t kTypeTxt   = 16;  ///< TXT record.
1274     static constexpr uint16_t kTypeSig   = 24;  ///< SIG record.
1275     static constexpr uint16_t kTypeKey   = 25;  ///< KEY record.
1276     static constexpr uint16_t kTypeAaaa  = 28;  ///< IPv6 address record.
1277     static constexpr uint16_t kTypeSrv   = 33;  ///< SRV locator record.
1278     static constexpr uint16_t kTypeOpt   = 41;  ///< Option record.
1279     static constexpr uint16_t kTypeNsec  = 47;  ///< NSEC record.
1280     static constexpr uint16_t kTypeAny   = 255; ///< ANY record.
1281 
1282     // Resource Record Class Codes.
1283     static constexpr uint16_t kClassInternet = 1;   ///< Class code Internet (IN).
1284     static constexpr uint16_t kClassNone     = 254; ///< Class code None (NONE) - RFC 2136.
1285     static constexpr uint16_t kClassAny      = 255; ///< Class code Any (ANY).
1286 
1287     /**
1288      * Initializes the resource record by setting its type and class.
1289      *
1290      * Only sets the type and class fields. Other fields (TTL and length) remain unchanged/uninitialized.
1291      *
1292      * @param[in] aType   The type of the resource record.
1293      * @param[in] aClass  The class of the resource record (default is `kClassInternet`).
1294      */
Init(uint16_t aType,uint16_t aClass=kClassInternet)1295     void Init(uint16_t aType, uint16_t aClass = kClassInternet)
1296     {
1297         SetType(aType);
1298         SetClass(aClass);
1299     }
1300 
1301     /**
1302      * Indicates whether the resources records matches a given type and class code.
1303      *
1304      * @param[in] aType   The resource record type to compare with.
1305      * @param[in] aClass  The resource record class code to compare with (default is `kClassInternet`).
1306      *
1307      * @returns TRUE if the resources records matches @p aType and @p aClass, FALSE otherwise.
1308      */
Matches(uint16_t aType,uint16_t aClass=kClassInternet) const1309     bool Matches(uint16_t aType, uint16_t aClass = kClassInternet) const
1310     {
1311         return (mType == BigEndian::HostSwap16(aType)) && (mClass == BigEndian::HostSwap16(aClass));
1312     }
1313 
1314     /**
1315      * Returns the type of the resource record.
1316      *
1317      * @returns The type of the resource record.
1318      */
GetType(void) const1319     uint16_t GetType(void) const { return BigEndian::HostSwap16(mType); }
1320 
1321     /**
1322      * Sets the type of the resource record.
1323      *
1324      * @param[in]  aType The type of the resource record.
1325      */
SetType(uint16_t aType)1326     void SetType(uint16_t aType) { mType = BigEndian::HostSwap16(aType); }
1327 
1328     /**
1329      * Returns the class of the resource record.
1330      *
1331      * @returns The class of the resource record.
1332      */
GetClass(void) const1333     uint16_t GetClass(void) const { return BigEndian::HostSwap16(mClass); }
1334 
1335     /**
1336      * Sets the class of the resource record.
1337      *
1338      * @param[in]  aClass The class of the resource record.
1339      */
SetClass(uint16_t aClass)1340     void SetClass(uint16_t aClass) { mClass = BigEndian::HostSwap16(aClass); }
1341 
1342     /**
1343      * Returns the time to live field of the resource record.
1344      *
1345      * @returns The time to live field of the resource record.
1346      */
GetTtl(void) const1347     uint32_t GetTtl(void) const { return BigEndian::HostSwap32(mTtl); }
1348 
1349     /**
1350      * Sets the time to live field of the resource record.
1351      *
1352      * @param[in]  aTtl The time to live field of the resource record.
1353      */
SetTtl(uint32_t aTtl)1354     void SetTtl(uint32_t aTtl) { mTtl = BigEndian::HostSwap32(aTtl); }
1355 
1356     /**
1357      * Returns the length of the resource record data.
1358      *
1359      * @returns The length of the resource record data.
1360      */
GetLength(void) const1361     uint16_t GetLength(void) const { return BigEndian::HostSwap16(mLength); }
1362 
1363     /**
1364      * Sets the length of the resource record data.
1365      *
1366      * @param[in]  aLength The length of the resource record data.
1367      */
SetLength(uint16_t aLength)1368     void SetLength(uint16_t aLength) { mLength = BigEndian::HostSwap16(aLength); }
1369 
1370     /**
1371      * Returns the size of (number of bytes) in resource record and its data RDATA section (excluding the
1372      * name field).
1373      *
1374      * @returns Size (number of bytes) of resource record and its data section (excluding the name field)
1375      */
GetSize(void) const1376     uint32_t GetSize(void) const { return sizeof(ResourceRecord) + GetLength(); }
1377 
1378     /**
1379      * Parses and skips over a given number of resource records in a message from a given offset.
1380      *
1381      * @param[in]     aMessage     The message from which to parse/read the resource records. `aMessage.GetOffset()`
1382      *                             MUST point to the start of DNS header.
1383      * @param[in,out] aOffset      On input the offset in @p aMessage pointing to the start of the first record.
1384      *                             On exit (when parsed successfully), @p aOffset is updated to point to the byte after
1385      *                             the last parsed record.
1386      * @param[in]     aNumRecords  Number of resource records to parse.
1387      *
1388      * @retval kErrorNone      Parsed records successfully. @p aOffset is updated.
1389      * @retval kErrorParse     Could not parse the records from @p aMessage (e.g., ran out of bytes in @p aMessage).
1390      */
1391     static Error ParseRecords(const Message &aMessage, uint16_t &aOffset, uint16_t aNumRecords);
1392 
1393     /**
1394      * Searches in a given message to find the first resource record matching a given record name.
1395      *
1396      * @param[in]     aMessage       The message in which to search for a matching resource record.
1397      *                               `aMessage.GetOffset()` MUST point to the start of DNS header.
1398      * @param[in,out] aOffset        On input, the offset in @p aMessage pointing to the start of the first record.
1399      *                               On exit, if a matching record is found, @p aOffset is updated to point to the byte
1400      *                               after the record name.
1401      *                               If a matching record could not be found, @p aOffset is updated to point to the byte
1402      *                               after the last record that was checked.
1403      * @param[in,out] aNumRecords    On input, the maximum number of records to check (starting from @p aOffset).
1404      *                               On exit and if a matching record is found, @p aNumRecords is updated to give the
1405      *                               number of remaining records after @p aOffset (excluding the matching record).
1406      * @param[in]     aName          The record name to match against.
1407      *
1408      * @retval kErrorNone         A matching record was found. @p aOffset, @p aNumRecords are updated.
1409      * @retval kErrorNotFound     A matching record could not be found. @p aOffset and @p aNumRecords are updated.
1410      * @retval kErrorParse        Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage).
1411      */
1412     static Error FindRecord(const Message &aMessage, uint16_t &aOffset, uint16_t &aNumRecords, const Name &aName);
1413 
1414     /**
1415      * This template static method searches in a message to find the i-th occurrence of resource records of specific
1416      * type with a given record name and if found, reads the record from the message.
1417      *
1418      * Searches in @p aMessage starting from @p aOffset up to maximum of @p aNumRecords, for the
1419      * `(aIndex+1)`th occurrence of a resource record of `RecordType` with record name @p aName.
1420      *
1421      * On success (i.e., when a matching record is found and read from the message), @p aOffset is updated to point
1422      * to after the last byte read from the message and copied into @p aRecord. This allows the caller to read any
1423      * remaining fields in the record data.
1424      *
1425      * @tparam        RecordType     The resource record type (i.e., a sub-class of `ResourceRecord`).
1426      *
1427      * @param[in]     aMessage       The message to search within for matching resource records.
1428      *                               `aMessage.GetOffset()` MUST point to the start of DNS header.
1429      * @param[in,out] aOffset        On input, the offset in @p aMessage pointing to the start of the first record.
1430      *                               On exit and only if a matching record is found, @p aOffset is updated to point to
1431      *                               the last read byte in the record (allowing caller to read any remaining fields in
1432      *                               the record data from the message).
1433      * @param[in]     aNumRecords    The maximum number of records to check (starting from @p aOffset).
1434      * @param[in]     aIndex         The matching record index to find. @p aIndex value of zero returns the first
1435      *                               matching record.
1436      * @param[in]     aName          The record name to match against.
1437      * @param[in]     aRecord        A reference to a record object to read a matching record into.
1438      *                               If a matching record is found, `sizeof(RecordType)` bytes from @p aMessage are
1439      *                               read and copied into @p aRecord.
1440      *
1441      * @retval kErrorNone         A matching record was found. @p aOffset is updated.
1442      * @retval kErrorNotFound     A matching record could not be found.
1443      * @retval kErrorParse        Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage).
1444      */
1445     template <class RecordType>
FindRecord(const Message & aMessage,uint16_t & aOffset,uint16_t aNumRecords,uint16_t aIndex,const Name & aName,RecordType & aRecord)1446     static Error FindRecord(const Message &aMessage,
1447                             uint16_t      &aOffset,
1448                             uint16_t       aNumRecords,
1449                             uint16_t       aIndex,
1450                             const Name    &aName,
1451                             RecordType    &aRecord)
1452     {
1453         return FindRecord(aMessage, aOffset, aNumRecords, aIndex, aName, RecordType::kType, aRecord,
1454                           sizeof(RecordType));
1455     }
1456 
1457     /**
1458      * This template static method tries to read a resource record of a given type from a message. If the record type
1459      * does not matches the type, it skips over the record.
1460      *
1461      * Requires the record name to be already parsed/read from the message. On input, @p aOffset should
1462      * point to the start of the `ResourceRecord` fields (type, class, TTL, data length) in @p aMessage.
1463      *
1464      * Verifies that the record is well-formed in the message. It then reads the record type and compares
1465      * it with `RecordType::kType` and ensures that the record size is at least `sizeof(RecordType)`. If it all matches,
1466      * the record is read into @p aRecord.
1467      *
1468      * On success (i.e., when a matching record is read from the message), the @p aOffset is updated to point to after
1469      * the last byte read from the message and copied into @p aRecord and not necessarily the end of the record.
1470      *  Depending on the `RecordType` format, there may still be more data bytes left in the record to be read. For
1471      * example, when reading a SRV record using `SrvRecord` type, @p aOffset would point to after the last field in
1472      * `SrvRecord`  which is the start of "target host domain name" field.
1473      *
1474      * @tparam        RecordType     The resource record type (i.e., a sub-class of `ResourceRecord`).
1475      *
1476      * @param[in]     aMessage       The message from which to read the record.
1477      * @param[in,out] aOffset        On input, the offset in @p aMessage pointing to the byte after the record name.
1478      *                               On exit, if a matching record is read, @p aOffset is updated to point to the last
1479      *                               read byte in the record.
1480      *                               If a matching record could not be read, @p aOffset is updated to point to the byte
1481      *                               after the entire record (skipping over the record).
1482      * @param[out]    aRecord        A reference to a record to read a matching record into.
1483      *                               If a matching record is found, `sizeof(RecordType)` bytes from @p aMessage are
1484      *                               read and copied into @p aRecord.
1485      *
1486      * @retval kErrorNone         A matching record was read successfully. @p aOffset, and @p aRecord are updated.
1487      * @retval kErrorNotFound     A matching record could not be found. @p aOffset is updated.
1488      * @retval kErrorParse        Could not parse records from @p aMessage (e.g., ran out of bytes in @p aMessage).
1489      */
ReadRecord(const Message & aMessage,uint16_t & aOffset,RecordType & aRecord)1490     template <class RecordType> static Error ReadRecord(const Message &aMessage, uint16_t &aOffset, RecordType &aRecord)
1491     {
1492         return ReadRecord(aMessage, aOffset, RecordType::kType, aRecord, sizeof(RecordType));
1493     }
1494 
1495 protected:
1496     Error ReadName(const Message &aMessage,
1497                    uint16_t      &aOffset,
1498                    uint16_t       aStartOffset,
1499                    char          *aNameBuffer,
1500                    uint16_t       aNameBufferSize,
1501                    bool           aSkipRecord) const;
1502     Error SkipRecord(const Message &aMessage, uint16_t &aOffset) const;
1503 
1504 private:
1505     static constexpr uint16_t kType = kTypeAny; // This is intended for used by `ReadRecord<RecordType>()` only.
1506 
1507     static Error FindRecord(const Message  &aMessage,
1508                             uint16_t       &aOffset,
1509                             uint16_t        aNumRecords,
1510                             uint16_t        aIndex,
1511                             const Name     &aName,
1512                             uint16_t        aType,
1513                             ResourceRecord &aRecord,
1514                             uint16_t        aMinRecordSize);
1515 
1516     static Error ReadRecord(const Message  &aMessage,
1517                             uint16_t       &aOffset,
1518                             uint16_t        aType,
1519                             ResourceRecord &aRecord,
1520                             uint16_t        aMinRecordSize);
1521 
1522     Error CheckRecord(const Message &aMessage, uint16_t aOffset) const;
1523     Error ReadFrom(const Message &aMessage, uint16_t aOffset);
1524 
1525     uint16_t mType;   // The type of the data in RDATA section.
1526     uint16_t mClass;  // The class of the data in RDATA section.
1527     uint32_t mTtl;    // Specifies the maximum time that the resource record may be cached.
1528     uint16_t mLength; // The length of RDATA section in bytes.
1529 
1530 } OT_TOOL_PACKED_END;
1531 
1532 /**
1533  * Implements Resource Record body format of A type.
1534  */
1535 OT_TOOL_PACKED_BEGIN
1536 class ARecord : public ResourceRecord
1537 {
1538 public:
1539     static constexpr uint16_t kType = kTypeA; ///< The A record type.
1540 
1541     /**
1542      * Initializes the A Resource Record by setting its type, class, and length.
1543      *
1544      * Other record fields (TTL, address) remain unchanged/uninitialized.
1545      */
Init(void)1546     void Init(void)
1547     {
1548         ResourceRecord::Init(kTypeA);
1549         SetLength(sizeof(Ip4::Address));
1550     }
1551 
1552     /**
1553      * Sets the IPv4 address of the resource record.
1554      *
1555      * @param[in]  aAddress The IPv4 address of the resource record.
1556      */
SetAddress(const Ip4::Address & aAddress)1557     void SetAddress(const Ip4::Address &aAddress) { mAddress = aAddress; }
1558 
1559     /**
1560      * Returns the reference to IPv4 address of the resource record.
1561      *
1562      * @returns The reference to IPv4 address of the resource record.
1563      */
GetAddress(void) const1564     const Ip4::Address &GetAddress(void) const { return mAddress; }
1565 
1566 private:
1567     Ip4::Address mAddress; // IPv4 Address of A Resource Record.
1568 } OT_TOOL_PACKED_END;
1569 
1570 /**
1571  * Implements Resource Record body format of CNAME type.
1572  */
1573 OT_TOOL_PACKED_BEGIN
1574 class CnameRecord : public ResourceRecord
1575 {
1576 public:
1577     static constexpr uint16_t kType = kTypeCname; ///< The CNAME record type.
1578 
1579     /**
1580      * Initializes the CNAME Resource Record by setting its type and class.
1581      *
1582      * Other record fields (TTL, length) remain unchanged/uninitialized.
1583      *
1584      * @param[in] aClass  The class of the resource record (default is `kClassInternet`).
1585      */
Init(uint16_t aClass=kClassInternet)1586     void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeCname, aClass); }
1587 
1588     /**
1589      * Parses and reads the CNAME alias name from a message.
1590      *
1591      * Also verifies that the CNAME record is well-formed (e.g., the record data length `GetLength()`
1592      * matches the CNAME encoded name).
1593      *
1594      * @param[in]      aMessage         The message to read from. `aMessage.GetOffset()` MUST point to the start of
1595      *                                  DNS header.
1596      * @param[in,out]  aOffset          On input, the offset in @p aMessage to start of CNAME name field.
1597      *                                  On exit when successfully read, @p aOffset is updated to point to the byte
1598      *                                  after the entire PTR record (skipping over the record).
1599      * @param[out]     aNameBuffer      A pointer to a char array to output the read name as a null-terminated C string
1600      *                                  (MUST NOT be `nullptr`).
1601      * @param[in]      aNameBufferSize  The size of @p aNameBuffer.
1602      *
1603      * @retval kErrorNone           The CNAME name was read successfully. @p aOffset and @p aNameBuffer are updated.
1604      * @retval kErrorParse          The CNAME record in @p aMessage could not be parsed (invalid format).
1605      * @retval kErrorNoBufs         Name could not fit in @p aNameBufferSize chars.
1606      */
ReadCanonicalName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const1607     Error ReadCanonicalName(const Message &aMessage,
1608                             uint16_t      &aOffset,
1609                             char          *aNameBuffer,
1610                             uint16_t       aNameBufferSize) const
1611     {
1612         return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(CnameRecord),
1613                                         aNameBuffer, aNameBufferSize, /* aSkipRecord */ true);
1614     }
1615 
1616 } OT_TOOL_PACKED_END;
1617 
1618 /**
1619  * Implements Resource Record body format of PTR type.
1620  */
1621 OT_TOOL_PACKED_BEGIN
1622 class PtrRecord : public ResourceRecord
1623 {
1624 public:
1625     static constexpr uint16_t kType = kTypePtr; ///< The PTR record type.
1626 
1627     /**
1628      * Initializes the PTR Resource Record by setting its type and class.
1629      *
1630      * Other record fields (TTL, length) remain unchanged/uninitialized.
1631      *
1632      * @param[in] aClass  The class of the resource record (default is `kClassInternet`).
1633      */
Init(uint16_t aClass=kClassInternet)1634     void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypePtr, aClass); }
1635 
1636     /**
1637      * Parses and reads the PTR name from a message.
1638      *
1639      * Also verifies that the PTR record is well-formed (e.g., the record data length `GetLength()` matches
1640      * the PTR encoded name).
1641      *
1642      * @param[in]      aMessage         The message to read from.  `aMessage.GetOffset()` MUST point to the start of
1643      *                                  DNS header.
1644      * @param[in,out]  aOffset          On input, the offset in @p aMessage to start of PTR name field.
1645      *                                  On exit when successfully read, @p aOffset is updated to point to the byte
1646      *                                  after the entire PTR record (skipping over the record).
1647      * @param[out]     aNameBuffer      A pointer to a char array to output the read name as a null-terminated C string
1648      *                                  (MUST NOT be `nullptr`).
1649      * @param[in]      aNameBufferSize  The size of @p aNameBuffer.
1650      *
1651      * @retval kErrorNone           The PTR name was read successfully. @p aOffset and @p aNameBuffer are updated.
1652      * @retval kErrorParse          The PTR record in @p aMessage could not be parsed (invalid format).
1653      * @retval kErrorNoBufs         Name could not fit in @p aNameBufferSize chars.
1654      */
ReadPtrName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const1655     Error ReadPtrName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize) const
1656     {
1657         return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(PtrRecord), aNameBuffer,
1658                                         aNameBufferSize,
1659                                         /* aSkipRecord */ true);
1660     }
1661 
1662     /**
1663      * Parses and reads the PTR name from a message.
1664      *
1665      * Also verifies that the PTR record is well-formed (e.g., the record data length `GetLength()` matches
1666      * the PTR encoded name).
1667      *
1668      * Unlike the previous method which reads the entire PTR name into a single char buffer, this method reads the
1669      * first label separately and into a different buffer @p aLabelBuffer and the rest of the name into @p aNameBuffer.
1670      * The @p aNameBuffer can be set to `nullptr` if the caller is only interested in the first label. This method is
1671      * intended for "Service Instance Name" where first label (`<Instance>` portion) can be a user-friendly string and
1672      * can contain dot character.
1673      *
1674      * @param[in]      aMessage          The message to read from. `aMessage.GetOffset()` MUST point to the start of
1675      *                                   DNS header.
1676      * @param[in,out]  aOffset           On input, the offset in @p aMessage to the start of PTR name field.
1677      *                                   On exit, when successfully read, @p aOffset is updated to point to the byte
1678      *                                   after the entire PTR record (skipping over the record).
1679      * @param[out]     aLabelBuffer      A pointer to a char array to output the first label as a null-terminated C
1680      *                                   string (MUST NOT be `nullptr`).
1681      * @param[in]      aLabelBufferSize  The size of @p aLabelBuffer.
1682      * @param[out]     aNameBuffer       A pointer to a char array to output the rest of name (after first label). Can
1683      *                                   be `nullptr` if caller is only interested in the first label.
1684      * @param[in]      aNameBufferSize   The size of @p aNameBuffer.
1685      *
1686      * @retval kErrorNone    The PTR name was read successfully. @p aOffset, @aLabelBuffer and @aNameBuffer are updated.
1687      * @retval kErrorParse   The PTR record in @p aMessage could not be parsed (invalid format).
1688      * @retval kErrorNoBufs  Either label or name could not fit in the related char buffers.
1689      */
1690     Error ReadPtrName(const Message &aMessage,
1691                       uint16_t      &aOffset,
1692                       char          *aLabelBuffer,
1693                       uint8_t        aLabelBufferSize,
1694                       char          *aNameBuffer,
1695                       uint16_t       aNameBufferSize) const;
1696 
1697     /**
1698      * Parses and reads the PTR name from a message.
1699      *
1700      * This is a template variation of the previous method with name and label buffer sizes as template parameters.
1701      *
1702      * @tparam kLabelBufferSize          The size of label buffer.
1703      * @tparam kNameBufferSize           The size of name buffer.
1704      *
1705      * @param[in]      aMessage          The message to read from. `aMessage.GetOffset()` MUST point to the start of
1706      *                                   DNS header.
1707      * @param[in,out]  aOffset           On input, the offset in @p aMessage to the start of PTR name field.
1708      *                                   On exit, when successfully read, @p aOffset is updated to point to the byte
1709      *                                   after the entire PTR record (skipping over the record).
1710      * @param[out]     aLabelBuffer      A char array buffer to output the first label as a null-terminated C string.
1711      * @param[out]     aNameBuffer       A char array to output the rest of name (after first label).
1712      *
1713      * @retval kErrorNone    The PTR name was read successfully. @p aOffset, @aLabelBuffer and @aNameBuffer are updated.
1714      * @retval kErrorParse   The PTR record in @p aMessage could not be parsed (invalid format).
1715      * @retval kErrorNoBufs  Either label or name could not fit in the related given buffers.
1716      */
1717     template <uint16_t kLabelBufferSize, uint16_t kNameBufferSize>
ReadPtrName(const Message & aMessage,uint16_t & aOffset,char (& aLabelBuffer)[kLabelBufferSize],char (& aNameBuffer)[kNameBufferSize]) const1718     Error ReadPtrName(const Message &aMessage,
1719                       uint16_t      &aOffset,
1720                       char (&aLabelBuffer)[kLabelBufferSize],
1721                       char (&aNameBuffer)[kNameBufferSize]) const
1722     {
1723         return ReadPtrName(aMessage, aOffset, aLabelBuffer, kLabelBufferSize, aNameBuffer, kNameBufferSize);
1724     }
1725 
1726 } OT_TOOL_PACKED_END;
1727 
1728 /**
1729  * Implements Resource Record body format of TXT type.
1730  */
1731 OT_TOOL_PACKED_BEGIN
1732 class TxtRecord : public ResourceRecord
1733 {
1734 public:
1735     static constexpr uint16_t kType = kTypeTxt; ///< The TXT record type.
1736 
1737     /**
1738      * Initializes the TXT Resource Record by setting its type and class.
1739      *
1740      * Other record fields (TTL, length) remain unchanged/uninitialized.
1741      *
1742      * @param[in] aClass  The class of the resource record (default is `kClassInternet`).
1743      */
Init(uint16_t aClass=kClassInternet)1744     void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeTxt, aClass); }
1745 
1746     /**
1747      * Parses and reads the TXT record data from a message.
1748      *
1749      * Also checks if the TXT data is well-formed by calling `VerifyTxtData()` when it is successfully
1750      * read.
1751      *
1752      * @param[in]      aMessage         The message to read from.
1753      * @param[in,out]  aOffset          On input, the offset in @p aMessage to start of TXT record data.
1754      *                                  On exit when successfully read, @p aOffset is updated to point to the byte
1755      *                                  after the entire TXT record (skipping over the record).
1756      * @param[out]     aTxtBuffer       A pointer to a byte array to output the read TXT data.
1757      * @param[in,out]  aTxtBufferSize   On input, the size of @p aTxtBuffer (max bytes that can be read).
1758      *                                  On exit, @p aTxtBufferSize gives number of bytes written to @p aTxtBuffer.
1759      *
1760      * @retval kErrorNone           The TXT data was read successfully. @p aOffset, @p aTxtBuffer and @p aTxtBufferSize
1761      *                              are updated.
1762      * @retval kErrorParse          The TXT record in @p aMessage could not be parsed (invalid format).
1763      * @retval kErrorNoBufs         TXT data could not fit in @p aTxtBufferSize bytes. TXT data is still partially read
1764      *                              into @p aTxtBuffer up to its size and @p aOffset is updated to skip over the full
1765      *                              TXT record.
1766      */
1767     Error ReadTxtData(const Message &aMessage, uint16_t &aOffset, uint8_t *aTxtBuffer, uint16_t &aTxtBufferSize) const;
1768 
1769     /**
1770      * Tests if a buffer contains valid encoded TXT data.
1771      *
1772      * @param[in]  aTxtData     The TXT data buffer.
1773      * @param[in]  aTxtLength   The length of the TXT data buffer.
1774      * @param[in]  aAllowEmpty  True if zero-length TXT data is allowed.
1775      *
1776      * @returns  TRUE if @p aTxtData contains valid encoded TXT data, FALSE if not.
1777      */
1778     static bool VerifyTxtData(const uint8_t *aTxtData, uint16_t aTxtLength, bool aAllowEmpty);
1779 
1780 } OT_TOOL_PACKED_END;
1781 
1782 /**
1783  * Implements Resource Record body format of AAAA type.
1784  */
1785 OT_TOOL_PACKED_BEGIN
1786 class AaaaRecord : public ResourceRecord
1787 {
1788 public:
1789     static constexpr uint16_t kType = kTypeAaaa; ///< The AAAA record type.
1790 
1791     /**
1792      * Initializes the AAAA Resource Record by setting its type, class, and length.
1793      *
1794      * Other record fields (TTL, address) remain unchanged/uninitialized.
1795      */
Init(void)1796     void Init(void)
1797     {
1798         ResourceRecord::Init(kTypeAaaa);
1799         SetLength(sizeof(Ip6::Address));
1800     }
1801 
1802     /**
1803      * Tells whether this is a valid AAAA record.
1804      *
1805      * @returns  A boolean indicates whether this is a valid AAAA record.
1806      */
1807     bool IsValid(void) const;
1808 
1809     /**
1810      * Sets the IPv6 address of the resource record.
1811      *
1812      * @param[in]  aAddress The IPv6 address of the resource record.
1813      */
SetAddress(const Ip6::Address & aAddress)1814     void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; }
1815 
1816     /**
1817      * Returns the reference to IPv6 address of the resource record.
1818      *
1819      * @returns The reference to IPv6 address of the resource record.
1820      */
GetAddress(void) const1821     const Ip6::Address &GetAddress(void) const { return mAddress; }
1822 
1823 private:
1824     Ip6::Address mAddress; // IPv6 Address of AAAA Resource Record.
1825 } OT_TOOL_PACKED_END;
1826 
1827 /**
1828  * Implements Resource Record body format of SRV type (RFC 2782).
1829  */
1830 OT_TOOL_PACKED_BEGIN
1831 class SrvRecord : public ResourceRecord
1832 {
1833 public:
1834     static constexpr uint16_t kType = kTypeSrv; ///< The SRV record type.
1835 
1836     /**
1837      * Initializes the SRV Resource Record by settings its type and class.
1838      *
1839      * Other record fields (TTL, length, propriety, weight, port, ...) remain unchanged/uninitialized.
1840      *
1841      * @param[in] aClass  The class of the resource record (default is `kClassInternet`).
1842      */
Init(uint16_t aClass=kClassInternet)1843     void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeSrv, aClass); }
1844 
1845     /**
1846      * Returns the SRV record's priority value.
1847      *
1848      * @returns The priority value.
1849      */
GetPriority(void) const1850     uint16_t GetPriority(void) const { return BigEndian::HostSwap16(mPriority); }
1851 
1852     /**
1853      * Sets the SRV record's priority value.
1854      *
1855      * @param[in]  aPriority  The priority value.
1856      */
SetPriority(uint16_t aPriority)1857     void SetPriority(uint16_t aPriority) { mPriority = BigEndian::HostSwap16(aPriority); }
1858 
1859     /**
1860      * Returns the SRV record's weight value.
1861      *
1862      * @returns The weight value.
1863      */
GetWeight(void) const1864     uint16_t GetWeight(void) const { return BigEndian::HostSwap16(mWeight); }
1865 
1866     /**
1867      * Sets the SRV record's weight value.
1868      *
1869      * @param[in]  aWeight  The weight value.
1870      */
SetWeight(uint16_t aWeight)1871     void SetWeight(uint16_t aWeight) { mWeight = BigEndian::HostSwap16(aWeight); }
1872 
1873     /**
1874      * Returns the SRV record's port number on the target host for this service.
1875      *
1876      * @returns The port number.
1877      */
GetPort(void) const1878     uint16_t GetPort(void) const { return BigEndian::HostSwap16(mPort); }
1879 
1880     /**
1881      * Sets the SRV record's port number on the target host for this service.
1882      *
1883      * @param[in]  aPort  The port number.
1884      */
SetPort(uint16_t aPort)1885     void SetPort(uint16_t aPort) { mPort = BigEndian::HostSwap16(aPort); }
1886 
1887     /**
1888      * Parses and reads the SRV target host name from a message.
1889      *
1890      * Also verifies that the SRV record is well-formed (e.g., the record data length `GetLength()` matches
1891      * the SRV encoded name).
1892      *
1893      * @param[in]      aMessage         The message to read from. `aMessage.GetOffset()` MUST point to the start of
1894      *                                  DNS header.
1895      * @param[in,out]  aOffset          On input, the offset in @p aMessage to start of target host name field.
1896      *                                  On exit when successfully read, @p aOffset is updated to point to the byte
1897      *                                  after the entire SRV record (skipping over the record).
1898      * @param[out]     aNameBuffer      A pointer to a char array to output the read name as a null-terminated C string
1899      *                                  (MUST NOT be `nullptr`).
1900      * @param[in]      aNameBufferSize  The size of @p aNameBuffer.
1901      *
1902      * @retval kErrorNone            The host name was read successfully. @p aOffset and @p aNameBuffer are updated.
1903      * @retval kErrorParse           The SRV record in @p aMessage could not be parsed (invalid format).
1904      * @retval kErrorNoBufs          Name could not fit in @p aNameBufferSize chars.
1905      */
ReadTargetHostName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const1906     Error ReadTargetHostName(const Message &aMessage,
1907                              uint16_t      &aOffset,
1908                              char          *aNameBuffer,
1909                              uint16_t       aNameBufferSize) const
1910     {
1911         return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(SrvRecord), aNameBuffer,
1912                                         aNameBufferSize,
1913                                         /* aSkipRecord */ true);
1914     }
1915 
1916     /**
1917      * Parses and reads the SRV target host name from a message.
1918      *
1919      * Also verifies that the SRV record is well-formed (e.g., the record data length `GetLength()` matches
1920      * the SRV encoded name).
1921      *
1922      * @tparam         kNameBufferSize  Size of the name buffer.
1923      *
1924      * @param[in]      aMessage         The message to read from. `aMessage.GetOffset()` MUST point to the start of
1925      *                                  DNS header.
1926      * @param[in,out]  aOffset          On input, the offset in @p aMessage to start of target host name field.
1927      *                                  On exit when successfully read, @p aOffset is updated to point to the byte
1928      *                                  after the entire SRV record (skipping over the record).
1929      * @param[out]     aNameBuffer      A char array to output the read name as a null-terminated C string
1930      *
1931      * @retval kErrorNone            The host name was read successfully. @p aOffset and @p aNameBuffer are updated.
1932      * @retval kErrorParse           The SRV record in @p aMessage could not be parsed (invalid format).
1933      * @retval kErrorNoBufs          Name could not fit in @p aNameBuffer.
1934      */
1935     template <uint16_t kNameBufferSize>
ReadTargetHostName(const Message & aMessage,uint16_t & aOffset,char (& aNameBuffer)[kNameBufferSize]) const1936     Error ReadTargetHostName(const Message &aMessage, uint16_t &aOffset, char (&aNameBuffer)[kNameBufferSize]) const
1937     {
1938         return ReadTargetHostName(aMessage, aOffset, aNameBuffer, kNameBufferSize);
1939     }
1940 
1941 private:
1942     uint16_t mPriority;
1943     uint16_t mWeight;
1944     uint16_t mPort;
1945     // Followed by the target host domain name.
1946 
1947 } OT_TOOL_PACKED_END;
1948 
1949 /**
1950  * Implements Resource Record body format of KEY type (RFC 2535).
1951  */
1952 OT_TOOL_PACKED_BEGIN
1953 class KeyRecord : public ResourceRecord
1954 {
1955 public:
1956     static constexpr uint16_t kType = kTypeKey; ///< The KEY record type.
1957 
1958     // Protocol field values (RFC 2535 - section 3.1.3).
1959     static constexpr uint8_t kProtocolTls    = 1; ///< TLS protocol code.
1960     static constexpr uint8_t kProtocolDnsSec = 3; ///< DNS security protocol code.
1961 
1962     // Algorithm field values (RFC 8624 - section 3.1).
1963     static constexpr uint8_t kAlgorithmEcdsaP256Sha256 = 13; ///< ECDSA-P256-SHA256 algorithm.
1964     static constexpr uint8_t kAlgorithmEcdsaP384Sha384 = 14; ///< ECDSA-P384-SHA384 algorithm.
1965     static constexpr uint8_t kAlgorithmEd25519         = 15; ///< ED25519 algorithm.
1966     static constexpr uint8_t kAlgorithmEd448           = 16; ///< ED448 algorithm.
1967 
1968     /**
1969      * Type represents the use (or key type) flags (RFC 2535 - section 3.1.2).
1970      */
1971     enum UseFlags : uint8_t
1972     {
1973         kAuthConfidPermitted = 0x00, ///< Use of the key for authentication and/or confidentiality is permitted.
1974         kAuthPermitted       = 0x40, ///< Use of the key is only permitted for authentication.
1975         kConfidPermitted     = 0x80, ///< Use of the key is only permitted for confidentiality.
1976         kNoKey               = 0xc0, ///< No key value (e.g., can indicate zone is not secure).
1977     };
1978 
1979     /**
1980      * Type represents key owner (or name type) flags (RFC 2535 - section 3.1.2).
1981      */
1982     enum OwnerFlags : uint8_t
1983     {
1984         kOwnerUser     = 0x00, ///< Key is associated with a "user" or "account" at end entity.
1985         kOwnerZone     = 0x01, ///< Key is a zone key (used for data origin authentication).
1986         kOwnerNonZone  = 0x02, ///< Key is associated with a non-zone "entity".
1987         kOwnerReserved = 0x03, ///< Reserved for future use.
1988     };
1989 
1990     // Constants for flag bits for the "signatory" flags (RFC 2137).
1991     //
1992     // The flags defined are for non-zone (`kOwnerNoneZone`) keys (RFC 2137 - section 3.1.3).
1993 
1994     /**
1995      * Key is authorized to attach, detach, and move zones.
1996      */
1997     static constexpr uint8_t kSignatoryFlagZone = 1 << 3;
1998 
1999     /**
2000      * Key is authorized to add and delete RRs even if RRs auth with other key.
2001      */
2002     static constexpr uint8_t kSignatoryFlagStrong = 1 << 2;
2003 
2004     /**
2005      * Key is authorized to add and update RRs for only a single owner name.
2006      */
2007     static constexpr uint8_t kSignatoryFlagUnique = 1 << 1;
2008 
2009     /**
2010      * If the other flags are zero, this is used to indicate it is an update key.
2011      */
2012     static constexpr uint8_t kSignatoryFlagGeneral = 1 << 0;
2013 
2014     /**
2015      * Initializes the KEY Resource Record by setting its type and class.
2016      *
2017      * Other record fields (TTL, length, flags, protocol, algorithm) remain unchanged/uninitialized.
2018      *
2019      * @param[in] aClass  The class of the resource record (default is `kClassInternet`).
2020      */
Init(uint16_t aClass=kClassInternet)2021     void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeKey, aClass); }
2022 
2023     /**
2024      * Tells whether the KEY record is valid.
2025      *
2026      * @returns  TRUE if this is a valid KEY record, FALSE if an invalid KEY record.
2027      */
2028     bool IsValid(void) const;
2029 
2030     /**
2031      * Gets the key use (or key type) flags.
2032      *
2033      * @returns The key use flags.
2034      */
GetUseFlags(void) const2035     UseFlags GetUseFlags(void) const { return static_cast<UseFlags>(mFlags[0] & kUseFlagsMask); }
2036 
2037     /**
2038      * Gets the owner (or name type) flags.
2039      *
2040      * @returns The key owner flags.
2041      */
GetOwnerFlags(void) const2042     OwnerFlags GetOwnerFlags(void) const { return static_cast<OwnerFlags>(mFlags[0] & kOwnerFlagsMask); }
2043 
2044     /**
2045      * Gets the signatory flags.
2046      *
2047      * @returns The signatory flags.
2048      */
GetSignatoryFlags(void) const2049     uint8_t GetSignatoryFlags(void) const { return (mFlags[1] & kSignatoryFlagsMask); }
2050 
2051     /**
2052      * Sets the flags field.
2053      *
2054      * @param[in] aUseFlags        The `UseFlags` value.
2055      * @param[in] aOwnerFlags      The `OwnerFlags` value.
2056      * @param[in] aSignatoryFlags  The signatory flags.
2057      */
SetFlags(UseFlags aUseFlags,OwnerFlags aOwnerFlags,uint8_t aSignatoryFlags)2058     void SetFlags(UseFlags aUseFlags, OwnerFlags aOwnerFlags, uint8_t aSignatoryFlags)
2059     {
2060         mFlags[0] = (static_cast<uint8_t>(aUseFlags) | static_cast<uint8_t>(aOwnerFlags));
2061         mFlags[1] = (aSignatoryFlags & kSignatoryFlagsMask);
2062     }
2063 
2064     /**
2065      * Returns the KEY record's protocol value.
2066      *
2067      * @returns The protocol value.
2068      */
GetProtocol(void) const2069     uint8_t GetProtocol(void) const { return mProtocol; }
2070 
2071     /**
2072      * Sets the KEY record's protocol value.
2073      *
2074      * @param[in]  aProtocol  The protocol value.
2075      */
SetProtocol(uint8_t aProtocol)2076     void SetProtocol(uint8_t aProtocol) { mProtocol = aProtocol; }
2077 
2078     /**
2079      * Returns the KEY record's algorithm value.
2080      *
2081      * @returns The algorithm value.
2082      */
GetAlgorithm(void) const2083     uint8_t GetAlgorithm(void) const { return mAlgorithm; }
2084 
2085     /**
2086      * Sets the KEY record's algorithm value.
2087      *
2088      * @param[in]  aAlgorithm  The algorithm value.
2089      */
SetAlgorithm(uint8_t aAlgorithm)2090     void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; }
2091 
2092 private:
2093     static constexpr uint8_t kUseFlagsMask       = 0xc0; // top two bits in the first flag byte.
2094     static constexpr uint8_t kOwnerFlagsMask     = 0x03; // lowest two bits in the first flag byte.
2095     static constexpr uint8_t kSignatoryFlagsMask = 0x0f; // lower 4 bits in the second flag byte.
2096 
2097     // Flags format:
2098     //
2099     //    0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5
2100     //  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2101     //  |  Use  | Z | XT| Z | Z | Owner | Z | Z | Z | Z |      SIG      |
2102     //  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2103     //  \                              / \                             /
2104     //   ---------- mFlags[0] ---------   -------- mFlags[1] ----------
2105 
2106     uint8_t mFlags[2];
2107     uint8_t mProtocol;
2108     uint8_t mAlgorithm;
2109     // Followed by the public key
2110 
2111 } OT_TOOL_PACKED_END;
2112 
2113 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
2114 OT_TOOL_PACKED_BEGIN
2115 class Ecdsa256KeyRecord : public KeyRecord, public Clearable<Ecdsa256KeyRecord>, public Equatable<Ecdsa256KeyRecord>
2116 {
2117 public:
2118     /**
2119      * Initializes the KEY Resource Record to ECDSA with curve P-256.
2120      *
2121      * Other record fields (TTL, length, flags, protocol) remain unchanged/uninitialized.
2122      */
2123     void Init(void);
2124 
2125     /**
2126      * Tells whether this is a valid ECDSA DNSKEY with curve P-256.
2127      *
2128      * @returns  A boolean that indicates whether this is a valid ECDSA DNSKEY RR with curve P-256.
2129      */
2130     bool IsValid(void) const;
2131 
2132     /**
2133      * Returns the ECDSA P-256 public key.
2134      *
2135      * @returns  A reference to the public key.
2136      */
GetKey(void) const2137     const Crypto::Ecdsa::P256::PublicKey &GetKey(void) const { return mKey; }
2138 
2139     /**
2140      * Sets the ECDSA P-256 public key.
2141      *
2142      * @param[in] aKey  The public key.
2143      */
SetKey(const Crypto::Ecdsa::P256::PublicKey & aKey)2144     void SetKey(const Crypto::Ecdsa::P256::PublicKey &aKey) { mKey = aKey; }
2145 
2146 private:
2147     Crypto::Ecdsa::P256::PublicKey mKey;
2148 } OT_TOOL_PACKED_END;
2149 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
2150 
2151 /**
2152  * Implements Resource Record body format of SIG type (RFC 2535 - section-4.1).
2153  */
2154 OT_TOOL_PACKED_BEGIN
2155 class SigRecord : public ResourceRecord, public Clearable<SigRecord>
2156 {
2157 public:
2158     static constexpr uint16_t kType = kTypeSig; ///< The SIG record type.
2159 
2160     /**
2161      * Initializes the SIG Resource Record by setting its type and class.
2162      *
2163      * Other record fields (TTL, length, ...) remain unchanged/uninitialized.
2164      *
2165      * SIG(0) requires SIG RR to set class field as ANY or `kClassAny` (RFC 2931 - section 3).
2166      *
2167      * @param[in] aClass  The class of the resource record.
2168      */
Init(uint16_t aClass)2169     void Init(uint16_t aClass) { ResourceRecord::Init(kTypeSig, aClass); }
2170 
2171     /**
2172      * Tells whether the SIG record is valid.
2173      *
2174      * @returns  TRUE if this is a valid SIG record, FALSE if not a valid SIG record.
2175      */
2176     bool IsValid(void) const;
2177 
2178     /**
2179      * Returns the SIG record's type-covered value.
2180      *
2181      * @returns The type-covered value.
2182      */
GetTypeCovered(void) const2183     uint16_t GetTypeCovered(void) const { return BigEndian::HostSwap16(mTypeCovered); }
2184 
2185     /**
2186      * Sets the SIG record's type-covered value.
2187      *
2188      * @param[in]  aTypeCovered  The type-covered value.
2189      */
SetTypeCovered(uint8_t aTypeCovered)2190     void SetTypeCovered(uint8_t aTypeCovered) { mTypeCovered = BigEndian::HostSwap16(aTypeCovered); }
2191 
2192     /**
2193      * Returns the SIG record's algorithm value.
2194      *
2195      * @returns The algorithm value.
2196      */
GetAlgorithm(void) const2197     uint8_t GetAlgorithm(void) const { return mAlgorithm; }
2198 
2199     /**
2200      * Sets the SIG record's algorithm value.
2201      *
2202      * @param[in]  aAlgorithm  The algorithm value.
2203      */
SetAlgorithm(uint8_t aAlgorithm)2204     void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; }
2205 
2206     /**
2207      * Returns the SIG record's labels-count (number of labels, not counting null label, in the original
2208      * name of the owner).
2209      *
2210      * @returns The labels-count value.
2211      */
GetLabels(void) const2212     uint8_t GetLabels(void) const { return mLabels; }
2213 
2214     /**
2215      * Sets the SIG record's labels-count (number of labels, not counting null label, in the original
2216      * name of the owner).
2217      *
2218      * @param[in]  aLabels  The labels-count value.
2219      */
SetLabels(uint8_t aLabels)2220     void SetLabels(uint8_t aLabels) { mLabels = aLabels; }
2221 
2222     /**
2223      * Returns the SIG record's original TTL value.
2224      *
2225      * @returns The original TTL value.
2226      */
GetOriginalTtl(void) const2227     uint32_t GetOriginalTtl(void) const { return BigEndian::HostSwap32(mOriginalTtl); }
2228 
2229     /**
2230      * Sets the SIG record's original TTL value.
2231      *
2232      * @param[in]  aOriginalTtl  The original TTL value.
2233      */
SetOriginalTtl(uint32_t aOriginalTtl)2234     void SetOriginalTtl(uint32_t aOriginalTtl) { mOriginalTtl = BigEndian::HostSwap32(aOriginalTtl); }
2235 
2236     /**
2237      * Returns the SIG record's expiration time value.
2238      *
2239      * @returns The expiration time value (seconds since Jan 1, 1970).
2240      */
GetExpiration(void) const2241     uint32_t GetExpiration(void) const { return BigEndian::HostSwap32(mExpiration); }
2242 
2243     /**
2244      * Sets the SIG record's expiration time value.
2245      *
2246      * @param[in]  aExpiration  The expiration time value (seconds since Jan 1, 1970).
2247      */
SetExpiration(uint32_t aExpiration)2248     void SetExpiration(uint32_t aExpiration) { mExpiration = BigEndian::HostSwap32(aExpiration); }
2249 
2250     /**
2251      * Returns the SIG record's inception time value.
2252      *
2253      * @returns The inception time value (seconds since Jan 1, 1970).
2254      */
GetInception(void) const2255     uint32_t GetInception(void) const { return BigEndian::HostSwap32(mInception); }
2256 
2257     /**
2258      * Sets the SIG record's inception time value.
2259      *
2260      * @param[in]  aInception  The inception time value (seconds since Jan 1, 1970).
2261      */
SetInception(uint32_t aInception)2262     void SetInception(uint32_t aInception) { mInception = BigEndian::HostSwap32(aInception); }
2263 
2264     /**
2265      * Returns the SIG record's key tag value.
2266      *
2267      * @returns The key tag value.
2268      */
GetKeyTag(void) const2269     uint16_t GetKeyTag(void) const { return BigEndian::HostSwap16(mKeyTag); }
2270 
2271     /**
2272      * Sets the SIG record's key tag value.
2273      *
2274      * @param[in]  aKeyTag  The key tag value.
2275      */
SetKeyTag(uint16_t aKeyTag)2276     void SetKeyTag(uint16_t aKeyTag) { mKeyTag = BigEndian::HostSwap16(aKeyTag); }
2277 
2278     /**
2279      * Returns a pointer to the start of the record data fields.
2280      *
2281      * @returns A pointer to the start of the record data fields.
2282      */
GetRecordData(void) const2283     const uint8_t *GetRecordData(void) const { return reinterpret_cast<const uint8_t *>(&mTypeCovered); }
2284 
2285     /**
2286      * Parses and reads the SIG signer name from a message.
2287      *
2288      * @param[in]      aMessage         The message to read from. `aMessage.GetOffset()` MUST point to the start of DNS
2289      *                                  header.
2290      * @param[in,out]  aOffset          On input, the offset in @p aMessage to start of signer name field.
2291      *                                  On exit when successfully read, @p aOffset is updated to point to the byte
2292      *                                  after the name field (i.e., start of signature field).
2293      * @param[out]     aNameBuffer      A pointer to a char array to output the read name as a null-terminated C string
2294      *                                  (MUST NOT be `nullptr`).
2295      * @param[in]      aNameBufferSize  The size of @p aNameBuffer.
2296      *
2297      * @retval kErrorNone           The name was read successfully. @p aOffset and @p aNameBuffer are updated.
2298      * @retval kErrorParse          The SIG record in @p aMessage could not be parsed (invalid format).
2299      * @retval kErrorNoBufs         Name could not fit in @p aNameBufferSize chars.
2300      */
ReadSignerName(const Message & aMessage,uint16_t & aOffset,char * aNameBuffer,uint16_t aNameBufferSize) const2301     Error ReadSignerName(const Message &aMessage, uint16_t &aOffset, char *aNameBuffer, uint16_t aNameBufferSize) const
2302     {
2303         return ResourceRecord::ReadName(aMessage, aOffset, /* aStartOffset */ aOffset - sizeof(SigRecord), aNameBuffer,
2304                                         aNameBufferSize,
2305                                         /* aSkipRecord */ false);
2306     }
2307 
2308 private:
2309     uint16_t mTypeCovered; // type of the other RRs covered by this SIG. set to zero for SIG(0).
2310     uint8_t  mAlgorithm;   // Algorithm number (see `KeyRecord` enumeration).
2311     uint8_t  mLabels;      // Number of labels (not counting null label) in the original name of the owner of RR.
2312     uint32_t mOriginalTtl; // Original time-to-live (should set to zero for SIG(0)).
2313     uint32_t mExpiration;  // Signature expiration time (seconds since Jan 1, 1970).
2314     uint32_t mInception;   // Signature inception time (seconds since Jan 1, 1970).
2315     uint16_t mKeyTag;      // Key tag.
2316     // Followed by signer name fields and signature fields
2317 } OT_TOOL_PACKED_END;
2318 
2319 /**
2320  * Implements DNS OPT Pseudo Resource Record header for EDNS(0) (RFC 6891 - Section 6.1).
2321  */
2322 OT_TOOL_PACKED_BEGIN
2323 class OptRecord : public ResourceRecord
2324 {
2325 public:
2326     static constexpr uint16_t kType = kTypeOpt; ///< The OPT record type.
2327 
2328     /**
2329      * Initializes the OPT Resource Record by setting its type and clearing extended Response Code, version
2330      * and all flags.
2331      *
2332      * Other record fields (UDP payload size, length) remain unchanged/uninitialized.
2333      */
Init(void)2334     void Init(void)
2335     {
2336         SetType(kTypeOpt);
2337         SetTtl(0);
2338     }
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      * The field is encoded in the CLASS field.
2345      *
2346      * @returns The UDP payload size.
2347      */
GetUdpPayloadSize(void) const2348     uint16_t GetUdpPayloadSize(void) const { return GetClass(); }
2349 
2350     /**
2351      * Gets the requester's UDP payload size (the number of bytes of the largest UDP payload that can be
2352      * delivered in the requester's network).
2353      *
2354      * @param[in] aPayloadSize  The UDP payload size.
2355      */
SetUdpPayloadSize(uint16_t aPayloadSize)2356     void SetUdpPayloadSize(uint16_t aPayloadSize) { SetClass(aPayloadSize); }
2357 
2358     /**
2359      * Gets the upper 8-bit of the extended 12-bit Response Code.
2360      *
2361      * Value of 0 indicates that an unextended Response code is in use.
2362      *
2363      * @return The upper 8-bit of the extended 12-bit Response Code.
2364      */
GetExtendedResponseCode(void) const2365     uint8_t GetExtendedResponseCode(void) const { return GetTtlByteAt(kExtRCodeByteIndex); }
2366 
2367     /**
2368      * Sets the upper 8-bit of the extended 12-bit Response Code.
2369      *
2370      * Value of 0 indicates that an unextended Response code is in use.
2371      *
2372      * @param[in] aExtendedResponse The upper 8-bit of the extended 12-bit Response Code.
2373      */
SetExtendedResponseCode(uint8_t aExtendedResponse)2374     void SetExtendedResponseCode(uint8_t aExtendedResponse) { GetTtlByteAt(kExtRCodeByteIndex) = aExtendedResponse; }
2375 
2376     /**
2377      * Gets the Version field.
2378      *
2379      * @returns The version.
2380      */
GetVersion(void) const2381     uint8_t GetVersion(void) const { return GetTtlByteAt(kVersionByteIndex); }
2382 
2383     /**
2384      * Set the Version field.
2385      *
2386      * @param[in] aVersion  The version.
2387      */
SetVersion(uint8_t aVersion)2388     void SetVersion(uint8_t aVersion) { GetTtlByteAt(kVersionByteIndex) = aVersion; }
2389 
2390     /**
2391      * Indicates whether the DNSSEC OK flag is set or not.
2392      *
2393      * @returns True if DNSSEC OK flag is set in the header, false otherwise.
2394      */
IsDnsSecurityFlagSet(void) const2395     bool IsDnsSecurityFlagSet(void) const { return (GetTtlByteAt(kFlagByteIndex) & kDnsSecFlag) != 0; }
2396 
2397     /**
2398      * Clears the DNSSEC OK bit flag.
2399      */
ClearDnsSecurityFlag(void)2400     void ClearDnsSecurityFlag(void) { GetTtlByteAt(kFlagByteIndex) &= ~kDnsSecFlag; }
2401 
2402     /**
2403      * Sets the DNSSEC OK bit flag.
2404      */
SetDnsSecurityFlag(void)2405     void SetDnsSecurityFlag(void) { GetTtlByteAt(kFlagByteIndex) |= kDnsSecFlag; }
2406 
2407 private:
2408     // The OPT RR re-purposes the existing CLASS and TTL fields in the
2409     // RR. The CLASS field (`uint16_t`) is used for requester UDP
2410     // payload size. The TTL field is used for extended Response Code,
2411     // version and flags as follows:
2412     //
2413     //    0   1   2   3   4   5   6   7   8   9   0   1   2   3   4   5
2414     //  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2415     //  |         EXTENDED-RCODE        |            VERSION            |
2416     //  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2417     //  | DO|                Z          |             Z                 |
2418     //  +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2419     //
2420     // The variable data part of OPT RR can contain zero of more `Option`.
2421 
2422     static constexpr uint8_t kExtRCodeByteIndex = 0;      // Byte index of Extended RCODE within the TTL field.
2423     static constexpr uint8_t kVersionByteIndex  = 1;      // Byte index of Version within the TTL field.
2424     static constexpr uint8_t kFlagByteIndex     = 2;      // Byte index of flag byte within the TTL field.
2425     static constexpr uint8_t kDnsSecFlag        = 1 << 7; // DNSSec OK bit flag.
2426 
GetTtlByteAt(uint8_t aIndex) const2427     uint8_t  GetTtlByteAt(uint8_t aIndex) const { return reinterpret_cast<const uint8_t *>(&mTtl)[aIndex]; }
GetTtlByteAt(uint8_t aIndex)2428     uint8_t &GetTtlByteAt(uint8_t aIndex) { return reinterpret_cast<uint8_t *>(&mTtl)[aIndex]; }
2429 
2430 } OT_TOOL_PACKED_END;
2431 
2432 /**
2433  * Implements the body of an Option in OPT Pseudo Resource Record (RFC 6981 - Section 6.1).
2434  */
2435 OT_TOOL_PACKED_BEGIN
2436 class Option
2437 {
2438 public:
2439     static constexpr uint16_t kUpdateLease = 2; ///< Update lease option code.
2440 
2441     /**
2442      * Returns the option code value.
2443      *
2444      * @returns The option code value.
2445      */
GetOptionCode(void) const2446     uint16_t GetOptionCode(void) const { return BigEndian::HostSwap16(mOptionCode); }
2447 
2448     /**
2449      * Sets the option code value.
2450      *
2451      * @param[in]  aOptionCode  The option code value.
2452      */
SetOptionCode(uint16_t aOptionCode)2453     void SetOptionCode(uint16_t aOptionCode) { mOptionCode = BigEndian::HostSwap16(aOptionCode); }
2454 
2455     /**
2456      * Returns the option length value.
2457      *
2458      * @returns The option length (size of option data in bytes).
2459      */
GetOptionLength(void) const2460     uint16_t GetOptionLength(void) const { return BigEndian::HostSwap16(mOptionLength); }
2461 
2462     /**
2463      * Sets the option length value.
2464      *
2465      * @param[in]  aOptionLength  The option length (size of option data in bytes).
2466      */
SetOptionLength(uint16_t aOptionLength)2467     void SetOptionLength(uint16_t aOptionLength) { mOptionLength = BigEndian::HostSwap16(aOptionLength); }
2468 
2469     /**
2470      * Returns the size of (number of bytes) in the Option and its data.
2471      *
2472      * @returns Size (number of bytes) of the Option its data section.
2473      */
GetSize(void) const2474     uint32_t GetSize(void) const { return sizeof(Option) + GetOptionLength(); }
2475 
2476 private:
2477     uint16_t mOptionCode;
2478     uint16_t mOptionLength;
2479     // Followed by Option data (varies per option code).
2480 
2481 } OT_TOOL_PACKED_END;
2482 
2483 /**
2484  * Implements an Update Lease Option body.
2485  *
2486  * This implementation is intended for use in Dynamic DNS Update Lease Requests and Responses as specified in
2487  * https://tools.ietf.org/html/draft-sekar-dns-ul-02.
2488  */
2489 OT_TOOL_PACKED_BEGIN
2490 class LeaseOption : public Option
2491 {
2492 public:
2493     /**
2494      * Initializes the Update Lease Option using the short variant format which contains lease interval
2495      * only.
2496      *
2497      * @param[in] aLeaseInterval     The lease interval in seconds.
2498      */
2499     void InitAsShortVariant(uint32_t aLeaseInterval);
2500 
2501     /**
2502      * Initializes the Update Lease Option using the long variant format which contains both lease and
2503      * key lease intervals.
2504      *
2505      * @param[in] aLeaseInterval     The lease interval in seconds.
2506      * @param[in] aKeyLeaseInterval  The key lease interval in seconds.
2507      */
2508     void InitAsLongVariant(uint32_t aLeaseInterval, uint32_t aKeyLeaseInterval);
2509 
2510     /**
2511      * Indicates whether or not the Update Lease Option follows the short variant format which contains
2512      * only the lease interval.
2513      *
2514      * @retval TRUE   The Update Lease Option follows the short variant format.
2515      * @retval FALSE  The Update Lease Option follows the long variant format.
2516      */
IsShortVariant(void) const2517     bool IsShortVariant(void) const { return (GetOptionLength() == kShortLength); }
2518 
2519     /**
2520      * Tells whether this is a valid Lease Option.
2521      *
2522      * Validates that option follows either short or long variant format.
2523      *
2524      * @returns  TRUE if this is a valid Lease Option, FALSE if not a valid Lease Option.
2525      */
2526     bool IsValid(void) const;
2527 
2528     /**
2529      * Returns the Update Lease OPT record's lease interval value.
2530      *
2531      * @returns The lease interval value (in seconds).
2532      */
GetLeaseInterval(void) const2533     uint32_t GetLeaseInterval(void) const { return BigEndian::HostSwap32(mLeaseInterval); }
2534 
2535     /**
2536      * Returns the Update Lease OPT record's key lease interval value.
2537      *
2538      * If the Update Lease Option follows the short variant format the lease interval is returned as key lease interval.
2539      *
2540      * @returns The key lease interval value (in seconds).
2541      */
GetKeyLeaseInterval(void) const2542     uint32_t GetKeyLeaseInterval(void) const
2543     {
2544         return IsShortVariant() ? GetLeaseInterval() : BigEndian::HostSwap32(mKeyLeaseInterval);
2545     }
2546 
2547     /**
2548      * Searches among the Options is a given message and reads and validates the Update Lease Option if
2549      * found.
2550      *
2551      * Reads the Update Lease Option whether it follows the short or long variant formats.
2552      *
2553      * @param[in] aMessage   The message to read the Option from.
2554      * @param[in] aOffset    Offset in @p aMessage to the start of Options (start of OPT Record data).
2555      * @param[in] aLength    Length of Option data in OPT record.
2556      *
2557      * @retval kErrorNone      Successfully read and validated the Update Lease Option from @p aMessage.
2558      * @retval kErrorNotFound  Did not find any Update Lease Option.
2559      * @retval kErrorParse     Failed to parse the Options.
2560      */
2561     Error ReadFrom(const Message &aMessage, uint16_t aOffset, uint16_t aLength);
2562 
2563 private:
2564     static constexpr uint16_t kShortLength = sizeof(uint32_t);                    // lease only.
2565     static constexpr uint16_t kLongLength  = sizeof(uint32_t) + sizeof(uint32_t); // lease and key lease values
2566 
SetLeaseInterval(uint32_t aLeaseInterval)2567     void SetLeaseInterval(uint32_t aLeaseInterval) { mLeaseInterval = BigEndian::HostSwap32(aLeaseInterval); }
SetKeyLeaseInterval(uint32_t aKeyLeaseInterval)2568     void SetKeyLeaseInterval(uint32_t aKeyLeaseInterval)
2569     {
2570         mKeyLeaseInterval = BigEndian::HostSwap32(aKeyLeaseInterval);
2571     }
2572 
2573     uint32_t mLeaseInterval;
2574     uint32_t mKeyLeaseInterval;
2575 } OT_TOOL_PACKED_END;
2576 
2577 /**
2578  * Implements body format of NSEC record (RFC 3845) for use with mDNS.
2579  */
2580 OT_TOOL_PACKED_BEGIN
2581 class NsecRecord : public ResourceRecord
2582 {
2583 public:
2584     static constexpr uint16_t kType = kTypeNsec; ///< The NSEC record type.
2585 
2586     /**
2587      * Represents NSEC Type Bit Map field (RFC 3845 - section 2.1.2)
2588      */
2589     OT_TOOL_PACKED_BEGIN
2590     class TypeBitMap : public Clearable<TypeBitMap>
2591     {
2592     public:
2593         static constexpr uint8_t kMinSize = 2; ///< Minimum size of a valid `TypeBitMap` (with zero length).
2594 
2595         static constexpr uint8_t kMaxLength = 32; ///< Maximum BitmapLength value.
2596 
2597         /**
2598          * Gets the Window Block Number
2599          *
2600          * @returns The Window Block Number.
2601          */
GetBlockNumber(void) const2602         uint8_t GetBlockNumber(void) const { return mBlockNumber; }
2603 
2604         /**
2605          * Sets the Window Block Number
2606          *
2607          * @param[in] aBlockNumber The Window Block Number.
2608          */
SetBlockNumber(uint8_t aBlockNumber)2609         void SetBlockNumber(uint8_t aBlockNumber) { mBlockNumber = aBlockNumber; }
2610 
2611         /**
2612          * Gets the Bitmap length
2613          *
2614          * @returns The Bitmap length
2615          */
GetBitmapLength(void)2616         uint8_t GetBitmapLength(void) { return mBitmapLength; }
2617 
2618         /**
2619          * Gets the total size (number of bytes) of the `TypeBitMap` field.
2620          *
2621          * @returns The size of the `TypeBitMap`
2622          */
GetSize(void) const2623         uint16_t GetSize(void) const { return (sizeof(mBlockNumber) + sizeof(mBitmapLength) + mBitmapLength); }
2624 
2625         /**
2626          * Adds a resource record type to the Bitmap.
2627          *
2628          * As the types are added to the Bitmap the Bitmap length gets updated accordingly.
2629          *
2630          * The type space is split into 256 window blocks, each representing the low-order 8 bits of the 16-bit type
2631          * value. If @p aType does not match the currently set Window Block Number, no action is performed.
2632          *
2633          * @param[in] aType   The resource record type to add.
2634          */
2635         void AddType(uint16_t aType);
2636 
2637         /**
2638          * Indicates whether a given resource record type is present in the Bitmap.
2639          *
2640          * If @p aType does not match the currently set Window Block Number, this method returns `false`..
2641          *
2642          * @param[in] aType   The resource record type to check.
2643          *
2644          * @retval TRUE   The @p aType is present in the Bitmap.
2645          * @retval FALSE  The @p aType is not present in the Bitmap.
2646          */
2647         bool ContainsType(uint16_t aType) const;
2648 
2649     private:
2650         uint8_t mBlockNumber;
2651         uint8_t mBitmapLength;
2652         uint8_t mBitmaps[kMaxLength];
2653     } OT_TOOL_PACKED_END;
2654 
2655     /**
2656      * Initializes the NSEC Resource Record by setting its type and class.
2657      *
2658      * Other record fields (TTL, length remain unchanged/uninitialized.
2659      *
2660      * @param[in] aClass  The class of the resource record (default is `kClassInternet`).
2661      */
Init(uint16_t aClass=kClassInternet)2662     void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeNsec, aClass); }
2663 
2664 } OT_TOOL_PACKED_END;
2665 
2666 /**
2667  * Implements Question format.
2668  */
2669 OT_TOOL_PACKED_BEGIN
2670 class Question
2671 {
2672 public:
2673     /**
2674      * Default constructor for Question
2675      */
2676     Question(void) = default;
2677 
2678     /**
2679      * Constructor for Question.
2680      */
Question(uint16_t aType,uint16_t aClass=ResourceRecord::kClassInternet)2681     explicit Question(uint16_t aType, uint16_t aClass = ResourceRecord::kClassInternet)
2682     {
2683         SetType(aType);
2684         SetClass(aClass);
2685     }
2686 
2687     /**
2688      * Returns the type of the question.
2689      *
2690      * @returns The type of the question.
2691      */
GetType(void) const2692     uint16_t GetType(void) const { return BigEndian::HostSwap16(mType); }
2693 
2694     /**
2695      * Sets the type of the question.
2696      *
2697      * @param[in]  aType The type of the question.
2698      */
SetType(uint16_t aType)2699     void SetType(uint16_t aType) { mType = BigEndian::HostSwap16(aType); }
2700 
2701     /**
2702      * Returns the class of the question.
2703      *
2704      * @returns The class of the question.
2705      */
GetClass(void) const2706     uint16_t GetClass(void) const { return BigEndian::HostSwap16(mClass); }
2707 
2708     /**
2709      * Sets the class of the question.
2710      *
2711      * @param[in]  aClass The class of the question.
2712      */
SetClass(uint16_t aClass)2713     void SetClass(uint16_t aClass) { mClass = BigEndian::HostSwap16(aClass); }
2714 
2715 private:
2716     uint16_t mType;  // The type of the data in question section.
2717     uint16_t mClass; // The class of the data in question section.
2718 } OT_TOOL_PACKED_END;
2719 
2720 /**
2721  * Implements Zone section body for DNS Update (RFC 2136 - section 2.3).
2722  */
2723 OT_TOOL_PACKED_BEGIN
2724 class Zone : public Question
2725 {
2726 public:
2727     /**
2728      * Constructor for Zone.
2729      *
2730      * @param[in] aClass  The class of the zone (default is `kClassInternet`).
2731      */
Zone(uint16_t aClass=ResourceRecord::kClassInternet)2732     explicit Zone(uint16_t aClass = ResourceRecord::kClassInternet)
2733         : Question(ResourceRecord::kTypeSoa, aClass)
2734     {
2735     }
2736 } OT_TOOL_PACKED_END;
2737 
2738 /**
2739  * @}
2740  */
2741 
2742 } // namespace Dns
2743 
2744 DefineCoreType(otDnsTxtEntry, Dns::TxtEntry);
2745 DefineCoreType(otDnsTxtEntryIterator, Dns::TxtEntry::Iterator);
2746 
2747 } // namespace ot
2748 
2749 #endif // DNS_HEADER_HPP_
2750