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