123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <exceptions/exceptions.h>
- #include <util/buffer.h>
- #include <util/memory_segment_local.h>
- #include <dns/rdata.h>
- #include <dns/rdataclass.h>
- #include <dns/rrset.h>
- #include <dns/rrclass.h>
- #include <dns/rrtype.h>
- #include <dns/rrttl.h>
- #include <datasrc/memory/segment_object_holder.h>
- #include <datasrc/memory/rdata_serialization.h>
- #include <datasrc/memory/rdataset.h>
- #include <testutils/dnsmessage_test.h>
- #include <gtest/gtest.h>
- #include <boost/lexical_cast.hpp>
- #include <string>
- using namespace isc::dns;
- using namespace isc::dns::rdata;
- using namespace isc::datasrc::memory;
- using namespace isc::testutils;
- using isc::datasrc::memory::detail::SegmentObjectHolder;
- using boost::lexical_cast;
- namespace {
- class RdataSetTest : public ::testing::Test {
- protected:
- RdataSetTest() :
- // 1076895760 = 0x40302010. Use this so we fill in all 8-bit "field"
- // of the 32-bit TTL
- a_rrset_(textToRRset("www.example.com. 1076895760 IN A 192.0.2.1")),
- rrsig_rrset_(textToRRset("www.example.com. 1076895760 IN RRSIG "
- "A 5 2 3600 20120814220826 20120715220826 "
- "1234 example.com. FAKE"))
- {}
- void TearDown() {
- EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
- }
- ConstRRsetPtr a_rrset_, rrsig_rrset_;
- isc::util::MemorySegmentLocal mem_sgmt_;
- RdataEncoder encoder_;
- };
- // Convert the given 32-bit integer (network byte order) to the corresponding
- // RRTTL object.
- RRTTL
- restoreTTL(const void* ttl_data) {
- isc::util::InputBuffer b(ttl_data, sizeof(uint32_t));
- return (RRTTL(b));
- }
- // A helper callback for checkRdataSet. This confirms the given data
- // is the expected in::A RDATA (the value is taken from the RdataSetTest
- // constructor).
- void
- checkData(const void* data, size_t size) {
- isc::util::InputBuffer b(data, size);
- EXPECT_EQ(0, in::A(b, size).compare(in::A("192.0.2.1")));
- }
- // This is a set of checks for an RdataSet created with some simple
- // conditions. with_rrset/with_rrsig is true iff the RdataSet is supposed to
- // contain normal/RRSIG RDATA.
- void
- checkRdataSet(const RdataSet& rdataset, bool with_rrset, bool with_rrsig) {
- EXPECT_FALSE(rdataset.next); // by default the next pointer should be NULL
- EXPECT_EQ(RRType::A(), rdataset.type);
- // See the RdataSetTest constructor for the magic number.
- EXPECT_EQ(RRTTL(1076895760), restoreTTL(rdataset.getTTLData()));
- EXPECT_EQ(with_rrset ? 1 : 0, rdataset.getRdataCount());
- EXPECT_EQ(with_rrsig ? 1 : 0, rdataset.getSigRdataCount());
- // A simple test for the data content. Details tests for the encoder/
- // reader should be basically sufficient for various cases of the data,
- // and the fact that this test doesn't detect memory leak should be
- // reasonably sufficient that the implementation handles the data region
- // correctly. Here we check one simple case for a simple form of RDATA,
- // mainly for checking the behavior of getDataBuf().
- RdataReader reader(RRClass::IN(), RRType::A(),
- reinterpret_cast<const uint8_t*>(
- rdataset.getDataBuf()),
- rdataset.getRdataCount(), rdataset.getSigRdataCount(),
- &RdataReader::emptyNameAction, checkData);
- reader.iterate();
- }
- TEST_F(RdataSetTest, create) {
- // A simple case of creating an RdataSet. Confirming the resulting
- // fields have the expected values, and then destroying it (TearDown()
- // would detect any memory leak)
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- ConstRRsetPtr());
- checkRdataSet(*rdataset, true, false);
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- }
- TEST_F(RdataSetTest, getNext) {
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- ConstRRsetPtr());
- // By default, the next pointer should be NULL (already tested in other
- // test cases), which should be the case with getNext(). We test both
- // mutable and immutable versions of getNext().
- EXPECT_EQ(static_cast<RdataSet*>(NULL), rdataset->getNext());
- EXPECT_EQ(static_cast<const RdataSet*>(NULL),
- static_cast<const RdataSet*>(rdataset)->getNext());
- // making a link (it would form an infinite loop, but it doesn't matter
- // in this test), and check the pointer returned by getNext().
- rdataset->next = rdataset;
- EXPECT_EQ(rdataset, static_cast<const RdataSet*>(rdataset)->getNext());
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- }
- TEST_F(RdataSetTest, find) {
- // Create some RdataSets and make a chain of them.
- SegmentObjectHolder<RdataSet, RRClass> holder1(
- mem_sgmt_,
- RdataSet::create(mem_sgmt_, encoder_, a_rrset_, ConstRRsetPtr()),
- RRClass::IN());
- ConstRRsetPtr aaaa_rrset =
- textToRRset("www.example.com. 1076895760 IN AAAA 2001:db8::1");
- SegmentObjectHolder<RdataSet, RRClass> holder2(
- mem_sgmt_,
- RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset, ConstRRsetPtr()),
- RRClass::IN());
- ConstRRsetPtr sigonly_rrset =
- textToRRset("www.example.com. 1076895760 IN RRSIG "
- "TXT 5 2 3600 20120814220826 20120715220826 "
- "1234 example.com. FAKE");
- SegmentObjectHolder<RdataSet, RRClass> holder3(
- mem_sgmt_,
- RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(), sigonly_rrset),
- RRClass::IN());
- RdataSet* rdataset_a = holder1.get();
- RdataSet* rdataset_aaaa = holder2.get();
- RdataSet* rdataset_sigonly = holder3.get();
- RdataSet* rdataset_null = NULL;
- rdataset_a->next = rdataset_aaaa;
- rdataset_aaaa->next = rdataset_sigonly;
- // If a non-RRSIG part of rdataset exists for the given type, it will be
- // returned regardless of the value of sigonly_ok. If it's RRSIG-only
- // rdataset, it returns non NULL iff sigonly_ok is explicitly set to true.
- EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA()));
- EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA(), true));
- EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA(), false));
- EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a, RRType::TXT()));
- EXPECT_EQ(rdataset_sigonly, RdataSet::find(rdataset_a, RRType::TXT(),
- true));
- EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a, RRType::TXT(), false));
- // Same tests for the const version of find().
- const RdataSet* rdataset_a_const = holder1.get();
- EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA()));
- EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA(),
- true));
- EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA(),
- false));
- EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a_const, RRType::TXT()));
- EXPECT_EQ(rdataset_sigonly, RdataSet::find(rdataset_a_const, RRType::TXT(),
- true));
- EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a_const, RRType::TXT(),
- false));
- }
- // A helper function to create an RRset containing the given number of
- // unique RDATAs.
- ConstRRsetPtr
- getRRsetWithRdataCount(size_t rdata_count) {
- RRsetPtr rrset(new RRset(Name("example.com"), RRClass::IN(), RRType::TXT(),
- RRTTL(3600)));
- for (size_t i = 0; i < rdata_count; ++i) {
- rrset->addRdata(rdata::createRdata(RRType::TXT(), RRClass::IN(),
- lexical_cast<std::string>(i)));
- }
- return (rrset);
- }
- TEST_F(RdataSetTest, createManyRRs) {
- // RRset with possible maximum number of RDATAs
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_,
- getRRsetWithRdataCount(8191),
- ConstRRsetPtr());
- EXPECT_EQ(8191, rdataset->getRdataCount());
- EXPECT_EQ(0, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- // Exceeding that will result in an exception.
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_,
- getRRsetWithRdataCount(8192),
- ConstRRsetPtr()),
- RdataSetError);
- // To be very sure even try larger number than the threshold
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_,
- getRRsetWithRdataCount(65535),
- ConstRRsetPtr()),
- RdataSetError);
- }
- TEST_F(RdataSetTest, createWithRRSIG) {
- // Normal case.
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- rrsig_rrset_);
- checkRdataSet(*rdataset, true, true);
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- // Unusual case: TTL doesn't match. This implementation accepts that,
- // using the TTL of the covered RRset.
- ConstRRsetPtr rrsig_badttl(textToRRset(
- "www.example.com. 3600 IN RRSIG "
- "A 5 2 3600 20120814220826 "
- "20120715220826 1234 example.com. FAKE"));
- rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_, rrsig_badttl);
- checkRdataSet(*rdataset, true, true);
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- }
- // A helper function to create an RRSIG RRset containing the given number of
- // unique RDATAs.
- ConstRRsetPtr
- getRRSIGWithRdataCount(size_t sig_count) {
- RRsetPtr rrset(new RRset(Name("example.com"), RRClass::IN(),
- RRType::RRSIG(), RRTTL(3600)));
- // We use a base wire-format image and tweak the original TTL field to
- // generate unique RDATAs in the loop. (Creating them from corresponding
- // text is simpler, but doing so for a large number of RRSIGs is
- // relatively heavy and could be too long for unittests).
- ConstRdataPtr rrsig_base =
- rdata::createRdata(RRType::RRSIG(), RRClass::IN(),
- "A 5 2 3600 20120814220826 20120715220826 1234 "
- "example.com. FAKE");
- isc::util::OutputBuffer ob(0);
- rrsig_base->toWire(ob);
- for (size_t i = 0; i < sig_count; ++i) {
- ob.writeUint16At((i >> 16) & 0xffff, 4);
- ob.writeUint16At(i & 0xffff, 6);
- isc::util::InputBuffer ib(ob.getData(), ob.getLength());
- rrset->addRdata(rdata::createRdata(RRType::RRSIG(), RRClass::IN(),
- ib, ib.getLength()));
- }
- return (rrset);
- }
- TEST_F(RdataSetTest, createManyRRSIGs) {
- // 7 has a special meaning in the implementation: if the number of the
- // RRSIGs reaches this value, an extra 'sig count' field will be created.
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- getRRSIGWithRdataCount(7));
- EXPECT_EQ(7, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- // 8 would cause overflow in the normal 3-bit field if there were no extra
- // count field.
- rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- getRRSIGWithRdataCount(8));
- EXPECT_EQ(8, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- // Up to 2^16-1 RRSIGs are allowed (although that would be useless
- // in practice)
- rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- getRRSIGWithRdataCount(65535));
- EXPECT_EQ(65535, rdataset->getSigRdataCount());
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- // Exceeding this limit will result in an exception.
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- getRRSIGWithRdataCount(65536)),
- RdataSetError);
- // To be very sure even try larger number than the threshold
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- getRRSIGWithRdataCount(70000)),
- RdataSetError);
- }
- TEST_F(RdataSetTest, createWithRRSIGOnly) {
- // A rare, but allowed, case: RdataSet without the main RRset but with
- // RRSIG.
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
- rrsig_rrset_);
- checkRdataSet(*rdataset, false, true);
- RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
- }
- TEST_F(RdataSetTest, badCeate) {
- // Neither the RRset nor RRSIG RRset is given
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
- ConstRRsetPtr()), isc::BadValue);
- // Empty RRset (An RRset without RDATA)
- ConstRRsetPtr empty_rrset(new RRset(Name("example.com"), RRClass::IN(),
- RRType::A(), RRTTL(3600)));
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, empty_rrset,
- ConstRRsetPtr()), isc::BadValue);
- ConstRRsetPtr empty_rrsig(new RRset(Name("example.com"), RRClass::IN(),
- RRType::RRSIG(), RRTTL(3600)));
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
- empty_rrsig), isc::BadValue);
- // The RRset type and RRSIG's type covered don't match
- ConstRRsetPtr bad_rrsig(textToRRset(
- "www.example.com. 1076895760 IN RRSIG "
- "NS 5 2 3600 20120814220826 20120715220826 "
- "1234 example.com. FAKE"));
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_, bad_rrsig),
- isc::BadValue);
- // Pass non RRSIG for the sig parameter
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_, a_rrset_),
- isc::BadValue);
- // Pass RRSIG for normal RRset (the RdataEncoder will catch this and throw)
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, rrsig_rrset_,
- rrsig_rrset_),
- isc::BadValue);
- // RR class doesn't match between RRset and RRSIG
- ConstRRsetPtr badclass_rrsig(textToRRset(
- "www.example.com. 1076895760 CH RRSIG "
- "A 5 2 3600 20120814220826 "
- "20120715220826 1234 example.com. FAKE",
- RRClass::CH()));
- EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
- badclass_rrsig),
- isc::BadValue);
- }
- }
|