diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:15:43 +0000 |
commit | f5f56e1a1c4d9e9496fcb9d81131066a964ccd23 (patch) | |
tree | 49e44c6f87febed37efb953ab5485aa49f6481a7 /src/lib/dns/rdata/generic/nsec3_50.cc | |
parent | Initial commit. (diff) | |
download | isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.tar.xz isc-kea-f5f56e1a1c4d9e9496fcb9d81131066a964ccd23.zip |
Adding upstream version 2.4.1.upstream/2.4.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/dns/rdata/generic/nsec3_50.cc')
-rw-r--r-- | src/lib/dns/rdata/generic/nsec3_50.cc | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/src/lib/dns/rdata/generic/nsec3_50.cc b/src/lib/dns/rdata/generic/nsec3_50.cc new file mode 100644 index 0000000..e99c109 --- /dev/null +++ b/src/lib/dns/rdata/generic/nsec3_50.cc @@ -0,0 +1,343 @@ +// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <config.h> + +#include <iostream> +#include <iomanip> +#include <string> +#include <sstream> +#include <vector> +#include <cassert> + +#include <boost/lexical_cast.hpp> + +#include <util/encode/base32hex.h> +#include <util/encode/hex.h> +#include <util/buffer.h> + +#include <dns/exceptions.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rrtype.h> +#include <dns/rrttl.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rdata/generic/detail/nsec_bitmap.h> +#include <dns/rdata/generic/detail/nsec3param_common.h> + +#include <memory> + +#include <stdio.h> +#include <time.h> + +using namespace std; +using namespace isc::dns::rdata::generic::detail::nsec; +using namespace isc::dns::rdata::generic::detail::nsec3; +using namespace isc::util::encode; +using namespace isc::util; + +// BEGIN_ISC_NAMESPACE +// BEGIN_RDATA_NAMESPACE + +struct NSEC3Impl { + // straightforward representation of NSEC3 RDATA fields + NSEC3Impl(uint8_t hashalg, uint8_t flags, uint16_t iterations, + vector<uint8_t>salt, vector<uint8_t>next, + vector<uint8_t> typebits) : + hashalg_(hashalg), flags_(flags), iterations_(iterations), + salt_(salt), next_(next), typebits_(typebits) + {} + + const uint8_t hashalg_; + const uint8_t flags_; + const uint16_t iterations_; + const vector<uint8_t> salt_; + const vector<uint8_t> next_; + const vector<uint8_t> typebits_; +}; + +/// \brief Constructor from string. +/// +/// The given string must represent a valid NSEC3 RDATA. There +/// can be extra space characters at the beginning or end of the +/// text (which are simply ignored), but other extra text, including +/// a new line, will make the construction fail with an exception. +/// +/// The Hash Algorithm, Flags and Iterations fields must be within their +/// valid ranges. The Salt field may contain "-" to indicate that the +/// salt is of length 0. The Salt field must not contain any whitespace. +/// The type mnemonics must be valid, and separated by whitespace. If +/// any invalid mnemonics are found, InvalidRdataText exception is +/// thrown. +/// +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param nsec3_str A string containing the RDATA to be created +NSEC3::NSEC3(const std::string& nsec3_str) : + impl_(NULL) +{ + // We use unique_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the NSEC3Impl that constructFromLexer() returns. + std::unique_ptr<NSEC3Impl> impl_ptr; + + try { + std::istringstream ss(nsec3_str); + MasterLexer lexer; + lexer.pushSource(ss); + + impl_ptr.reset(constructFromLexer(lexer)); + + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Extra input text for NSEC3: " << nsec3_str); + } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct NSEC3 from '" << nsec3_str << "': " + << ex.what()); + } + + impl_ = impl_ptr.release(); +} + +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of an NSEC3 RDATA. +/// +/// See \c NSEC3::NSEC3(const std::string&) for description of the +/// expected RDATA fields. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +NSEC3::NSEC3(MasterLexer& lexer, const Name*, MasterLoader::Options, + MasterLoaderCallbacks&) : + impl_(NULL) +{ + impl_ = constructFromLexer(lexer); +} + +NSEC3Impl* +NSEC3::constructFromLexer(MasterLexer& lexer) { + vector<uint8_t> salt; + const ParseNSEC3ParamResult params = + parseNSEC3ParamFromLexer("NSEC3", lexer, salt); + + const string& nexthash = + lexer.getNextToken(MasterToken::STRING).getString(); + if (*nexthash.rbegin() == '=') { + isc_throw(InvalidRdataText, "NSEC3 hash has padding: " << nexthash); + } + + vector<uint8_t> next; + decodeBase32Hex(nexthash, next); + if (next.size() > 255) { + isc_throw(InvalidRdataText, "NSEC3 hash is too long: " + << next.size() << " bytes"); + } + + vector<uint8_t> typebits; + // For NSEC3 empty bitmap is possible and allowed. + buildBitmapsFromLexer("NSEC3", lexer, typebits, true); + return (new NSEC3Impl(params.algorithm, params.flags, params.iterations, + salt, next, typebits)); +} + +NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len) : + impl_(NULL) +{ + vector<uint8_t> salt; + const ParseNSEC3ParamResult params = + parseNSEC3ParamWire("NSEC3", buffer, rdata_len, salt); + + if (rdata_len < 1) { + isc_throw(DNSMessageFORMERR, "NSEC3 too short to contain hash length, " + "length: " << rdata_len + salt.size() + 5); + } + const uint8_t nextlen = buffer.readUint8(); + --rdata_len; + if (nextlen == 0 || rdata_len < nextlen) { + isc_throw(DNSMessageFORMERR, "NSEC3 invalid hash length: " << + static_cast<unsigned int>(nextlen)); + } + + vector<uint8_t> next(nextlen); + buffer.readData(&next[0], nextlen); + rdata_len -= nextlen; + + vector<uint8_t> typebits(rdata_len); + if (rdata_len > 0) { + // Read and parse the bitmaps only when they exist; empty bitmap + // is possible for NSEC3. + buffer.readData(&typebits[0], rdata_len); + checkRRTypeBitmaps("NSEC3", typebits); + } + + impl_ = new NSEC3Impl(params.algorithm, params.flags, params.iterations, + salt, next, typebits); +} + +NSEC3::NSEC3(const NSEC3& source) : + Rdata(), impl_(new NSEC3Impl(*source.impl_)) +{} + +NSEC3& +NSEC3::operator=(const NSEC3& source) { + if (this == &source) { + return (*this); + } + + NSEC3Impl* newimpl = new NSEC3Impl(*source.impl_); + delete impl_; + impl_ = newimpl; + + return (*this); +} + +NSEC3::~NSEC3() { + delete impl_; +} + +string +NSEC3::toText() const { + ostringstream s; + bitmapsToText(impl_->typebits_, s); + + using boost::lexical_cast; + return (lexical_cast<string>(static_cast<int>(impl_->hashalg_)) + + " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) + + " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) + + " " + (impl_->salt_.empty() ? "-" : encodeHex(impl_->salt_)) + + " " + encodeBase32Hex(impl_->next_) + s.str()); +} + +template <typename OUTPUT_TYPE> +void +toWireHelper(const NSEC3Impl& impl, OUTPUT_TYPE& output) { + output.writeUint8(impl.hashalg_); + output.writeUint8(impl.flags_); + output.writeUint16(impl.iterations_); + output.writeUint8(impl.salt_.size()); + if (!impl.salt_.empty()) { + output.writeData(&impl.salt_[0], impl.salt_.size()); + } + assert(!impl.next_.empty()); + output.writeUint8(impl.next_.size()); + output.writeData(&impl.next_[0], impl.next_.size()); + if (!impl.typebits_.empty()) { + output.writeData(&impl.typebits_[0], impl.typebits_.size()); + } +} + +void +NSEC3::toWire(OutputBuffer& buffer) const { + toWireHelper(*impl_, buffer); +} + +void +NSEC3::toWire(AbstractMessageRenderer& renderer) const { + toWireHelper(*impl_, renderer); +} + +namespace { +// This is a helper subroutine for compare(). It compares two binary +// data stored in vector<uint8_t> objects based on the "Canonical RR Ordering" +// as defined in Section 6.3 of RFC4034, that is, the data are treated +// "as a left-justified unsigned octet sequence in which the absence of an +// octet sorts before a zero octet." +// +// If check_length_first is true, it treats the compared data as if they +// began with a single-octet "length" field whose value is the size of the +// corresponding vector. In this case, if the sizes of the two vectors are +// different the shorter one is always considered the "smaller"; the contents +// of the vector don't matter. +// +// This function returns: +// -1 if v1 is considered smaller than v2 +// 1 if v1 is considered larger than v2 +// 0 otherwise +int +compareVectors(const vector<uint8_t>& v1, const vector<uint8_t>& v2, + bool check_length_first = true) +{ + const size_t len1 = v1.size(); + const size_t len2 = v2.size(); + if (check_length_first && len1 != len2) { + return (len1 - len2); + } + const size_t cmplen = min(len1, len2); + const int cmp = cmplen == 0 ? 0 : memcmp(&v1.at(0), &v2.at(0), cmplen); + if (cmp != 0) { + return (cmp); + } else { + return (len1 - len2); + } +} +} + +int +NSEC3::compare(const Rdata& other) const { + const NSEC3& other_nsec3 = dynamic_cast<const NSEC3&>(other); + + if (impl_->hashalg_ != other_nsec3.impl_->hashalg_) { + return (impl_->hashalg_ < other_nsec3.impl_->hashalg_ ? -1 : 1); + } + if (impl_->flags_ != other_nsec3.impl_->flags_) { + return (impl_->flags_ < other_nsec3.impl_->flags_ ? -1 : 1); + } + if (impl_->iterations_ != other_nsec3.impl_->iterations_) { + return (impl_->iterations_ < other_nsec3.impl_->iterations_ ? -1 : 1); + } + + int cmp = compareVectors(impl_->salt_, other_nsec3.impl_->salt_); + if (cmp != 0) { + return (cmp); + } + cmp = compareVectors(impl_->next_, other_nsec3.impl_->next_); + if (cmp != 0) { + return (cmp); + } + // Note that bitmap doesn't have a dedicated length field, so we shouldn't + // terminate the comparison just because the lengths are different. + return (compareVectors(impl_->typebits_, other_nsec3.impl_->typebits_, + false)); +} + +uint8_t +NSEC3::getHashalg() const { + return (impl_->hashalg_); +} + +uint8_t +NSEC3::getFlags() const { + return (impl_->flags_); +} + +uint16_t +NSEC3::getIterations() const { + return (impl_->iterations_); +} + +const vector<uint8_t>& +NSEC3::getSalt() const { + return (impl_->salt_); +} + +const vector<uint8_t>& +NSEC3::getNext() const { + return (impl_->next_); +} + +// END_RDATA_NAMESPACE +// END_ISC_NAMESPACE |