diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 11:36:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 11:36:04 +0000 |
commit | 040eee1aa49b49df4698d83a05af57c220127fd1 (patch) | |
tree | f635435954e6ccde5eee9893889e24f30ca68346 /src/lib/dns/tests/rdata_nsecbitmap_unittest.cc | |
parent | Initial commit. (diff) | |
download | isc-kea-upstream.tar.xz isc-kea-upstream.zip |
Adding upstream version 2.2.0.upstream/2.2.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib/dns/tests/rdata_nsecbitmap_unittest.cc')
-rw-r--r-- | src/lib/dns/tests/rdata_nsecbitmap_unittest.cc | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc b/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc new file mode 100644 index 0000000..f18e9df --- /dev/null +++ b/src/lib/dns/tests/rdata_nsecbitmap_unittest.cc @@ -0,0 +1,269 @@ +// Copyright (C) 2011-2019 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 <dns/tests/unittest_util.h> + +#include <dns/exceptions.h> +#include <dns/rdata.h> +#include <dns/rdataclass.h> +#include <dns/rrclass.h> +#include <dns/rrtype.h> + +#include <gtest/gtest.h> + +#include <dns/tests/rdata_unittest.h> +#include <util/unittests/wiredata.h> + +#include <boost/lexical_cast.hpp> + +#include <string> +#include <vector> + +using namespace std; +using namespace isc::dns; +using namespace isc::dns::rdata; +using namespace isc::util; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; +using boost::lexical_cast; + +namespace { + +// Template for shared tests for NSEC and NSEC3 bitmaps +template <typename RDATA_TYPE> +class NSECLikeBitmapTest : public RdataTest { +protected: + RDATA_TYPE fromText(const string& rdata_text) { + return (RDATA_TYPE(rdata_text)); + } + + vector<RDATA_TYPE> compare_set; // used in compare() tests + + void compareCheck() const { + typename vector<RDATA_TYPE>::const_iterator it; + typename vector<RDATA_TYPE>::const_iterator const it_end = + compare_set.end(); + for (it = compare_set.begin(); it != it_end - 1; ++it) { + SCOPED_TRACE("compare " + it->toText() + " to " + + (it + 1)->toText()); + EXPECT_GT(0, (*it).compare(*(it + 1))); + EXPECT_LT(0, (*(it + 1)).compare(*it)); + } + } + + // These depend on the specific RR type. We use specialized methods + // for them. + static RRType getType(); // return either RRType::NSEC() or NSEC3() + static string getWireFilePrefix(); + static string getCommonText(); // commonly used part of textual form +}; + +// Instantiate specific typed tests +typedef ::testing::Types<generic::NSEC, generic::NSEC3> TestRdataTypes; +#ifdef TYPED_TEST_SUITE +TYPED_TEST_SUITE(NSECLikeBitmapTest, TestRdataTypes); +#else +TYPED_TEST_CASE(NSECLikeBitmapTest, TestRdataTypes); +#endif + +// NSEC and NSEC3 bitmaps have some subtle differences, in which case we +// need to test them separately. Using these typedef type names with TEST_F +// will do the trick. +typedef NSECLikeBitmapTest<generic::NSEC3> NSEC3BitmapTest; +typedef NSECLikeBitmapTest<generic::NSEC> NSECBitmapTest; + +template <> +string +NSECLikeBitmapTest<generic::NSEC>::getWireFilePrefix() { + return ("rdata_nsec_"); +} + +template <> +RRType +NSECLikeBitmapTest<generic::NSEC>::getType() { + return (RRType::NSEC()); +} + +template <> +string +NSECLikeBitmapTest<generic::NSEC3>::getWireFilePrefix() { + return ("rdata_nsec3_"); +} + +template <> +RRType +NSECLikeBitmapTest<generic::NSEC3>::getType() { + return (RRType::NSEC3()); +} + +template <> +string +NSECLikeBitmapTest<generic::NSEC>::getCommonText() { + return ("next. "); +} + +template <> +string +NSECLikeBitmapTest<generic::NSEC3>::getCommonText() { + return ("1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR "); +} + +// Tests against various types of bogus NSEC/NSEC3 type bitmaps. +// The syntax and semantics are common for both RR types, and our +// implementation of that part is shared, so in theory it should be sufficient +// to test for only one RR type. But we check for both just in case. +TYPED_TEST(NSECLikeBitmapTest, createFromWire) { + // A malformed NSEC bitmap length field that could cause overflow. + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire4.wire").c_str()), + DNSMessageFORMERR); + + // The bitmap field is incomplete (only the first byte is included) + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire5.wire").c_str()), + DNSMessageFORMERR); + + // Bitmap length is 0, which is invalid. + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire6.wire").c_str()), + DNSMessageFORMERR); + + // Too large bitmap length with a short buffer. + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire3").c_str()), + DNSMessageFORMERR); + + // A boundary case: longest possible bitmaps (32 maps). This should be + // accepted. + EXPECT_NO_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire7.wire").c_str())); + + // Another boundary condition: 33 bitmaps, which should be rejected. + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire8.wire").c_str()), + DNSMessageFORMERR); + + // Disordered bitmap window blocks. + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire9.wire").c_str()), + DNSMessageFORMERR); + + // Bitmap ending with all-zero bytes. Not necessarily harmful except + // the additional overhead of parsing, but invalid according to the + // spec anyway. + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire10.wire").c_str()), + DNSMessageFORMERR); +} + +// This tests the result of toText() with various kinds of NSEC/NSEC3 bitmaps. +// It also tests the "from text" constructor as a result. +TYPED_TEST(NSECLikeBitmapTest, toText) { + // A simple case (some commonly seen RR types in NSEC(3) bitmaps) + string rdata_text = this->getCommonText() + "NS SOA RRSIG DNSKEY"; + EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText()); + + // Similar to above, but involves more than one bitmap window blocks. + rdata_text = this->getCommonText() + "NS DLV"; + EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText()); + + // Make sure all possible bits in a one-octet bitmap field are handled + // correctly. + // We use the range around 1024 (reasonably higher number) so it's + // unlikely that they have predefined mnemonic and can be safely converted + // to TYPEnnnn by toText(). + for (unsigned int i = 1024; i < 1032; ++i) { + rdata_text = this->getCommonText() + "TYPE" + lexical_cast<string>(i); + EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText()); + } + + // Make sure all possible 32 octets in a longest possible block are + // handled correctly. + for (unsigned int i = 1024; i < 1024 + 256; i += 8) { + rdata_text = this->getCommonText() + "TYPE" + lexical_cast<string>(i); + EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText()); + } + + // Check for the highest window block. + rdata_text = this->getCommonText() + "TYPE65535"; + EXPECT_EQ(rdata_text, this->fromText(rdata_text).toText()); +} + +TYPED_TEST(NSECLikeBitmapTest, compare) { + // Bit map: [win=0][len=1] 00000010 + this->compare_set.push_back(this->fromText(this->getCommonText() + "SOA")); + // Bit map: [win=0][len=1] 00000010, [win=4][len=1] 10000000 + this->compare_set.push_back(this->fromText(this->getCommonText() + + "SOA TYPE1024")); + // Bit map: [win=0][len=1] 00100000 + this->compare_set.push_back(this->fromText(this->getCommonText() + "NS")); + // Bit map: [win=0][len=1] 00100010 + this->compare_set.push_back(this->fromText(this->getCommonText() + + "NS SOA")); + // Bit map: [win=0][len=2] 00100000, 00000001 + this->compare_set.push_back(this->fromText(this->getCommonText() + + "NS MX")); + // Bit map: [win=4][len=1] 10000000 + this->compare_set.push_back(this->fromText(this->getCommonText() + + "TYPE1024")); + + this->compareCheck(); +} + +// NSEC bitmaps must not be empty +TEST_F(NSECBitmapTest, emptyMap) { + EXPECT_THROW(this->fromText("next.example.").toText(), InvalidRdataText); + + EXPECT_THROW(this->rdataFactoryFromFile(this->getType(), RRClass::IN(), + (this->getWireFilePrefix() + + "fromWire16.wire").c_str()), + DNSMessageFORMERR); +} + +// NSEC3 bitmaps can be empty +TEST_F(NSEC3BitmapTest, emptyMap) { + // Read wire data wit an empty NSEC3 bitmap. This should succeed. + vector<uint8_t> data; + UnitTestUtil::readWireData((this->getWireFilePrefix() + + "fromWire16.wire").c_str(), data); + InputBuffer buffer(&data[0], data.size()); + const uint16_t rdlen = buffer.readUint16(); + const generic::NSEC3 empty_nsec3 = + dynamic_cast<const generic::NSEC3&>(*createRdata( + RRType::NSEC3(), RRClass::IN(), + buffer, rdlen)); + + // Check the toText() result. + EXPECT_EQ("1 0 1 7373737373 D1K6GQ38D1K6GQ38D1K6GQ38D1K6GQ38", + empty_nsec3.toText()); + + // Check the toWire() result. + OutputBuffer obuffer(0); + obuffer.writeUint16(rdlen); + empty_nsec3.toWire(obuffer); + matchWireData(&data[0], data.size(), + obuffer.getData(), obuffer.getLength()); + + // Same for MessageRenderer. + obuffer.clear(); + MessageRenderer renderer; + renderer.writeUint16(rdlen); + empty_nsec3.toWire(renderer); + matchWireData(&data[0], data.size(), + renderer.getData(), renderer.getLength()); +} + +} |