diff options
Diffstat (limited to 'src/lib/dns/tests/edns_unittest.cc')
-rw-r--r-- | src/lib/dns/tests/edns_unittest.cc | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/src/lib/dns/tests/edns_unittest.cc b/src/lib/dns/tests/edns_unittest.cc new file mode 100644 index 0000000..239c2eb --- /dev/null +++ b/src/lib/dns/tests/edns_unittest.cc @@ -0,0 +1,258 @@ +// Copyright (C) 2010-2024 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 <sstream> + +#include <exceptions/exceptions.h> + +#include <util/buffer.h> +#include <dns/edns.h> +#include <dns/exceptions.h> +#include <dns/message.h> +#include <dns/messagerenderer.h> +#include <dns/name.h> +#include <dns/rcode.h> +#include <dns/rdataclass.h> +#include <dns/rrclass.h> +#include <dns/rrttl.h> +#include <dns/rrtype.h> + +#include <gtest/gtest.h> + +#include <dns/tests/unittest_util.h> +#include <util/unittests/wiredata.h> + +using namespace std; +using namespace isc::dns; +using namespace isc::util; +using namespace isc::dns::rdata; +using isc::UnitTestUtil; +using isc::util::unittests::matchWireData; + +const uint8_t EDNS::SUPPORTED_VERSION; + +namespace { +class EDNSTest : public ::testing::Test { +protected: + EDNSTest() : rrtype(RRType::OPT()), buffer(0, 0), obuffer(0), rcode(0) { + opt_rdata = ConstRdataPtr(new generic::OPT()); + edns_base.setUDPSize(4096); + } + RRType rrtype; + EDNS edns_base; + ConstEDNSPtr edns; + InputBuffer buffer; + OutputBuffer obuffer; + MessageRenderer renderer; + ConstRdataPtr opt_rdata; + Rcode rcode; + vector<unsigned char> wiredata; +}; + +// RRClass of EDNS OPT means UDP buffer size +const RRClass rrclass(4096); +// RRTTL of EDNS OPT encodes extended-rcode, version, and DO bit +const RRTTL rrttl_do_on(0x00008000); // DO=on +const RRTTL rrttl_do_off(0); // DO=off +const RRTTL rrttl_badver(0x00018000); // version=1, DO=on + +TEST_F(EDNSTest, badVerConstruct) { + EXPECT_THROW(EDNS(1), isc::InvalidParameter); +} + +TEST_F(EDNSTest, DNSSECDOBit) { + // tests for EDNS from RR + + // DO bit is on, so DNSSEC should be considered to be supported. + EXPECT_TRUE(EDNS(Name::ROOT_NAME(), rrclass, rrtype, + rrttl_do_on, *opt_rdata).getDNSSECAwareness()); + + // DO bit is off. DNSSEC should be considered to be unsupported. + EXPECT_FALSE(EDNS(Name::ROOT_NAME(), rrclass, rrtype, + rrttl_do_off, *opt_rdata).getDNSSECAwareness()); + + // tests for EDNS constructed by hand + EXPECT_FALSE(edns_base.getDNSSECAwareness()); // false by default + edns_base.setDNSSECAwareness(true); // enable by hand + EXPECT_TRUE(edns_base.getDNSSECAwareness()); + edns_base.setDNSSECAwareness(false); // disable by hand + EXPECT_FALSE(edns_base.getDNSSECAwareness()); +} + +TEST_F(EDNSTest, UDPSize) { + EXPECT_EQ(4096, EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_on, + *opt_rdata).getUDPSize()); + + // EDNS UDP size smaller than the traditional max, 512. Unusual, but + // not prohibited. + edns_base.setUDPSize(511); + EXPECT_EQ(511, edns_base.getUDPSize()); + + // Even 0 is okay. + edns_base.setUDPSize(0); + EXPECT_EQ(0, edns_base.getUDPSize()); + + // Possible max value is also okay, although the higher layer app may + // adjust it to a reasonably lower value + edns_base.setUDPSize(65535); + EXPECT_EQ(65535, edns_base.getUDPSize()); +} + +TEST_F(EDNSTest, getVersion) { + // Constructed by hand + EXPECT_EQ(EDNS::SUPPORTED_VERSION, EDNS().getVersion()); + + // From RR + EXPECT_EQ(EDNS::SUPPORTED_VERSION, + EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_on, + *opt_rdata).getVersion()); +} + +TEST_F(EDNSTest, BadWireData) { + // Incompatible RR type + EXPECT_THROW(EDNS(Name::ROOT_NAME(), rrclass, RRType::A(), + rrttl_do_on, *opt_rdata), isc::InvalidParameter); + + // OPT RR of a non root name + EXPECT_THROW(EDNS(Name("example.com"), rrclass, rrtype, + rrttl_do_on, *opt_rdata), DNSMessageFORMERR); + + // Unsupported Version + EXPECT_THROW(EDNS(Name::ROOT_NAME(), rrclass, rrtype, + rrttl_badver, *opt_rdata), DNSMessageBADVERS); +} + +TEST_F(EDNSTest, toText) { + // Typical case, disabling DNSSEC + EXPECT_EQ("; EDNS: version: 0, flags:; udp: 4096\n", + EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_off, + *opt_rdata).toText()); + + // Typical case, enabling DNSSEC + EXPECT_EQ("; EDNS: version: 0, flags: do; udp: 4096\n", + EDNS(Name::ROOT_NAME(), rrclass, rrtype, rrttl_do_on, + *opt_rdata).toText()); + + // Non-0 extended Rcode: ignored in the toText() output. + EXPECT_EQ("; EDNS: version: 0, flags: do; udp: 4096\n", + EDNS(Name::ROOT_NAME(), rrclass, rrtype, + RRTTL(0x01008000), *opt_rdata).toText()); + + // Unknown flag: ignored in the toText() output. + EXPECT_EQ("; EDNS: version: 0, flags: do; udp: 4096\n", + EDNS(Name::ROOT_NAME(), rrclass, rrtype, + RRTTL(0x00008001), *opt_rdata).toText()); +} + +TEST_F(EDNSTest, toWireRenderer) { + // Typical case, (explicitly) disabling DNSSEC + edns_base.setDNSSECAwareness(false); + EXPECT_EQ(1, edns_base.toWire(renderer, + Rcode::NOERROR().getExtendedCode())); + UnitTestUtil::readWireData("edns_toWire1.wire", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); + + // Typical case, enabling DNSSEC + renderer.clear(); + wiredata.clear(); + edns_base.setDNSSECAwareness(true); + EXPECT_EQ(1, edns_base.toWire(renderer, + Rcode::NOERROR().getExtendedCode())); + UnitTestUtil::readWireData("edns_toWire2.wire", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); + + // Non-0 extended Rcode + renderer.clear(); + wiredata.clear(); + edns_base.setDNSSECAwareness(true); + EXPECT_EQ(1, edns_base.toWire(renderer, + Rcode::BADVERS().getExtendedCode())); + UnitTestUtil::readWireData("edns_toWire3.wire", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); + + // Uncommon UDP buffer size + renderer.clear(); + wiredata.clear(); + edns_base.setDNSSECAwareness(true); + edns_base.setUDPSize(511); + EXPECT_EQ(1, edns_base.toWire(renderer, + Rcode::NOERROR().getExtendedCode())); + UnitTestUtil::readWireData("edns_toWire4.wire", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); + + // From RR with unknown flag. If used for toWire(), the unknown flag + // should disappear. + renderer.clear(); + wiredata.clear(); + EXPECT_EQ(1, EDNS(Name::ROOT_NAME(), rrclass, rrtype, RRTTL(0x00008001), + *opt_rdata).toWire(renderer, + Rcode::NOERROR().getExtendedCode())); + UnitTestUtil::readWireData("edns_toWire2.wire", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + renderer.getData(), renderer.getLength()); + + // If the available length in the renderer is not sufficient for the OPT + // RR, it shouldn't be inserted. + renderer.clear(); + renderer.setLengthLimit(10); // 10 = minimum length of OPT RR - 1 + edns_base.setDNSSECAwareness(true); + edns_base.setUDPSize(4096); + EXPECT_EQ(0, edns_base.toWire(renderer, + Rcode::NOERROR().getExtendedCode())); + // renderer should be intact + EXPECT_EQ(0, renderer.getLength()); +} + +TEST_F(EDNSTest, toWireBuffer) { + // "to renderer" and "to buffer" should generally produce the same result. + // for simplicity we only check one typical case to confirm that. + EXPECT_EQ(1, edns_base.toWire(obuffer, + Rcode::NOERROR().getExtendedCode())); + UnitTestUtil::readWireData("edns_toWire1.wire", wiredata); + matchWireData(&wiredata[0], wiredata.size(), + obuffer.getData(), obuffer.getLength()); +} + +TEST_F(EDNSTest, createFromRR) { + uint8_t extended_rcode; + + // normal case + edns = ConstEDNSPtr(createEDNSFromRR(Name::ROOT_NAME(), rrclass, rrtype, + rrttl_do_on, *opt_rdata, + extended_rcode)); + EXPECT_EQ(EDNS::SUPPORTED_VERSION, edns->getVersion()); + EXPECT_TRUE(edns->getDNSSECAwareness()); + EXPECT_EQ(4096, edns->getUDPSize()); + EXPECT_EQ(0, static_cast<int>(extended_rcode)); + + // non-0 extended rcode + extended_rcode = 0; + ConstEDNSPtr(createEDNSFromRR(Name::ROOT_NAME(), rrclass, rrtype, + RRTTL(0x01008000), *opt_rdata, + extended_rcode)); + EXPECT_EQ(1, static_cast<int>(extended_rcode)); + + // creation triggers an exception. extended_rcode must be intact. + extended_rcode = 0; + EXPECT_THROW(createEDNSFromRR(Name::ROOT_NAME(), rrclass, rrtype, + rrttl_badver, *opt_rdata, extended_rcode), + DNSMessageBADVERS); + EXPECT_EQ(0, static_cast<int>(extended_rcode)); +} + +// test operator<<. We simply confirm it appends the result of toText(). +TEST_F(EDNSTest, LeftShiftOperator) { + ostringstream oss; + oss << edns_base; + EXPECT_EQ(edns_base.toText(), oss.str()); +} +} |