From 418c9afbe27d0fd359e0e5eb38ed041a1db5c823 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 9 Dec 2020 00:39:45 -0800 Subject: [PATCH] [dns] support new resource records (PTR, SRV, TXT, KEY, SIG, OPT) (#6048) --- src/core/net/dns_client.cpp | 12 +- src/core/net/dns_headers.cpp | 72 ++- src/core/net/dns_headers.hpp | 908 +++++++++++++++++++++++++++++++++-- 3 files changed, 939 insertions(+), 53 deletions(-) diff --git a/src/core/net/dns_client.cpp b/src/core/net/dns_client.cpp index c59fc9b01..5e0c459c4 100644 --- a/src/core/net/dns_client.cpp +++ b/src/core/net/dns_client.cpp @@ -346,12 +346,12 @@ void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessag // which it sent the corresponding query to. OT_UNUSED_VARIABLE(aMessageInfo); - otError error = OT_ERROR_NOT_FOUND; - Header responseHeader; - QueryMetadata queryMetadata; - ResourceRecordAaaa record; - Message * message = nullptr; - uint16_t offset; + otError error = OT_ERROR_NOT_FOUND; + Header responseHeader; + QueryMetadata queryMetadata; + AaaaRecord record; + Message * message = nullptr; + uint16_t offset; SuccessOrExit(aMessage.Read(aMessage.GetOffset(), responseHeader)); VerifyOrExit(responseHeader.GetType() == Header::kTypeResponse && responseHeader.GetQuestionCount() == 1 && diff --git a/src/core/net/dns_headers.cpp b/src/core/net/dns_headers.cpp index 21ff0dbac..855b6a566 100644 --- a/src/core/net/dns_headers.cpp +++ b/src/core/net/dns_headers.cpp @@ -35,6 +35,7 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" +#include "common/random.hpp" #include "common/string.hpp" namespace ot { @@ -42,6 +43,62 @@ namespace Dns { using ot::Encoding::BigEndian::HostSwap16; +otError Header::SetRandomMessageId(void) +{ + return Random::Crypto::FillBuffer(reinterpret_cast(&mMessageId), sizeof(mMessageId)); +} + +otError Header::ResponseCodeToError(Response aResponse) +{ + otError error = OT_ERROR_FAILED; + + switch (aResponse) + { + case kResponseSuccess: + error = OT_ERROR_NONE; + break; + + case kResponseFormatError: // Server unable to interpret request due to format error. + case kResponseBadName: // Bad name. + case kResponseBadTruncation: // Bad truncation. + case kResponseNotZone: // A name is not in the zone. + error = OT_ERROR_PARSE; + break; + + case kResponseServerFailure: // Server encountered an internal failure. + error = OT_ERROR_FAILED; + break; + + case kResponseNameError: // Name that ought to exist, does not exists. + case kResponseRecordNotExists: // Some RRset that out to exist, does not exist. + error = OT_ERROR_NOT_FOUND; + break; + + case kResponseNotImplemented: // Server does not support the query type (OpCode). + error = OT_ERROR_NOT_IMPLEMENTED; + break; + + case kResponseBadAlg: // Bad algorithm. + error = OT_ERROR_NOT_CAPABLE; + break; + + case kResponseNameExists: // Some name that ought not to exist, does exist. + case kResponseRecordExists: // Some RRset that ought not to exits, does exist. + error = OT_ERROR_DUPLICATED; + break; + + case kResponseRefused: // Server refused to perform operation for policy or security reasons. + case kResponseNotAuth: // Service is not authoritative for zone. + error = OT_ERROR_SECURITY; + break; + + default: + break; + } + + return error; +} + otError Name::AppendLabel(const char *aLabel, Message &aMessage) { return AppendLabel(aLabel, static_cast(StringLength(aLabel, kMaxLabelLength + 1)), aMessage); @@ -316,20 +373,5 @@ exit: return error; } -void ResourceRecord::Init(uint16_t aType, uint16_t aClass, uint32_t aTtl) -{ - SetType(aType); - SetClass(aClass); - SetTtl(aTtl); - SetLength(0); -} - -void ResourceRecordAaaa::Init(void) -{ - ResourceRecord::Init(kTypeAaaa); - SetLength(sizeof(mAddress)); - mAddress.Clear(); -} - } // namespace Dns } // namespace ot diff --git a/src/core/net/dns_headers.hpp b/src/core/net/dns_headers.hpp index 9d35d1f46..f218fd678 100644 --- a/src/core/net/dns_headers.hpp +++ b/src/core/net/dns_headers.hpp @@ -94,6 +94,15 @@ public: */ void SetMessageId(uint16_t aMessageId) { mMessageId = HostSwap16(aMessageId); } + /** + * This method sets the Message ID to a crypto-secure randomly generated number. + * + * @retval OT_ERROR_NONE Successfully generated random Message ID. + * @retval OT_ERROR_FAILED Could not generate random Message ID. + * + */ + otError SetRandomMessageId(void); + /** * Defines types of DNS message. * @@ -244,17 +253,20 @@ public: */ enum Response { - kResponseSuccess = 0, - kResponseFormatError = 1, - kResponseServerFailure = 2, - kResponseNameError = 3, - kResponseNotImplemented = 4, - kResponseRefused = 5, - kResponseNotAuth = 9, - kResponseNotZone = 10, - kResponseBadName = 20, - kResponseBadAlg = 21, - kResponseBadTruncation = 22, + kResponseSuccess = 0, ///< Success (no error condition). + kResponseFormatError = 1, ///< Server unable to interpret request due to format error. + kResponseServerFailure = 2, ///< Server encountered an internal failure. + kResponseNameError = 3, ///< Name that ought to exist, does not exists. + kResponseNotImplemented = 4, ///< Server does not support the query type (OpCode). + kResponseRefused = 5, ///< Server refused to perform operation for policy or security reasons. + kResponseNameExists = 6, ///< Some name that ought not to exist, does exist. + kResponseRecordExists = 7, ///< Some RRset that ought not to exits, does exist. + kResponseRecordNotExists = 8, ///< Some RRset that ought to exist, does not exist. + kResponseNotAuth = 9, ///< Service is not authoritative for zone. + kResponseNotZone = 10, ///< A name is not in the zone. + kResponseBadName = 20, ///< Bad name. + kResponseBadAlg = 21, ///< Bad algorithm. + kResponseBadTruncation = 22, ///< Bad truncation. }; /** @@ -277,6 +289,30 @@ public: mFlags[1] |= static_cast(aResponse) << kRCodeOffset; } + /** + * This method converts a Response Code into a related `otError`. + * + * - kResponseSuccess (0) : Success (no error condition) -> OT_ERROR_NONE + * - kResponseFormatError (1) : Server unable to interpret due to format error -> OT_ERROR_PARSE + * - kResponseServerFailure (2) : Server encountered an internal failure -> OT_ERROR_FAILED + * - kResponseNameError (3) : Name that ought to exist, does not exists -> OT_ERROR_NOT_FOUND + * - kResponseNotImplemented (4) : Server does not support the query type (OpCode) -> OT_ERROR_NOT_IMPLEMENTED + * - kResponseRefused (5) : Server refused for policy/security reasons -> OT_ERROR_SECURITY + * - kResponseNameExists (6) : Some name that ought not to exist, does exist -> OT_ERROR_DUPLICATED + * - kResponseRecordExists (7) : Some RRset that ought not to exits, does exist -> OT_ERROR_DUPLICATED + * - kResponseRecordNotExists (8) : Some RRset that ought to exist, does not exist -> OT_ERROR_NOT_FOUND + * - kResponseNotAuth (9) : Service is not authoritative for zone -> OT_ERROR_SECURITY + * - kResponseNotZone (10) : A name is not in the zone -> OT_ERROR_PARSE + * - kResponseBadName (20) : Bad name -> OT_ERROR_PARSE + * - kResponseBadAlg (21) : Bad algorithm -> OT_ERROR_SECURITY + * - kResponseBadTruncation (22) : Bad truncation -> OT_ERROR_PARSE + * - Other error -> OT_ERROR_FAILED + * + * @param[in] aResponse The response code to convert. + * + */ + static otError ResponseCodeToError(Response aResponse); + /** * This method returns the number of entries in question section. * @@ -374,6 +410,74 @@ private: } OT_TOOL_PACKED_END; +/** + * This class implements DNS Update message header generation and parsing. + * + * The DNS header specifies record counts for its four sections: Question, Answer, Authority, and Additional. A DNS + * Update header uses the same fields, and the same section formats, but the naming and use of these sections differs: + * DNS Update header uses Zone, Prerequisite, Update, Additional Data sections. + * + */ +OT_TOOL_PACKED_BEGIN +class UpdateHeader : public Header +{ +public: + /** + * Default constructor for DNS Update message header. + * + */ + UpdateHeader(void) { SetQueryType(kQueryTypeUpdate); } + + /** + * This method returns the number of records in Zone section. + * + * @returns The number of records in Zone section. + * + */ + uint16_t GetZoneRecordCount(void) const { return GetQuestionCount(); } + + /** + * This method sets the number of records in Zone section. + * + * @param[in] aCount The number of records in Zone section. + * + */ + void SetZoneRecordCount(uint16_t aCount) { SetQuestionCount(aCount); } + + /** + * This method returns the number of records in Prerequisite section. + * + * @returns The number of records in Prerequisite section. + * + */ + uint16_t GetPrerequisiteRecordCount(void) const { return GetAnswerCount(); } + + /** + * This method sets the number of records in Prerequisite section. + * + * @param[in] aCount The number of records in Prerequisite section. + * + */ + void SetPrerequisiteRecordCount(uint16_t aCount) { SetAnswerCount(aCount); } + + /** + * This method returns the number of records in Update section. + * + * @returns The number of records in Update section. + * + */ + uint16_t GetUpdateRecordCount(void) const { return GetAuthorityRecordsCount(); } + + /** + * This method sets the number of records in Update section. + * + * @param[in] aCount The number of records in Update section. + * + */ + void SetUpdateRecordCount(uint16_t aCount) { SetAuthorityRecordsCount(aCount); } + +} OT_TOOL_PACKED_END; + /** * This class implement helper methods for encoding/decoding of DNS Names. * @@ -611,12 +715,14 @@ private: }; /** - * This class implements Resource Record body format (RR). + * This class implements Resource Record (RR) body format. * */ OT_TOOL_PACKED_BEGIN class ResourceRecord { + friend class OptRecord; + public: /** * Resource Record Types. @@ -624,13 +730,17 @@ public: */ enum : uint16_t { - kTypeA = 1, ///< Address record (IPv4). - kTypePtr = 12, ///< PTR record. - kTypeTxt = 16, ///< TXT record. - kTypeSrv = 33, ///< SRV locator record. - kTypeAaaa = 28, ///< IPv6 address record. - kTypeKey = 25, ///< Key record. - kTypeOpt = 41, ///< Option record. + kTypeZero = 0, ///< Zero is used as a special indicator for the SIG RR (SIG(0) from RFC 2931). + kTypeA = 1, ///< Address record (IPv4). + kTypeSoa = 6, ///< Start of (zone of) authority. + kTypePtr = 12, ///< PTR record. + kTypeTxt = 16, ///< TXT record. + kTypeSig = 24, ///< SIG record. + kTypeKey = 25, ///< KEY record. + kTypeAaaa = 28, ///< IPv6 address record. + kTypeSrv = 33, ///< SRV locator record. + kTypeOpt = 41, ///< Option record. + kTypeAny = 255, ///< ANY record. }; /** @@ -639,18 +749,25 @@ public: */ enum : uint16_t { - kClassInternet = 1, ///< Class code Internet (IN). + kClassInternet = 1, ///< Class code Internet (IN). + kClassNone = 254, ///< Class code None (NONE) - RFC 2136. + kClassAny = 255, ///< Class code Any (ANY). }; /** - * This method initializes the resource record. + * This method initializes the resource record by setting its type and class. + * + * This method only sets the type and class fields. Other fields (TTL and length) remain unchanged/uninitialized. * * @param[in] aType The type of the resource record. * @param[in] aClass The class of the resource record (default is `kClassInternet`). - * @param[in] aTtl The time to live field of the resource record (default is zero). * */ - void Init(uint16_t aType, uint16_t aClass = kClassInternet, uint32_t aTtl = 0); + void Init(uint16_t aType, uint16_t aClass = kClassInternet) + { + SetType(aType); + SetClass(aClass); + } /** * This method indicates whether the resources records matches a given type and class code. @@ -686,6 +803,7 @@ public: * This method returns the class of the resource record. * * @returns The class of the resource record. + * */ uint16_t GetClass(void) const { return HostSwap16(mClass); } @@ -714,16 +832,17 @@ public: void SetTtl(uint32_t aTtl) { mTtl = HostSwap32(aTtl); } /** - * This method returns the length of the resource record. + * This method returns the length of the resource record data. + * + * @returns The length of the resource record data. * - * @returns The length of the resource record. */ uint16_t GetLength(void) const { return HostSwap16(mLength); } /** - * This method sets the length of the resource record. + * This method sets the length of the resource record data. * - * @param[in] aLength The length of the resource record. + * @param[in] aLength The length of the resource record data. * */ void SetLength(uint16_t aLength) { mLength = HostSwap16(aLength); } @@ -745,19 +864,61 @@ private: } OT_TOOL_PACKED_END; +/** + * This class implements Resource Record body format of PTR type. + * + */ +OT_TOOL_PACKED_BEGIN +class PtrRecord : public ResourceRecord +{ +public: + /** + * This method initializes the PTR Resource Record by setting its type and class. + * + * Other record fields (TTL, length) remain unchanged/uninitialized. + * + * @param[in] aClass The class of the resource record (default is `kClassInternet`). + * + */ + void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypePtr, aClass); } + +} OT_TOOL_PACKED_END; + +/** + * This class implements Resource Record body format of TXT type. + * + */ +OT_TOOL_PACKED_BEGIN +class TxtRecord : public ResourceRecord +{ +public: + /** + * This method initializes the TXT Resource Record by setting its type and class. + * + * Other record fields (TTL, length) remain unchanged/uninitialized. + * + * @param[in] aClass The class of the resource record (default is `kClassInternet`). + * + */ + void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeTxt, aClass); } + +} OT_TOOL_PACKED_END; + /** * This class implements Resource Record body format of AAAA type. * */ OT_TOOL_PACKED_BEGIN -class ResourceRecordAaaa : public ResourceRecord +class AaaaRecord : public ResourceRecord { public: /** - * This method initializes the AAAA Resource Record. + * This method initializes the AAAA Resource Record by setting its type, class, and length. + * + * Other record fields (TTL, address) remain unchanged/uninitialized. * */ - void Init(void); + void Init(void) { ResourceRecord::Init(kTypeAaaa); } /** * This method sets the IPv6 address of the resource record. @@ -765,7 +926,7 @@ public: * @param[in] aAddress The IPv6 address of the resource record. * */ - void SetAddress(Ip6::Address &aAddress) { mAddress = aAddress; } + void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; } /** * This method returns the reference to IPv6 address of the resource record. @@ -773,12 +934,675 @@ public: * @returns The reference to IPv6 address of the resource record. * */ - Ip6::Address &GetAddress(void) { return mAddress; } + const Ip6::Address &GetAddress(void) const { return mAddress; } private: Ip6::Address mAddress; // IPv6 Address of AAAA Resource Record. } OT_TOOL_PACKED_END; +/** + * This class implements Resource Record body format of SRV type (RFC 2782). + * + */ +OT_TOOL_PACKED_BEGIN +class SrvRecord : public ResourceRecord +{ +public: + /** + * This method initializes the SRV Resource Record by settings its type and class. + * + * Other record fields (TTL, length, propriety, weight, port, ...) remain unchanged/uninitialized. + * + * @param[in] aClass The class of the resource record (default is `kClassInternet`). + * + */ + void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeSrv, aClass); } + + /** + * This method returns the SRV record's priority value. + * + * @returns The priority value. + * + */ + uint16_t GetPriority(void) const { return HostSwap16(mPriority); } + + /** + * This method sets the SRV record's priority value. + * + * @param[in] aPriority The priority value. + * + */ + void SetPriority(uint16_t aPriority) { mPriority = HostSwap16(aPriority); } + + /** + * This method returns the SRV record's weight value. + * + * @returns The weight value. + * + */ + uint16_t GetWeight(void) const { return HostSwap16(mWeight); } + + /** + * This method sets the SRV record's weight value. + * + * @param[in] aWeight The weight value. + * + */ + void SetWeight(uint16_t aWeight) { mWeight = HostSwap16(aWeight); } + + /** + * This method returns the SRV record's port number on the target host for this service. + * + * @returns The port number. + * + */ + uint16_t GetPort(void) const { return HostSwap16(mPort); } + + /** + * This method sets the SRV record's port number on the target host for this service. + * + * @param[in] aPort The port number. + * + */ + void SetPort(uint16_t aPort) { mPort = HostSwap16(aPort); } + +private: + uint16_t mPriority; + uint16_t mWeight; + uint16_t mPort; + // Followed by the target host domain name. + +} OT_TOOL_PACKED_END; + +/** + * This class implements Resource Record body format of KEY type (RFC 2535). + * + */ +OT_TOOL_PACKED_BEGIN +class KeyRecord : public ResourceRecord +{ +public: + /** + * This enumeration defines protocol field values (RFC 2535 - section 3.1.3). + * + */ + enum : uint8_t + { + kProtocolTls = 1, ///< TLS protocol code. + kProtocolDnsSec = 3, ///< DNS security protocol code. + }; + + /** + * This enumeration defines algorithm field values (RFC 8624 - section 3.1). + * + */ + enum : uint8_t + { + kAlgorithmEcdsaP256Sha256 = 13, ///< ECDSA-P256-SHA256 algorithm. + kAlgorithmEcdsaP384Sha384 = 14, ///< ECDSA-P384-SHA384 algorithm. + kAlgorithmEd25519 = 15, ///< ED25519 algorithm. + kAlgorithmEd448 = 16, ///< ED448 algorithm. + }; + + /** + * This enumeration type represents the use (or key type) flags (RFC 2535 - section 3.1.2). + * + */ + enum UseFlags : uint8_t + { + kAuthConfidPermitted = 0x00, ///< Use of the key for authentication and/or confidentiality is permitted. + kAuthPermitted = 0x40, ///< Use of the key is only permitted for authentication. + kConfidPermitted = 0x80, ///< Use of the key is only permitted for confidentiality. + kNoKey = 0xc0, ///< No key value (e.g., can indicate zone is not secure). + }; + + /** + * This enumeration type represents key owner (or name type) flags (RFC 2535 - section 3.1.2). + * + */ + enum OwnerFlags : uint8_t + { + kOwnerUser = 0x00, ///< Key is associated with a "user" or "account" at end entity. + kOwnerZone = 0x01, ///< Key is a zone key (used for data origin authentication). + kOwnerNonZone = 0x02, ///< Key is associated with a non-zone "entity". + kOwnerReserved = 0x03, ///< Reserved for future use. + }; + + /** + * This enumeration defines flag bits for the "signatory" flags (RFC 2137). + * + * The flags defined are for non-zone (`kOwnerNoneZone`) keys (RFC 2137 - section 3.1.3). + * + */ + enum : uint8_t + { + kSignatoryFlagZone = 1 << 3, ///< Key is authorized to attach, detach, and move zones. + kSignatoryFlagStrong = 1 << 2, ///< Key is authorized to add and delete RRs even if RRs auth with other key. + kSignatoryFlagUnique = 1 << 1, ///< Key is authorized to add and update RRs for only a single owner name. + kSignatoryFlagGeneral = 1 << 0, ///< If the other flags are zero, this is used to indicate it is an update key. + }; + + /** + * This method initializes the KEY Resource Record by setting its type and class. + * + * Other record fields (TTL, length, flags, protocol, algorithm) remain unchanged/uninitialized. + * + * @param[in] aClass The class of the resource record (default is `kClassInternet`). + * + */ + void Init(uint16_t aClass = kClassInternet) { ResourceRecord::Init(kTypeKey, aClass); } + + /** + * This method gets the key use (or key type) flags. + * + * @returns The key use flags. + * + */ + UseFlags GetUseFlags(void) const { return static_cast(mFlags[0] & kUseFlagsMask); } + + /** + * This method gets the owner (or name type) flags. + * + * @returns The key owner flags. + * + */ + OwnerFlags GetOwnerFlags(void) const { return static_cast(mFlags[0] & kOwnerFlagsMask); } + + /** + * This method gets the signatory flags. + * + * @returns The signatory flags. + * + */ + uint8_t GetSignatoryFlags(void) const { return (mFlags[1] & kSignatoryFlagsMask); } + + /** + * This method sets the flags field. + * + * @param[in] aUseFlags The `UseFlags` value. + * @param[in] aOwnerFlags The `OwnerFlags` value. + * @param[in] aSignatoryFlags The signatory flags. + * + */ + void SetFlags(UseFlags aUseFlags, OwnerFlags aOwnerFlags, uint8_t aSignatoryFlags) + { + mFlags[0] = (static_cast(aUseFlags) | static_cast(aOwnerFlags)); + mFlags[1] = (aSignatoryFlags & kSignatoryFlagsMask); + } + + /** + * This method returns the KEY record's protocol value. + * + * @returns The protocol value. + * + */ + uint8_t GetProtocol(void) const { return mProtocol; } + + /** + * This method sets the KEY record's protocol value. + * + * @param[in] aProtocol The protocol value. + * + */ + void SetProtocol(uint8_t aProtocol) { mProtocol = aProtocol; } + + /** + * This method returns the KEY record's algorithm value. + * + * @returns The algorithm value. + * + */ + uint8_t GetAlgorithm(void) const { return mAlgorithm; } + + /** + * This method sets the KEY record's algorithm value. + * + * @param[in] aAlgorithm The algorithm value. + * + */ + void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; } + +private: + enum : uint8_t + { + kUseFlagsMask = 0xc0, // top two bits in the first flag byte. + kOwnerFlagsMask = 0x03, // lowest two bits in the first flag byte. + kSignatoryFlagsMask = 0x0f, // lower 4 bits in the second flag byte. + }; + + // Flags format: + // + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + // | Use | Z | XT| Z | Z | Owner | Z | Z | Z | Z | SIG | + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + // \ / \ / + // ---------- mFlags[0] --------- -------- mFlags[1] ---------- + + uint8_t mFlags[2]; + uint8_t mProtocol; + uint8_t mAlgorithm; + // Followed by the public key + +} OT_TOOL_PACKED_END; + +/** + * This class implements Resource Record body format of SIG type (RFC 2535 - section-4.1). + * + * + */ +OT_TOOL_PACKED_BEGIN +class SigRecord : public ResourceRecord, public Clearable +{ +public: + /** + * This method initializes the SIG Resource Record by setting its type and class. + * + * Other record fields (TTL, length, ...) remain unchanged/uninitialized. + * + * SIG(0) requires SIG RR to set class field as ANY or `kClassAnyANY (RFC 2931 - section 3). + * + * @param[in] aClass The class of the resource record. + * + */ + void Init(uint16_t aClass) { ResourceRecord::Init(kTypeSig, aClass); } + + /** + * This method returns the SIG record's type-covered value. + * + * @returns The type-covered value. + * + */ + uint16_t GetTypeCovered(void) const { return HostSwap16(mTypeCovered); } + + /** + * This method sets the SIG record's type-covered value. + * + * @param[in] aTypeCovered The type-covered value. + * + */ + void SetTypeCovered(uint8_t aTypeCovered) { mTypeCovered = HostSwap16(aTypeCovered); } + + /** + * This method returns the SIG record's algorithm value. + * + * @returns The algorithm value. + * + */ + uint8_t GetAlgorithm(void) const { return mAlgorithm; } + + /** + * This method sets the SIG record's algorithm value. + * + * @param[in] aAlgorithm The algorithm value. + * + */ + void SetAlgorithm(uint8_t aAlgorithm) { mAlgorithm = aAlgorithm; } + + /** + * This method returns the SIG record's labels-count (number of labels, not counting null label, in the original + * name of the owner). + * + * @returns The labels-count value. + * + */ + uint8_t GetLabels(void) const { return mLabels; } + + /** + * This method sets the SIG record's labels-count (number of labels, not counting null label, in the original + * name of the owner). + * + * @param[in] aLabels The labels-count value. + * + */ + void SetLabels(uint8_t aLabels) { mLabels = aLabels; } + + /** + * This method returns the SIG record's original TTL value. + * + * @returns The original TTL value. + * + */ + uint32_t GetOriginalTtl(void) const { return HostSwap32(mOriginalTtl); } + + /** + * This method sets the SIG record's original TTL value. + * + * @param[in] aOriginalTtl The original TTL value. + * + */ + void SetOriginalTtl(uint32_t aOriginalTtl) { mOriginalTtl = HostSwap32(aOriginalTtl); } + + /** + * This method returns the SIG record's expiration time value. + * + * @returns The expiration time value (seconds since Jan 1, 1970). + * + */ + uint32_t GetExpiration(void) const { return HostSwap32(mExpiration); } + + /** + * This method sets the SIG record's expiration time value. + * + * @param[in] aExpiration The expiration time value (seconds since Jan 1, 1970). + * + */ + void SetExpiration(uint32_t aExpiration) { mExpiration = HostSwap32(aExpiration); } + + /** + * This method returns the SIG record's inception time value. + * + * @returns The inception time value (seconds since Jan 1, 1970). + * + */ + uint32_t GetInception(void) const { return HostSwap32(mInception); } + + /** + * This method sets the SIG record's inception time value. + * + * @param[in] aInception The inception time value (seconds since Jan 1, 1970). + * + */ + void SetInception(uint32_t aInception) { mInception = HostSwap32(aInception); } + + /** + * This method returns the SIG record's key tag value. + * + * @returns The key tag value. + * + */ + uint16_t GetKeyTag(void) const { return HostSwap16(mKeyTag); } + + /** + * This method sets the SIG record's key tag value. + * + * @param[in] aKeyTag The key tag value. + * + */ + void SetKeyTag(uint16_t aKeyTag) { mKeyTag = HostSwap16(aKeyTag); } + + /** + * This method returns a pointer to the start of the record data fields. + * + * @returns A pointer to the start of the record data fields. + * + */ + const uint8_t *GetRecordData(void) const { return reinterpret_cast(&mTypeCovered); } + +private: + uint16_t mTypeCovered; // type of the other RRs covered by this SIG. set to zero for SIG(0). + uint8_t mAlgorithm; // Algorithm number (see `KeyRecord` enumeration). + uint8_t mLabels; // Number of labels (not counting null label) in the original name of the owner of RR. + uint32_t mOriginalTtl; // Original time-to-live (should set to zero for SIG(0)). + uint32_t mExpiration; // Signature expiration time (seconds since Jan 1, 1970). + uint32_t mInception; // Signature inception time (seconds since Jan 1, 1970). + uint16_t mKeyTag; // Key tag. + // Followed by signer name fields and signature fields +} OT_TOOL_PACKED_END; + +/** + * This class implements DNS OPT Pseudo Resource Record header for EDNS(0) (RFC 6981 - Section 6.1). + * + */ +OT_TOOL_PACKED_BEGIN +class OptRecord : public ResourceRecord +{ +public: + /** + * This method initializes the OPT Resource Record by setting its type and clearing extended Response Code, version + * and all flags. + * + * Other record fields (UDP payload size, length) remain unchanged/uninitialized. + * + */ + void Init(void) + { + SetType(kTypeOpt); + SetTtl(0); + } + + /** + * This method gets the requester's UDP payload size (the number of bytes of the largest UDP payload that can be + * delivered in the requester's network). + * + * The field is encoded in the CLASS field. + * + * @returns The UDP payload size. + * + */ + uint16_t GetUdpPayloadSize(void) const { return GetClass(); } + + /** + * This method gets the requester's UDP payload size (the number of bytes of the largest UDP payload that can be + * delivered in the requester's network). + * + * @param[in] aPayloadSize The UDP payload size. + * + */ + void SetUdpPayloadSize(uint16_t aPayloadSize) { SetClass(aPayloadSize); } + + /** + * This method gets the upper 8-bit of the extended 12-bit Response Code. + * + * Value of 0 indicates that an unextended Response code is in use. + * + * @return The upper 8-bit of the extended 12-bit Response Code. + * + */ + uint8_t GetExtendedResponseCode(void) const + { + return static_cast((mTtl & kExtRCodeMask) >> kExtRCodeffset); + } + + /** + * This method sets the upper 8-bit of the extended 12-bit Response Code. + * + * Value of 0 indicates that an unextended Response code is in use. + * + * @param[in] aExtendedResponse The upper 8-bit of the extended 12-bit Response Code. + * + */ + void SetExtnededResponseCode(uint8_t aExtendedResponse) + { + mTtl &= ~kExtRCodeffset; + mTtl |= (static_cast(aExtendedResponse) << kExtRCodeffset); + } + + /** + * This method gets the Version field. + * + * @returns The version. + * + */ + uint8_t GetVersion(void) const { return static_cast((mTtl & kVersionMask) >> kVersionOffset); } + + /** + * This method set the Version field. + * + * @param[in] aVersion The version. + * + */ + void SetVersion(uint8_t aVersion) + { + mTtl &= ~kVersionMask; + mTtl |= (static_cast(aVersion) << kVersionOffset); + } + + /** + * This method indicates whether the DNSSEC OK flag is set or not. + * + * @returns True if DNSSEC OK flag is set in the header, false otherwise. + * + */ + bool IsDnsSecurityFlagSet(void) const { return (mTtl & kDnsSecFlag) != 0; } + + /** + * This method clears the DNSSEC OK bit flag. + * + */ + void ClearDnsSecurityFlags(void) { mTtl &= ~kDnsSecFlag; } + + /** + * This method sets the DNSSEC OK bit flag. + * + */ + void SetDnsSecurityFlags(void) { mTtl |= kDnsSecFlag; } + +private: + // The OPT RR re-purposes the existing CLASS and TTL fields in the + // RR The CLASS field (`uint16_t`) is used for requester UDP + // payload size The TTL field is used for extended Response Code, + // version and flags as follows: + // + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + // | EXTENDED-RCODE | VERSION | + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + // | DO| Z | + // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + // + // The variable data part of OPT RR can contain zero of more `Option`. + + enum : uint32_t + { + kExtRCodeffset = 24, // Extended RCODE field offset. + kExtRCodeMask = 0xf << kExtRCodeffset, // Extended RCODE field mask. + kVersionOffset = 16, // Version field offset. + kVersionMask = 0xf << kVersionOffset, // Version field mask. + kDnsSecFlag = 1 << 15, // DnsSec bit flag. + }; + +} OT_TOOL_PACKED_END; + +/** + * This class implements the body of an Option in OPT Pseudo Resource Record (RFC 6981 - Section 6.1). + * + */ +OT_TOOL_PACKED_BEGIN +class Option +{ +public: + /** + * This enumeration defines option code values. + * + */ + enum : uint16_t + { + kUpdateLease = 2, ///< Update lease option code. + }; + + /** + * This method returns the option code value. + * + * @returns The option code value. + * + */ + uint16_t GetOptionCode(void) const { return HostSwap16(mOptionCode); } + + /** + * This method sets the option code value. + * + * @param[in] aOptionCode The option code value. + * + */ + void SetOptionCode(uint16_t aOptionCode) { mOptionCode = HostSwap16(aOptionCode); } + + /** + * This method returns the option length value. + * + * @returns The option length (size of option data in bytes). + * + */ + uint16_t GetOptionLength(void) const { return HostSwap16(mOptionLength); } + + /** + * This method sets the option length value. + * + * @param[in] aOptionLength The option length (size of option data in bytes). + * + */ + void SetOptionLength(uint16_t aOptionLength) { mOptionLength = HostSwap16(aOptionLength); } + + /** + * This method returns the size of (number of bytes) in the Option and its data. + * + * @returns Size (number of bytes) of the Option its data section. + * + */ + uint32_t GetSize(void) const { return sizeof(Option) + GetOptionLength(); } + +private: + uint16_t mOptionCode; + uint16_t mOptionLength; + // Followed by Option data (varies per option code). + +} OT_TOOL_PACKED_END; + +/** + * This class implements an Update Lease Option body. + * + * This implementation is intended for use in Dynamic DNS Update Lease Requests and Responses as specified in + * https://tools.ietf.org/html/draft-sekar-dns-ul-02. + * + */ +OT_TOOL_PACKED_BEGIN +class LeaseOption : public Option +{ +public: + enum : uint16_t + { + kOptionLength = sizeof(uint32_t) + sizeof(uint32_t), ///< Option length (lease and key lease values) + }; + + /** + * This method initialize the Update Lease Option by setting the Option Code and Option Length. + * + * The lease and key lease intervals remain unchanged/uninitialized. + * + */ + void Init(void) + { + SetOptionCode(kUpdateLease); + SetOptionLength(kOptionLength); + } + + /** + * This method returns the Update Lease OPT record's lease interval value. + * + * @returns The lease interval value (in seconds). + * + */ + uint32_t GetLeaseInterval(void) const { return HostSwap32(mLeaseInterval); } + + /** + * This method sets the Update Lease OPT record's lease interval value. + * + * @param[in] aLeaseInterval The lease interval value. + * + */ + void SetLeaseInterval(uint32_t aLeaseInterval) { mLeaseInterval = HostSwap32(aLeaseInterval); } + + /** + * This method returns the Update Lease OPT record's key lease interval value. + * + * @returns The key lease interval value (in seconds). + * + */ + uint32_t GetKeyLeaseInterval(void) const { return HostSwap32(mKeyLeaseInterval); } + + /** + * This method sets the Update Lease OPT record's key lease interval value. + * + * @param[in] aKeyLeaseInterval The key lease interval value (in seconds). + * + */ + void SetKeyLeaseInterval(uint32_t aKeyLeaseInterval) { mKeyLeaseInterval = HostSwap32(aKeyLeaseInterval); } + +private: + uint32_t mLeaseInterval; + uint32_t mKeyLeaseInterval; +} OT_TOOL_PACKED_END; + /** * This class implements Question format. * @@ -870,6 +1694,26 @@ private: }; }; +/** + * This class implements Zone section body for DNS Update (RFC 2136 - section 2.3). + * + */ +OT_TOOL_PACKED_BEGIN +class Zone : public Question +{ +public: + /** + * Constructor for Zone. + * + * @param[in] aClass The class of the zone (default is `kClassInternet`). + * + */ + explicit Zone(uint16_t aClass = ResourceRecord::kClassInternet) + : Question(ResourceRecord::kTypeSoa, aClass) + { + } +} OT_TOOL_PACKED_END; + /** * @} *