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