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