1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060 |
- // Copyright (C) 2010 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 <fstream>
- #include <boost/scoped_ptr.hpp>
- #include <exceptions/exceptions.h>
- #include <util/buffer.h>
- #include <util/time_utilities.h>
- #include <util/unittests/testdata.h>
- #include <util/unittests/textdata.h>
- #include <dns/edns.h>
- #include <dns/exceptions.h>
- #include <dns/message.h>
- #include <dns/messagerenderer.h>
- #include <dns/question.h>
- #include <dns/opcode.h>
- #include <dns/rcode.h>
- #include <dns/rdataclass.h>
- #include <dns/rrclass.h>
- #include <dns/rrttl.h>
- #include <dns/rrtype.h>
- #include <dns/tsig.h>
- #include <dns/tsigkey.h>
- #include <gtest/gtest.h>
- #include <dns/tests/unittest_util.h>
- using isc::UnitTestUtil;
- using namespace std;
- using namespace isc;
- using namespace isc::dns;
- using namespace isc::util;
- using namespace isc::dns::rdata;
- //
- // Note: we need more tests, including:
- // parsing malformed headers
- // more complete tests about parsing/rendering header flags, opcode, rcode, etc.
- // tests for adding RRsets
- // tests for RRset/Question iterators
- // But, we'll ship with the current set of tests for now, partly because many
- // of the above are covered as part of other tests, and partly due to time
- // limitation. We also expect to revisit the fundamental design of the Message
- // class, at which point we'll also revise the tests including more cases.
- //
- const uint16_t Message::DEFAULT_MAX_UDPSIZE;
- namespace isc {
- namespace util {
- namespace detail {
- extern int64_t (*gettimeFunction)();
- }
- }
- }
- // XXX: this is defined as class static constants, but some compilers
- // seemingly cannot find the symbol when used in the EXPECT_xxx macros.
- const uint16_t TSIGContext::DEFAULT_FUDGE;
- namespace {
- class MessageTest : public ::testing::Test {
- protected:
- MessageTest() : test_name("test.example.com"), obuffer(0),
- renderer(obuffer),
- message_parse(Message::PARSE),
- message_render(Message::RENDER),
- bogus_section(static_cast<Message::Section>(
- Message::SECTION_ADDITIONAL + 1)),
- tsig_ctx(TSIGKey("www.example.com:"
- "SFuWd/q99SzF8Yzd1QbB9g=="))
- {
- rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(),
- RRType::A(), RRTTL(3600)));
- rrset_a->addRdata(in::A("192.0.2.1"));
- rrset_a->addRdata(in::A("192.0.2.2"));
- rrset_aaaa = RRsetPtr(new RRset(test_name, RRClass::IN(),
- RRType::AAAA(), RRTTL(3600)));
- rrset_aaaa->addRdata(in::AAAA("2001:db8::1234"));
- rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
- RRType::RRSIG(), RRTTL(3600)));
- rrset_rrsig->addRdata(generic::RRSIG("AAAA 5 3 7200 20100322084538 "
- "20100220084538 1 example.com "
- "FAKEFAKEFAKEFAKE"));
- rrset_aaaa->addRRsig(rrset_rrsig);
- }
- static Question factoryFromFile(const char* datafile);
- const Name test_name;
- OutputBuffer obuffer;
- MessageRenderer renderer;
- Message message_parse;
- Message message_render;
- const Message::Section bogus_section;
- RRsetPtr rrset_a; // A RRset with two RDATAs
- RRsetPtr rrset_aaaa; // AAAA RRset with one RDATA with RRSIG
- RRsetPtr rrset_rrsig; // RRSIG for the AAAA RRset
- TSIGContext tsig_ctx;
- vector<unsigned char> received_data;
- vector<unsigned char> expected_data;
- void factoryFromFile(Message& message, const char* datafile,
- Message::ParseOptions options =
- Message::PARSE_DEFAULT);
- };
- void
- MessageTest::factoryFromFile(Message& message, const char* datafile,
- Message::ParseOptions options)
- {
- received_data.clear();
- UnitTestUtil::readWireData(datafile, received_data);
- InputBuffer buffer(&received_data[0], received_data.size());
- message.fromWire(buffer, options);
- }
- TEST_F(MessageTest, headerFlag) {
- // by default no flag is set
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_QR));
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_AA));
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_TC));
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_RD));
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_RA));
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_AD));
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_CD));
- // set operation: by default it will be on
- message_render.setHeaderFlag(Message::HEADERFLAG_QR);
- EXPECT_TRUE(message_render.getHeaderFlag(Message::HEADERFLAG_QR));
- // it can be set to on explicitly, too
- message_render.setHeaderFlag(Message::HEADERFLAG_AA, true);
- EXPECT_TRUE(message_render.getHeaderFlag(Message::HEADERFLAG_AA));
- // the bit can also be cleared
- message_render.setHeaderFlag(Message::HEADERFLAG_AA, false);
- EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_AA));
- // Invalid flag values
- EXPECT_THROW(message_render.setHeaderFlag(
- static_cast<Message::HeaderFlag>(0)), InvalidParameter);
- EXPECT_THROW(message_render.setHeaderFlag(
- static_cast<Message::HeaderFlag>(0x7000)),
- InvalidParameter);
- EXPECT_THROW(message_render.setHeaderFlag(
- static_cast<Message::HeaderFlag>(0x0800)),
- InvalidParameter);
- EXPECT_THROW(message_render.setHeaderFlag(
- static_cast<Message::HeaderFlag>(0x0040)),
- InvalidParameter);
- EXPECT_THROW(message_render.setHeaderFlag(
- static_cast<Message::HeaderFlag>(0x10000)),
- InvalidParameter);
- EXPECT_THROW(message_render.setHeaderFlag(
- static_cast<Message::HeaderFlag>(0x80000000)),
- InvalidParameter);
- // set operation isn't allowed in the parse mode.
- EXPECT_THROW(message_parse.setHeaderFlag(Message::HEADERFLAG_QR),
- InvalidMessageOperation);
- }
- TEST_F(MessageTest, getEDNS) {
- EXPECT_FALSE(message_parse.getEDNS()); // by default EDNS isn't set
- factoryFromFile(message_parse, "message_fromWire10.wire");
- EXPECT_TRUE(message_parse.getEDNS());
- EXPECT_EQ(0, message_parse.getEDNS()->getVersion());
- EXPECT_EQ(4096, message_parse.getEDNS()->getUDPSize());
- EXPECT_TRUE(message_parse.getEDNS()->getDNSSECAwareness());
- }
- TEST_F(MessageTest, setEDNS) {
- // setEDNS() isn't allowed in the parse mode
- EXPECT_THROW(message_parse.setEDNS(EDNSPtr(new EDNS())),
- InvalidMessageOperation);
- EDNSPtr edns = EDNSPtr(new EDNS());
- message_render.setEDNS(edns);
- EXPECT_EQ(edns, message_render.getEDNS());
- }
- TEST_F(MessageTest, fromWireWithTSIG) {
- // Initially there should be no TSIG
- EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
- // getTSIGRecord() is only valid in the parse mode.
- EXPECT_THROW(message_render.getTSIGRecord(), InvalidMessageOperation);
- factoryFromFile(message_parse, "message_toWire2.wire");
- const uint8_t expected_mac[] = {
- 0x22, 0x70, 0x26, 0xad, 0x29, 0x7b, 0xee, 0xe7,
- 0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
- };
- const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
- ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
- EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
- EXPECT_EQ(85, tsig_rr->getLength()); // see TSIGRecordTest.getLength
- EXPECT_EQ(TSIGKey::HMACMD5_NAME(), tsig_rr->getRdata().getAlgorithm());
- EXPECT_EQ(0x4da8877a, tsig_rr->getRdata().getTimeSigned());
- EXPECT_EQ(TSIGContext::DEFAULT_FUDGE, tsig_rr->getRdata().getFudge());
- EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
- tsig_rr->getRdata().getMAC(),
- tsig_rr->getRdata().getMACSize(),
- expected_mac, sizeof(expected_mac));
- EXPECT_EQ(0, tsig_rr->getRdata().getError());
- EXPECT_EQ(0, tsig_rr->getRdata().getOtherLen());
- EXPECT_EQ(static_cast<void*>(NULL), tsig_rr->getRdata().getOtherData());
- // If we clear the message for reuse, the recorded TSIG will be cleared.
- message_parse.clear(Message::PARSE);
- EXPECT_EQ(static_cast<void*>(NULL), message_parse.getTSIGRecord());
- }
- TEST_F(MessageTest, fromWireWithTSIGCompressed) {
- // Mostly same as fromWireWithTSIG, but the TSIG owner name is compressed.
- factoryFromFile(message_parse, "message_fromWire12.wire");
- const TSIGRecord* tsig_rr = message_parse.getTSIGRecord();
- ASSERT_NE(static_cast<void*>(NULL), tsig_rr);
- EXPECT_EQ(Name("www.example.com"), tsig_rr->getName());
- // len(www.example.com) = 17, but when fully compressed, the length is
- // 2 bytes. So the length of the record should be 15 bytes shorter.
- EXPECT_EQ(70, tsig_rr->getLength());
- }
- TEST_F(MessageTest, fromWireWithBadTSIG) {
- // Multiple TSIG RRs
- EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire13.wire"),
- DNSMessageFORMERR);
- message_parse.clear(Message::PARSE);
- // TSIG in the answer section (must be in additional)
- EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire14.wire"),
- DNSMessageFORMERR);
- message_parse.clear(Message::PARSE);
- // TSIG is not the last record.
- EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire15.wire"),
- DNSMessageFORMERR);
- message_parse.clear(Message::PARSE);
- // Unexpected RR Class (this will fail in constructing TSIGRecord)
- EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire16.wire"),
- DNSMessageFORMERR);
- }
- TEST_F(MessageTest, getRRCount) {
- // by default all counters should be 0
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
- message_render.addQuestion(Question(Name("test.example.com"),
- RRClass::IN(), RRType::A()));
- EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
- // rrset_a contains two RRs
- message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
- EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
- // parse a message containing a Question and EDNS OPT RR.
- // OPT shouldn't be counted as normal RR, so result of getRRCount
- // shouldn't change.
- factoryFromFile(message_parse, "message_fromWire11.wire");
- EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
- // out-of-band section ID
- EXPECT_THROW(message_parse.getRRCount(bogus_section), OutOfRange);
- }
- TEST_F(MessageTest, addRRset) {
- // default case
- message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
- EXPECT_EQ(rrset_a,
- *message_render.beginSection(Message::SECTION_ANSWER));
- EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
- // signed RRset, default case
- message_render.clear(Message::RENDER);
- message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
- EXPECT_EQ(rrset_aaaa,
- *message_render.beginSection(Message::SECTION_ANSWER));
- EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_ANSWER));
- // signed RRset, add with the RRSIG. getRRCount() should return 2
- message_render.clear(Message::RENDER);
- message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa, true);
- EXPECT_EQ(rrset_aaaa,
- *message_render.beginSection(Message::SECTION_ANSWER));
- EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
- // signed RRset, add explicitly without RRSIG.
- message_render.clear(Message::RENDER);
- message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa, false);
- EXPECT_EQ(rrset_aaaa,
- *message_render.beginSection(Message::SECTION_ANSWER));
- EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_ANSWER));
- }
- TEST_F(MessageTest, badAddRRset) {
- // addRRset() isn't allowed in the parse mode.
- EXPECT_THROW(message_parse.addRRset(Message::SECTION_ANSWER,
- rrset_a), InvalidMessageOperation);
- // out-of-band section ID
- EXPECT_THROW(message_render.addRRset(bogus_section, rrset_a), OutOfRange);
- }
- TEST_F(MessageTest, hasRRset) {
- message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
- EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::A()));
- // section doesn't match
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
- RRClass::IN(), RRType::A()));
- // name doesn't match
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER,
- Name("nomatch.example"),
- RRClass::IN(), RRType::A()));
- // RR class doesn't match
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::CH(), RRType::A()));
- // RR type doesn't match
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::AAAA()));
- // out-of-band section ID
- EXPECT_THROW(message_render.hasRRset(bogus_section, test_name,
- RRClass::IN(), RRType::A()),
- OutOfRange);
- // Repeat the checks having created an RRset of the appropriate type.
- RRsetPtr rrs1(new RRset(test_name, RRClass::IN(), RRType::A(), RRTTL(60)));
- EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, rrs1));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, rrs1));
- RRsetPtr rrs2(new RRset(Name("nomatch.example"), RRClass::IN(), RRType::A(),
- RRTTL(5)));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs2));
- RRsetPtr rrs3(new RRset(test_name, RRClass::CH(), RRType::A(), RRTTL(60)));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs3));
- RRsetPtr rrs4(new RRset(test_name, RRClass::IN(), RRType::AAAA(), RRTTL(5)));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs4));
- RRsetPtr rrs5(new RRset(test_name, RRClass::IN(), RRType::AAAA(), RRTTL(5)));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, rrs4));
- EXPECT_THROW(message_render.hasRRset(bogus_section, rrs1), OutOfRange);
- }
- TEST_F(MessageTest, removeRRset) {
- message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
- message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
- EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::A()));
- EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::AAAA()));
- EXPECT_EQ(3, message_render.getRRCount(Message::SECTION_ANSWER));
- // Locate the AAAA RRset and remove it; this has one RR in it.
- RRsetIterator i = message_render.beginSection(Message::SECTION_ANSWER);
- if ((*i)->getType() == RRType::A()) {
- ++i;
- }
- EXPECT_EQ(RRType::AAAA(), (*i)->getType());
- message_render.removeRRset(Message::SECTION_ANSWER, i);
- EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::A()));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::AAAA()));
- EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
- }
- TEST_F(MessageTest, clearQuestionSection) {
- QuestionPtr q(new Question(Name("www.example.com"), RRClass::IN(),
- RRType::A()));
- message_render.addQuestion(q);
- ASSERT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
- message_render.clearSection(Message::SECTION_QUESTION);
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
- }
- TEST_F(MessageTest, clearAnswerSection) {
- // Add two RRsets, check they are present, clear the section,
- // check if they are gone.
- message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
- message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
- ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::A()));
- ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::AAAA()));
- ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ANSWER));
- message_render.clearSection(Message::SECTION_ANSWER);
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::A()));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::AAAA()));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
- }
- TEST_F(MessageTest, clearAuthoritySection) {
- // Add two RRsets, check they are present, clear the section,
- // check if they are gone.
- message_render.addRRset(Message::SECTION_AUTHORITY, rrset_a);
- message_render.addRRset(Message::SECTION_AUTHORITY, rrset_aaaa);
- ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
- RRClass::IN(), RRType::A()));
- ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
- RRClass::IN(), RRType::AAAA()));
- ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_AUTHORITY));
- message_render.clearSection(Message::SECTION_AUTHORITY);
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
- RRClass::IN(), RRType::A()));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
- RRClass::IN(), RRType::AAAA()));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
- }
- TEST_F(MessageTest, clearAdditionalSection) {
- // Add two RRsets, check they are present, clear the section,
- // check if they are gone.
- message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_a);
- message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_aaaa);
- ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
- RRClass::IN(), RRType::A()));
- ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
- RRClass::IN(), RRType::AAAA()));
- ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ADDITIONAL));
- message_render.clearSection(Message::SECTION_ADDITIONAL);
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
- RRClass::IN(), RRType::A()));
- EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
- RRClass::IN(), RRType::AAAA()));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
- }
- TEST_F(MessageTest, badBeginSection) {
- // valid cases are tested via other tests
- EXPECT_THROW(message_render.beginSection(Message::SECTION_QUESTION),
- InvalidMessageSection);
- EXPECT_THROW(message_render.beginSection(bogus_section), OutOfRange);
- }
- TEST_F(MessageTest, badEndSection) {
- // valid cases are tested via other tests
- EXPECT_THROW(message_render.endSection(Message::SECTION_QUESTION),
- InvalidMessageSection);
- EXPECT_THROW(message_render.endSection(bogus_section), OutOfRange);
- }
- TEST_F(MessageTest, appendSection) {
- Message target(Message::RENDER);
- // Section check
- EXPECT_THROW(target.appendSection(bogus_section, message_render),
- OutOfRange);
- // Make sure nothing is copied if there is nothing to copy
- target.appendSection(Message::SECTION_QUESTION, message_render);
- EXPECT_EQ(0, target.getRRCount(Message::SECTION_QUESTION));
- target.appendSection(Message::SECTION_ANSWER, message_render);
- EXPECT_EQ(0, target.getRRCount(Message::SECTION_ANSWER));
- target.appendSection(Message::SECTION_AUTHORITY, message_render);
- EXPECT_EQ(0, target.getRRCount(Message::SECTION_AUTHORITY));
- target.appendSection(Message::SECTION_ADDITIONAL, message_render);
- EXPECT_EQ(0, target.getRRCount(Message::SECTION_ADDITIONAL));
- // Now add some data, copy again, and see if it got added
- message_render.addQuestion(Question(Name("test.example.com"),
- RRClass::IN(), RRType::A()));
- message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
- message_render.addRRset(Message::SECTION_AUTHORITY, rrset_a);
- message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_a);
- message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_aaaa);
- target.appendSection(Message::SECTION_QUESTION, message_render);
- EXPECT_EQ(1, target.getRRCount(Message::SECTION_QUESTION));
- target.appendSection(Message::SECTION_ANSWER, message_render);
- EXPECT_EQ(2, target.getRRCount(Message::SECTION_ANSWER));
- EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::A()));
- target.appendSection(Message::SECTION_AUTHORITY, message_render);
- EXPECT_EQ(2, target.getRRCount(Message::SECTION_AUTHORITY));
- EXPECT_TRUE(target.hasRRset(Message::SECTION_AUTHORITY, test_name,
- RRClass::IN(), RRType::A()));
- target.appendSection(Message::SECTION_ADDITIONAL, message_render);
- EXPECT_EQ(3, target.getRRCount(Message::SECTION_ADDITIONAL));
- EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
- RRClass::IN(), RRType::A()));
- EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
- RRClass::IN(), RRType::AAAA()));
- // One more test, test to see if the section gets added, not replaced
- Message source2(Message::RENDER);
- source2.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
- target.appendSection(Message::SECTION_ANSWER, source2);
- EXPECT_EQ(3, target.getRRCount(Message::SECTION_ANSWER));
- EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::A()));
- EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
- RRClass::IN(), RRType::AAAA()));
-
- }
- TEST_F(MessageTest, parseHeader) {
- received_data.clear();
- UnitTestUtil::readWireData("message_fromWire1", received_data);
- // parseHeader() isn't allowed in the render mode.
- InputBuffer buffer(&received_data[0], received_data.size());
- EXPECT_THROW(message_render.parseHeader(buffer), InvalidMessageOperation);
- message_parse.parseHeader(buffer);
- EXPECT_EQ(0x1035, message_parse.getQid());
- EXPECT_EQ(Opcode::QUERY(), message_parse.getOpcode());
- EXPECT_EQ(Rcode::NOERROR(), message_parse.getRcode());
- EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_QR));
- EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_AA));
- EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_TC));
- EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_RD));
- EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_RA));
- EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_AD));
- EXPECT_FALSE(message_parse.getHeaderFlag(Message::HEADERFLAG_CD));
- EXPECT_EQ(1, message_parse.getRRCount(Message::SECTION_QUESTION));
- EXPECT_EQ(2, message_parse.getRRCount(Message::SECTION_ANSWER));
- EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_AUTHORITY));
- EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_ADDITIONAL));
- // Only the header part should have been examined.
- EXPECT_EQ(12, buffer.getPosition()); // 12 = size of the header section
- EXPECT_TRUE(message_parse.beginQuestion() == message_parse.endQuestion());
- EXPECT_TRUE(message_parse.beginSection(Message::SECTION_ANSWER) ==
- message_parse.endSection(Message::SECTION_ANSWER));
- EXPECT_TRUE(message_parse.beginSection(Message::SECTION_AUTHORITY) ==
- message_parse.endSection(Message::SECTION_AUTHORITY));
- EXPECT_TRUE(message_parse.beginSection(Message::SECTION_ADDITIONAL) ==
- message_parse.endSection(Message::SECTION_ADDITIONAL));
- }
- TEST_F(MessageTest, fromWire) {
- // fromWire() isn't allowed in the render mode.
- EXPECT_THROW(factoryFromFile(message_render, "message_fromWire1"),
- InvalidMessageOperation);
- factoryFromFile(message_parse, "message_fromWire1");
- EXPECT_EQ(0x1035, message_parse.getQid());
- EXPECT_EQ(Opcode::QUERY(), message_parse.getOpcode());
- EXPECT_EQ(Rcode::NOERROR(), message_parse.getRcode());
- EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_QR));
- EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_RD));
- EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_AA));
- QuestionPtr q = *message_parse.beginQuestion();
- EXPECT_EQ(test_name, q->getName());
- EXPECT_EQ(RRType::A(), q->getType());
- EXPECT_EQ(RRClass::IN(), q->getClass());
- EXPECT_EQ(1, message_parse.getRRCount(Message::SECTION_QUESTION));
- EXPECT_EQ(2, message_parse.getRRCount(Message::SECTION_ANSWER));
- EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_AUTHORITY));
- EXPECT_EQ(0, message_parse.getRRCount(Message::SECTION_ADDITIONAL));
- RRsetPtr rrset = *message_parse.beginSection(Message::SECTION_ANSWER);
- EXPECT_EQ(test_name, rrset->getName());
- EXPECT_EQ(RRType::A(), rrset->getType());
- EXPECT_EQ(RRClass::IN(), rrset->getClass());
- // TTL should be 3600, even though that of the 2nd RR is 7200
- EXPECT_EQ(RRTTL(3600), rrset->getTTL());
- RdataIteratorPtr it = rrset->getRdataIterator();
- EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
- it->next();
- EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
- it->next();
- EXPECT_TRUE(it->isLast());
- }
- TEST_F(MessageTest, fromWireShortBuffer) {
- // We trim a valid message (ending with an SOA RR) for one byte.
- // fromWire() should throw an exception while parsing the trimmed RR.
- UnitTestUtil::readWireData("message_fromWire22.wire", received_data);
- InputBuffer buffer(&received_data[0], received_data.size() - 1);
- EXPECT_THROW(message_parse.fromWire(buffer), InvalidBufferPosition);
- }
- TEST_F(MessageTest, fromWireCombineRRs) {
- // This message contains 3 RRs in the answer section in the order of
- // A, AAAA, A types. fromWire() should combine the two A RRs into a
- // single RRset by default.
- factoryFromFile(message_parse, "message_fromWire19.wire");
- RRsetIterator it = message_parse.beginSection(Message::SECTION_ANSWER);
- RRsetIterator it_end = message_parse.endSection(Message::SECTION_ANSWER);
- ASSERT_TRUE(it != it_end);
- EXPECT_EQ(RRType::A(), (*it)->getType());
- EXPECT_EQ(2, (*it)->getRdataCount());
- ++it;
- ASSERT_TRUE(it != it_end);
- EXPECT_EQ(RRType::AAAA(), (*it)->getType());
- EXPECT_EQ(1, (*it)->getRdataCount());
- }
- // A helper function for a test pattern commonly used in several tests below.
- void
- preserveRRCheck(const Message& message, Message::Section section) {
- RRsetIterator it = message.beginSection(section);
- RRsetIterator it_end = message.endSection(section);
- ASSERT_TRUE(it != it_end);
- EXPECT_EQ(RRType::A(), (*it)->getType());
- EXPECT_EQ(1, (*it)->getRdataCount());
- EXPECT_EQ("192.0.2.1", (*it)->getRdataIterator()->getCurrent().toText());
- ++it;
- ASSERT_TRUE(it != it_end);
- EXPECT_EQ(RRType::AAAA(), (*it)->getType());
- EXPECT_EQ(1, (*it)->getRdataCount());
- EXPECT_EQ("2001:db8::1", (*it)->getRdataIterator()->getCurrent().toText());
- ++it;
- ASSERT_TRUE(it != it_end);
- EXPECT_EQ(RRType::A(), (*it)->getType());
- EXPECT_EQ(1, (*it)->getRdataCount());
- EXPECT_EQ("192.0.2.2", (*it)->getRdataIterator()->getCurrent().toText());
- }
- TEST_F(MessageTest, fromWirePreserveAnswer) {
- // Using the same data as the previous test, but specify the PRESERVE_ORDER
- // option. The received order of RRs should be preserved, and each RR
- // should be stored in a single RRset.
- factoryFromFile(message_parse, "message_fromWire19.wire",
- Message::PRESERVE_ORDER);
- {
- SCOPED_TRACE("preserve answer RRs");
- preserveRRCheck(message_parse, Message::SECTION_ANSWER);
- }
- }
- TEST_F(MessageTest, fromWirePreserveAuthority) {
- // Same for the previous test, but for the authority section.
- factoryFromFile(message_parse, "message_fromWire20.wire",
- Message::PRESERVE_ORDER);
- {
- SCOPED_TRACE("preserve authority RRs");
- preserveRRCheck(message_parse, Message::SECTION_AUTHORITY);
- }
- }
- TEST_F(MessageTest, fromWirePreserveAdditional) {
- // Same for the previous test, but for the additional section.
- factoryFromFile(message_parse, "message_fromWire21.wire",
- Message::PRESERVE_ORDER);
- {
- SCOPED_TRACE("preserve additional RRs");
- preserveRRCheck(message_parse, Message::SECTION_ADDITIONAL);
- }
- }
- TEST_F(MessageTest, EDNS0ExtRcode) {
- // Extended Rcode = BADVERS
- factoryFromFile(message_parse, "message_fromWire10.wire");
- EXPECT_EQ(Rcode::BADVERS(), message_parse.getRcode());
- // Maximum extended Rcode
- message_parse.clear(Message::PARSE);
- factoryFromFile(message_parse, "message_fromWire11.wire");
- EXPECT_EQ(0xfff, message_parse.getRcode().getCode());
- }
- TEST_F(MessageTest, BadEDNS0) {
- // OPT RR in the answer section
- EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire4"),
- DNSMessageFORMERR);
- // multiple OPT RRs (in the additional section)
- message_parse.clear(Message::PARSE);
- EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire5"),
- DNSMessageFORMERR);
- }
- TEST_F(MessageTest, toWire) {
- message_render.setQid(0x1035);
- message_render.setOpcode(Opcode::QUERY());
- message_render.setRcode(Rcode::NOERROR());
- message_render.setHeaderFlag(Message::HEADERFLAG_QR, true);
- message_render.setHeaderFlag(Message::HEADERFLAG_RD, true);
- message_render.setHeaderFlag(Message::HEADERFLAG_AA, true);
- message_render.addQuestion(Question(Name("test.example.com"), RRClass::IN(),
- RRType::A()));
- message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
- EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
- EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
- EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
- message_render.toWire(renderer);
- vector<unsigned char> data;
- UnitTestUtil::readWireData("message_toWire1", data);
- EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
- obuffer.getLength(), &data[0], data.size());
- }
- TEST_F(MessageTest, toWireInParseMode) {
- // toWire() isn't allowed in the parse mode.
- EXPECT_THROW(message_parse.toWire(renderer), InvalidMessageOperation);
- }
- // See dnssectime_unittest.cc
- template <int64_t NOW>
- int64_t
- testGetTime() {
- return (NOW);
- }
- // bit-wise constant flags to configure DNS header flags for test
- // messages.
- const unsigned int QR_FLAG = 0x1;
- const unsigned int AA_FLAG = 0x2;
- const unsigned int RD_FLAG = 0x4;
- void
- commonTSIGToWireCheck(Message& message, MessageRenderer& renderer,
- TSIGContext& tsig_ctx, const char* const expected_file,
- unsigned int message_flags = RD_FLAG,
- RRType qtype = RRType::A(),
- const vector<const char*>* answer_data = NULL)
- {
- message.setOpcode(Opcode::QUERY());
- message.setRcode(Rcode::NOERROR());
- if ((message_flags & QR_FLAG) != 0) {
- message.setHeaderFlag(Message::HEADERFLAG_QR);
- }
- if ((message_flags & AA_FLAG) != 0) {
- message.setHeaderFlag(Message::HEADERFLAG_AA);
- }
- if ((message_flags & RD_FLAG) != 0) {
- message.setHeaderFlag(Message::HEADERFLAG_RD);
- }
- message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
- qtype));
- if (answer_data != NULL) {
- RRsetPtr ans_rrset(new RRset(Name("www.example.com"), RRClass::IN(),
- qtype, RRTTL(86400)));
- for (vector<const char*>::const_iterator it = answer_data->begin();
- it != answer_data->end();
- ++it) {
- ans_rrset->addRdata(createRdata(qtype, RRClass::IN(), *it));
- }
- message.addRRset(Message::SECTION_ANSWER, ans_rrset);
- }
- message.toWire(renderer, tsig_ctx);
- vector<unsigned char> expected_data;
- UnitTestUtil::readWireData(expected_file, expected_data);
- EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
- renderer.getLength(),
- &expected_data[0], expected_data.size());
- }
- TEST_F(MessageTest, toWireWithTSIG) {
- // Rendering a message with TSIG. Various special cases specific to
- // TSIG are tested in the tsig tests. We only check the message contains
- // a TSIG at the end and the ARCOUNT of the header is updated.
- isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
- message_render.setQid(0x2d65);
- {
- SCOPED_TRACE("Message sign with TSIG");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
- "message_toWire2.wire");
- }
- }
- TEST_F(MessageTest, toWireWithEDNSAndTSIG) {
- // Similar to the previous test, but with an EDNS before TSIG.
- // The wire data check will confirm the ordering.
- isc::util::detail::gettimeFunction = testGetTime<0x4db60d1f>;
- message_render.setQid(0x6cd);
- EDNSPtr edns(new EDNS());
- edns->setUDPSize(4096);
- message_render.setEDNS(edns);
- {
- SCOPED_TRACE("Message sign with TSIG and EDNS");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
- "message_toWire3.wire");
- }
- }
- // Some of the following tests involve truncation. We use the query name
- // "www.example.com" and some TXT question/answers. The length of the
- // header and question will be 33 bytes. If we also try to include a
- // TSIG of the same key name (not compressed) with HMAC-MD5, the TSIG RR
- // will be 85 bytes.
- // A long TXT RDATA. With a fully compressed owner name, the corresponding
- // RR will be 268 bytes.
- const char* const long_txt1 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde";
- // With a fully compressed owner name, the corresponding RR will be 212 bytes.
- // It should result in truncation even without TSIG (33 + 268 + 212 = 513)
- const char* const long_txt2 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456";
- // With a fully compressed owner name, the corresponding RR will be 127 bytes.
- // So, it can fit in the standard 512 bytes with txt1 and without TSIG, but
- // adding a TSIG would result in truncation (33 + 268 + 127 + 85 = 513)
- const char* const long_txt3 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01";
- // This is 1 byte shorter than txt3, which will result in a possible longest
- // message containing answer RRs and TSIG.
- const char* const long_txt4 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0";
- // Example output generated by
- // "dig -y www.example.com:SFuWd/q99SzF8Yzd1QbB9g== www.example.com txt
- // QID: 0x22c2
- // Time Signed: 0x00004e179212
- TEST_F(MessageTest, toWireTSIGTruncation) {
- isc::util::detail::gettimeFunction = testGetTime<0x4e179212>;
- // Verify a validly signed query so that we can use the TSIG context
- factoryFromFile(message_parse, "message_fromWire17.wire");
- EXPECT_EQ(TSIGError::NOERROR(),
- tsig_ctx.verify(message_parse.getTSIGRecord(),
- &received_data[0], received_data.size()));
- message_render.setQid(0x22c2);
- vector<const char*> answer_data;
- answer_data.push_back(long_txt1);
- answer_data.push_back(long_txt2);
- {
- SCOPED_TRACE("Message sign with TSIG and TC bit on");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
- "message_toWire4.wire",
- QR_FLAG|AA_FLAG|RD_FLAG,
- RRType::TXT(), &answer_data);
- }
- }
- TEST_F(MessageTest, toWireTSIGTruncation2) {
- // Similar to the previous test, but without TSIG it wouldn't cause
- // truncation.
- isc::util::detail::gettimeFunction = testGetTime<0x4e179212>;
- factoryFromFile(message_parse, "message_fromWire17.wire");
- EXPECT_EQ(TSIGError::NOERROR(),
- tsig_ctx.verify(message_parse.getTSIGRecord(),
- &received_data[0], received_data.size()));
- message_render.setQid(0x22c2);
- vector<const char*> answer_data;
- answer_data.push_back(long_txt1);
- answer_data.push_back(long_txt3);
- {
- SCOPED_TRACE("Message sign with TSIG and TC bit on (2)");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
- "message_toWire4.wire",
- QR_FLAG|AA_FLAG|RD_FLAG,
- RRType::TXT(), &answer_data);
- }
- }
- TEST_F(MessageTest, toWireTSIGTruncation3) {
- // Similar to previous ones, but truncation occurs due to too many
- // Questions (very unusual, but not necessarily illegal).
- // We are going to create a message starting with a standard
- // header (12 bytes) and multiple questions in the Question
- // section of the same owner name (changing the RRType, just so
- // that it would be the form that would be accepted by the BIND 9
- // parser). The first Question is 21 bytes in length, and the subsequent
- // ones are 6 bytes. We'll also use a TSIG whose size is 85 bytes.
- // Up to 66 questions can fit in the standard 512-byte buffer
- // (12 + 21 + 6 * 65 + 85 = 508). If we try to add one more it would
- // result in truncation.
- message_render.setOpcode(Opcode::QUERY());
- message_render.setRcode(Rcode::NOERROR());
- for (int i = 1; i <= 67; ++i) {
- message_render.addQuestion(Question(Name("www.example.com"),
- RRClass::IN(), RRType(i)));
- }
- message_render.toWire(renderer, tsig_ctx);
- // Check the rendered data by parsing it. We only check it has the
- // TC bit on, has the correct number of questions, and has a TSIG RR.
- // Checking the signature wouldn't be necessary for this rare case
- // scenario.
- InputBuffer buffer(renderer.getData(), renderer.getLength());
- message_parse.fromWire(buffer);
- EXPECT_TRUE(message_parse.getHeaderFlag(Message::HEADERFLAG_TC));
- // Note that the number of questions are 66, not 67 as we tried to add.
- EXPECT_EQ(66, message_parse.getRRCount(Message::SECTION_QUESTION));
- EXPECT_TRUE(message_parse.getTSIGRecord() != NULL);
- }
- TEST_F(MessageTest, toWireTSIGNoTruncation) {
- // A boundary case that shouldn't cause truncation: the resulting
- // response message with a TSIG will be 512 bytes long.
- isc::util::detail::gettimeFunction = testGetTime<0x4e17b38d>;
- factoryFromFile(message_parse, "message_fromWire18.wire");
- EXPECT_EQ(TSIGError::NOERROR(),
- tsig_ctx.verify(message_parse.getTSIGRecord(),
- &received_data[0], received_data.size()));
- message_render.setQid(0xd6e2);
- vector<const char*> answer_data;
- answer_data.push_back(long_txt1);
- answer_data.push_back(long_txt4);
- {
- SCOPED_TRACE("Message sign with TSIG, no truncation");
- commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
- "message_toWire5.wire",
- QR_FLAG|AA_FLAG|RD_FLAG,
- RRType::TXT(), &answer_data);
- }
- }
- // This is a buggy renderer for testing. It behaves like the straightforward
- // MessageRenderer, but once it has some data, its setLengthLimit() ignores
- // the given parameter and resets the limit to the current length, making
- // subsequent insertion result in truncation, which would make TSIG RR
- // rendering fail unexpectedly in the test that follows.
- class BadRenderer : public MessageRenderer {
- public:
- BadRenderer(isc::util::OutputBuffer& buffer) :
- MessageRenderer(buffer)
- {}
- virtual void setLengthLimit(size_t len) {
- if (getLength() > 0) {
- MessageRenderer::setLengthLimit(getLength());
- } else {
- MessageRenderer::setLengthLimit(len);
- }
- }
- };
- TEST_F(MessageTest, toWireTSIGLengthErrors) {
- // specify an unusual short limit that wouldn't be able to hold
- // the TSIG.
- renderer.setLengthLimit(tsig_ctx.getTSIGLength() - 1);
- // Use commonTSIGToWireCheck() only to call toWire() with otherwise valid
- // conditions. The checks inside it don't matter because we expect an
- // exception before any of the checks.
- EXPECT_THROW(commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
- "message_toWire2.wire"),
- InvalidParameter);
- // This one is large enough for TSIG, but the remaining limit isn't
- // even enough for the Header section.
- renderer.clear();
- message_render.clear(Message::RENDER);
- renderer.setLengthLimit(tsig_ctx.getTSIGLength() + 1);
- EXPECT_THROW(commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
- "message_toWire2.wire"),
- InvalidParameter);
- // Trying to render a message with TSIG using a buggy renderer.
- obuffer.clear();
- BadRenderer bad_renderer(obuffer);
- bad_renderer.setLengthLimit(512);
- message_render.clear(Message::RENDER);
- EXPECT_THROW(commonTSIGToWireCheck(message_render, bad_renderer, tsig_ctx,
- "message_toWire2.wire"),
- Unexpected);
- }
- TEST_F(MessageTest, toWireWithoutOpcode) {
- message_render.setRcode(Rcode::NOERROR());
- EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
- }
- TEST_F(MessageTest, toWireWithoutRcode) {
- message_render.setOpcode(Opcode::QUERY());
- EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
- }
- TEST_F(MessageTest, toText) {
- // Check toText() output for a typical DNS response with records in
- // all sections
-
- factoryFromFile(message_parse, "message_toText1.wire");
- {
- SCOPED_TRACE("Message toText test (basic case)");
- ifstream ifs;
- unittests::openTestData("message_toText1.txt", ifs);
- unittests::matchTextData(ifs, message_parse.toText());
- }
- // Another example with EDNS. The expected data was slightly modified
- // from the dig output (other than replacing tabs with a space): adding
- // a newline after the "OPT PSEUDOSECTION". This is an intentional change
- // in our version for better readability.
- message_parse.clear(Message::PARSE);
- factoryFromFile(message_parse, "message_toText2.wire");
- {
- SCOPED_TRACE("Message toText test with EDNS");
- ifstream ifs;
- unittests::openTestData("message_toText2.txt", ifs);
- unittests::matchTextData(ifs, message_parse.toText());
- }
- // Another example with TSIG. The expected data was slightly modified
- // from the dig output (other than replacing tabs with a space): removing
- // a redundant white space at the end of TSIG RDATA. We'd rather consider
- // it a dig's defect than a feature.
- message_parse.clear(Message::PARSE);
- factoryFromFile(message_parse, "message_toText3.wire");
- {
- SCOPED_TRACE("Message toText test with TSIG");
- ifstream ifs;
- unittests::openTestData("message_toText3.txt", ifs);
- unittests::matchTextData(ifs, message_parse.toText());
- }
- }
- TEST_F(MessageTest, toTextWithoutOpcode) {
- message_render.setRcode(Rcode::NOERROR());
- EXPECT_THROW(message_render.toText(), InvalidMessageOperation);
- }
- TEST_F(MessageTest, toTextWithoutRcode) {
- message_render.setOpcode(Opcode::QUERY());
- EXPECT_THROW(message_render.toText(), InvalidMessageOperation);
- }
- }
|