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