mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 22:15:23 +00:00
catch up to trunk
git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac470@4156 e5f2f494-b856-4b98-b285-d166d9295462
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
143. [build] jinmei
|
||||||
|
Fixed build problems with clang++ in unit tests due to recent
|
||||||
|
changes. No behavior change. (Trac #448, svn r4133)
|
||||||
|
|
||||||
142. [func] jinmei
|
142. [func] jinmei
|
||||||
b10-auth: updated query benchmark so that it can test in memory
|
b10-auth: updated query benchmark so that it can test in memory
|
||||||
data source. Also fixed a bug that the output buffer isn't
|
data source. Also fixed a bug that the output buffer isn't
|
||||||
|
@@ -597,6 +597,8 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/lib/Makefile
|
src/lib/Makefile
|
||||||
src/lib/asiolink/Makefile
|
src/lib/asiolink/Makefile
|
||||||
src/lib/asiolink/tests/Makefile
|
src/lib/asiolink/tests/Makefile
|
||||||
|
src/lib/asiolink/internal/Makefile
|
||||||
|
src/lib/asiolink/internal/tests/Makefile
|
||||||
src/lib/bench/Makefile
|
src/lib/bench/Makefile
|
||||||
src/lib/bench/example/Makefile
|
src/lib/bench/example/Makefile
|
||||||
src/lib/bench/tests/Makefile
|
src/lib/bench/tests/Makefile
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <dns/message.h>
|
#include <dns/message.h>
|
||||||
#include <dns/rcode.h>
|
#include <dns/rcode.h>
|
||||||
|
#include <dns/rdataclass.h>
|
||||||
|
|
||||||
#include <datasrc/memory_datasrc.h>
|
#include <datasrc/memory_datasrc.h>
|
||||||
|
|
||||||
@@ -21,10 +22,51 @@
|
|||||||
|
|
||||||
using namespace isc::dns;
|
using namespace isc::dns;
|
||||||
using namespace isc::datasrc;
|
using namespace isc::datasrc;
|
||||||
|
using namespace isc::dns::rdata;
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
namespace auth {
|
namespace auth {
|
||||||
|
|
||||||
|
void
|
||||||
|
Query::getAdditional(const isc::datasrc::Zone& zone,
|
||||||
|
const isc::dns::RRset& rrset) const
|
||||||
|
{
|
||||||
|
if (rrset.getType() == RRType::NS()) {
|
||||||
|
// Need to perform the search in the "GLUE OK" mode.
|
||||||
|
RdataIteratorPtr rdata_iterator = rrset.getRdataIterator();
|
||||||
|
for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
|
||||||
|
const Rdata& rdata(rdata_iterator->getCurrent());
|
||||||
|
const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
|
||||||
|
findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Query::findAddrs(const isc::datasrc::Zone& zone,
|
||||||
|
const isc::dns::Name& qname,
|
||||||
|
const isc::datasrc::Zone::FindOptions options) const
|
||||||
|
{
|
||||||
|
// Out of zone name
|
||||||
|
NameComparisonResult result = zone.getOrigin().compare(qname);
|
||||||
|
if ((result.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
|
||||||
|
(result.getRelation() != NameComparisonResult::EQUAL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Find A rrset
|
||||||
|
Zone::FindResult a_result = zone.find(qname, RRType::A(), options);
|
||||||
|
if (a_result.code == Zone::SUCCESS) {
|
||||||
|
response_.addRRset(Message::SECTION_ADDITIONAL,
|
||||||
|
boost::const_pointer_cast<RRset>(a_result.rrset));
|
||||||
|
}
|
||||||
|
// Find AAAA rrset
|
||||||
|
Zone::FindResult aaaa_result = zone.find(qname, RRType::AAAA(), options);
|
||||||
|
if (aaaa_result.code == Zone::SUCCESS) {
|
||||||
|
response_.addRRset(Message::SECTION_ADDITIONAL,
|
||||||
|
boost::const_pointer_cast<RRset>(aaaa_result.rrset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Query::putSOA(const Zone& zone) const {
|
Query::putSOA(const Zone& zone) const {
|
||||||
Zone::FindResult soa_result(zone.find(zone.getOrigin(),
|
Zone::FindResult soa_result(zone.find(zone.getOrigin(),
|
||||||
@@ -74,7 +116,11 @@ Query::process() const {
|
|||||||
// TODO : fill in authority and addtional sections.
|
// TODO : fill in authority and addtional sections.
|
||||||
break;
|
break;
|
||||||
case Zone::DELEGATION:
|
case Zone::DELEGATION:
|
||||||
// TODO : add NS to authority section, fill in additional section.
|
response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
|
||||||
|
response_.setRcode(Rcode::NOERROR());
|
||||||
|
response_.addRRset(Message::SECTION_AUTHORITY,
|
||||||
|
boost::const_pointer_cast<RRset>(db_result.rrset));
|
||||||
|
getAdditional(*result.zone, *db_result.rrset);
|
||||||
break;
|
break;
|
||||||
case Zone::NXDOMAIN:
|
case Zone::NXDOMAIN:
|
||||||
// Just empty answer with SOA in authority section
|
// Just empty answer with SOA in authority section
|
||||||
|
@@ -15,17 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <exceptions/exceptions.h>
|
#include <exceptions/exceptions.h>
|
||||||
|
#include <datasrc/zone.h>
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
namespace dns {
|
namespace dns {
|
||||||
class Message;
|
class Message;
|
||||||
class Name;
|
class Name;
|
||||||
class RRType;
|
class RRType;
|
||||||
|
class RRset;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace datasrc {
|
namespace datasrc {
|
||||||
class MemoryDataSrc;
|
class MemoryDataSrc;
|
||||||
class Zone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace auth {
|
namespace auth {
|
||||||
@@ -63,6 +64,48 @@ namespace auth {
|
|||||||
/// accidentally, and since it's considered a temporary development state,
|
/// accidentally, and since it's considered a temporary development state,
|
||||||
/// we keep this name at the moment.
|
/// we keep this name at the moment.
|
||||||
class Query {
|
class Query {
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// \short Adds a SOA.
|
||||||
|
///
|
||||||
|
/// Adds a SOA of the zone into the authority zone of response_.
|
||||||
|
/// Can throw NoSOA.
|
||||||
|
///
|
||||||
|
void putSOA(const isc::datasrc::Zone& zone) const;
|
||||||
|
|
||||||
|
/// Look up additional data (i.e., address records for the names included
|
||||||
|
/// in NS or MX records).
|
||||||
|
///
|
||||||
|
/// This method may throw a exception because its underlying methods may
|
||||||
|
/// throw exceptions.
|
||||||
|
///
|
||||||
|
/// \param zone The Zone wherein the additional data to the query is bo be
|
||||||
|
/// found.
|
||||||
|
/// \param rrset The RRset (i.e., NS or MX rrset) which require additional
|
||||||
|
/// processing.
|
||||||
|
void getAdditional(const isc::datasrc::Zone& zone,
|
||||||
|
const isc::dns::RRset& rrset) const;
|
||||||
|
|
||||||
|
/// Find address records for a specified name.
|
||||||
|
///
|
||||||
|
/// Search the specified zone for AAAA/A RRs of each of the NS/MX RDATA
|
||||||
|
/// (domain name), and insert the found ones into the additional section
|
||||||
|
/// if address records are available. By default the search will stop
|
||||||
|
/// once it encounters a zone cut.
|
||||||
|
///
|
||||||
|
/// Note: we need to perform the search in the "GLUE OK" mode for NS RDATA,
|
||||||
|
/// which means that we should include A/AAAA RRs under a zone cut.
|
||||||
|
/// The glue records must exactly match the name in the NS RDATA, without
|
||||||
|
/// CNAME or wildcard processing.
|
||||||
|
///
|
||||||
|
/// \param zone The Zone wherein the address records is to be found.
|
||||||
|
/// \param qname The name in rrset RDATA.
|
||||||
|
/// \param options The search options.
|
||||||
|
void findAddrs(const isc::datasrc::Zone& zone,
|
||||||
|
const isc::dns::Name& qname,
|
||||||
|
const isc::datasrc::Zone::FindOptions options
|
||||||
|
= isc::datasrc::Zone::FIND_DEFAULT) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor from query parameters.
|
/// Constructor from query parameters.
|
||||||
///
|
///
|
||||||
@@ -135,14 +178,6 @@ private:
|
|||||||
const isc::dns::Name& qname_;
|
const isc::dns::Name& qname_;
|
||||||
const isc::dns::RRType& qtype_;
|
const isc::dns::RRType& qtype_;
|
||||||
isc::dns::Message& response_;
|
isc::dns::Message& response_;
|
||||||
|
|
||||||
/**
|
|
||||||
* \short Adds a SOA.
|
|
||||||
*
|
|
||||||
* Adds a SOA of the zone into the authority zone of response_.
|
|
||||||
* Can throw NoSOA.
|
|
||||||
*/
|
|
||||||
void putSOA(const isc::datasrc::Zone& zone) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
|||||||
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||||
run_unittests_LDADD = $(GTEST_LDADD)
|
run_unittests_LDADD = $(GTEST_LDADD)
|
||||||
run_unittests_LDADD += $(SQLITE_LIBS)
|
run_unittests_LDADD += $(SQLITE_LIBS)
|
||||||
|
run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
|
||||||
run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
|
run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
|
||||||
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
|
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
|
||||||
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
|
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
|
||||||
|
@@ -30,15 +30,19 @@
|
|||||||
|
|
||||||
#include <datasrc/memory_datasrc.h>
|
#include <datasrc/memory_datasrc.h>
|
||||||
#include <auth/auth_srv.h>
|
#include <auth/auth_srv.h>
|
||||||
#include <testutils/srv_unittest.h>
|
|
||||||
#include <auth/statistics.h>
|
#include <auth/statistics.h>
|
||||||
|
|
||||||
|
#include <dns/tests/unittest_util.h>
|
||||||
|
#include <testutils/srv_test.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
using namespace isc::cc;
|
using namespace isc::cc;
|
||||||
using namespace isc::dns;
|
using namespace isc::dns;
|
||||||
using namespace isc::dns::rdata;
|
using namespace isc::dns::rdata;
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
using namespace isc::xfr;
|
using namespace isc::xfr;
|
||||||
using namespace asiolink;
|
using namespace asiolink;
|
||||||
|
using namespace isc::testutils;
|
||||||
using isc::UnitTestUtil;
|
using isc::UnitTestUtil;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -55,6 +59,10 @@ protected:
|
|||||||
server.setXfrinSession(¬ify_session);
|
server.setXfrinSession(¬ify_session);
|
||||||
server.setStatisticsSession(&statistics_session);
|
server.setStatisticsSession(&statistics_session);
|
||||||
}
|
}
|
||||||
|
virtual void processMessage() {
|
||||||
|
server.processMessage(*io_message, parse_message, response_obuffer,
|
||||||
|
&dnsserv);
|
||||||
|
}
|
||||||
MockSession statistics_session;
|
MockSession statistics_session;
|
||||||
MockXfroutClient xfrout;
|
MockXfroutClient xfrout;
|
||||||
AuthSrv server;
|
AuthSrv server;
|
||||||
@@ -159,48 +167,52 @@ TEST_F(AuthSrvTest, iqueryViaDNSServer) {
|
|||||||
|
|
||||||
// Unsupported requests. Should result in NOTIMP.
|
// Unsupported requests. Should result in NOTIMP.
|
||||||
TEST_F(AuthSrvTest, unsupportedRequest) {
|
TEST_F(AuthSrvTest, unsupportedRequest) {
|
||||||
UNSUPPORTED_REQUEST_TEST;
|
unsupportedRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple API check
|
// Simple API check
|
||||||
TEST_F(AuthSrvTest, verbose) {
|
TEST_F(AuthSrvTest, verbose) {
|
||||||
VERBOSE_TEST;
|
EXPECT_FALSE(server.getVerbose());
|
||||||
|
server.setVerbose(true);
|
||||||
|
EXPECT_TRUE(server.getVerbose());
|
||||||
|
server.setVerbose(false);
|
||||||
|
EXPECT_FALSE(server.getVerbose());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiple questions. Should result in FORMERR.
|
// Multiple questions. Should result in FORMERR.
|
||||||
TEST_F(AuthSrvTest, multiQuestion) {
|
TEST_F(AuthSrvTest, multiQuestion) {
|
||||||
MULTI_QUESTION_TEST;
|
multiQuestion();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incoming data doesn't even contain the complete header. Must be silently
|
// Incoming data doesn't even contain the complete header. Must be silently
|
||||||
// dropped.
|
// dropped.
|
||||||
TEST_F(AuthSrvTest, shortMessage) {
|
TEST_F(AuthSrvTest, shortMessage) {
|
||||||
SHORT_MESSAGE_TEST;
|
shortMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response messages. Must be silently dropped, whether it's a valid response
|
// Response messages. Must be silently dropped, whether it's a valid response
|
||||||
// or malformed or could otherwise cause a protocol error.
|
// or malformed or could otherwise cause a protocol error.
|
||||||
TEST_F(AuthSrvTest, response) {
|
TEST_F(AuthSrvTest, response) {
|
||||||
RESPONSE_TEST;
|
response();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query with a broken question
|
// Query with a broken question
|
||||||
TEST_F(AuthSrvTest, shortQuestion) {
|
TEST_F(AuthSrvTest, shortQuestion) {
|
||||||
SHORT_QUESTION_TEST;
|
shortQuestion();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query with a broken answer section
|
// Query with a broken answer section
|
||||||
TEST_F(AuthSrvTest, shortAnswer) {
|
TEST_F(AuthSrvTest, shortAnswer) {
|
||||||
SHORT_ANSWER_TEST;
|
shortAnswer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query with unsupported version of EDNS.
|
// Query with unsupported version of EDNS.
|
||||||
TEST_F(AuthSrvTest, ednsBadVers) {
|
TEST_F(AuthSrvTest, ednsBadVers) {
|
||||||
EDNS_BADVERS_TEST;
|
ednsBadVers();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AuthSrvTest, AXFROverUDP) {
|
TEST_F(AuthSrvTest, AXFROverUDP) {
|
||||||
AXFR_OVER_UDP_TEST;
|
axfrOverUDP();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AuthSrvTest, AXFRSuccess) {
|
TEST_F(AuthSrvTest, AXFRSuccess) {
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include <dns/rcode.h>
|
#include <dns/rcode.h>
|
||||||
#include <dns/rrttl.h>
|
#include <dns/rrttl.h>
|
||||||
#include <dns/rrtype.h>
|
#include <dns/rrtype.h>
|
||||||
|
#include <dns/rdataclass.h>
|
||||||
|
|
||||||
#include <datasrc/memory_datasrc.h>
|
#include <datasrc/memory_datasrc.h>
|
||||||
|
|
||||||
@@ -36,19 +37,48 @@ RRsetPtr a_rrset = RRsetPtr(new RRset(Name("www.example.com"),
|
|||||||
RRsetPtr soa_rrset = RRsetPtr(new RRset(Name("example.com"),
|
RRsetPtr soa_rrset = RRsetPtr(new RRset(Name("example.com"),
|
||||||
RRClass::IN(), RRType::SOA(),
|
RRClass::IN(), RRType::SOA(),
|
||||||
RRTTL(3600)));
|
RRTTL(3600)));
|
||||||
|
RRsetPtr ns_rrset(RRsetPtr(new RRset(Name("ns.example.com"),
|
||||||
|
RRClass::IN(), RRType::NS(),
|
||||||
|
RRTTL(3600))));
|
||||||
|
RRsetPtr glue_a_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
|
||||||
|
RRClass::IN(), RRType::A(),
|
||||||
|
RRTTL(3600))));
|
||||||
|
RRsetPtr glue_aaaa_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
|
||||||
|
RRClass::IN(), RRType::AAAA(),
|
||||||
|
RRTTL(3600))));
|
||||||
|
RRsetPtr noglue_a_rrset(RRsetPtr(new RRset(Name("noglue.example.com"),
|
||||||
|
RRClass::IN(), RRType::A(),
|
||||||
|
RRTTL(3600))));
|
||||||
// This is a mock Zone class for testing.
|
// This is a mock Zone class for testing.
|
||||||
// It is a derived class of Zone, and simply hardcode the results of find()
|
// It is a derived class of Zone, and simply hardcode the results of find()
|
||||||
// return SUCCESS for "www.example.com",
|
// return SUCCESS for "www.example.com",
|
||||||
// return NXDOMAIN for "nxdomain.example.com",
|
// return NXDOMAIN for "nxdomain.example.com",
|
||||||
// return NXRRSET for "nxrrset.example.com",
|
// return NXRRSET for "nxrrset.example.com",
|
||||||
// return CNAME for "cname.example.com",
|
// return CNAME for "cname.example.com",
|
||||||
// else return DNAME
|
// otherwise return DNAME
|
||||||
class MockZone : public Zone {
|
class MockZone : public Zone {
|
||||||
public:
|
public:
|
||||||
MockZone(bool has_SOA = true) :
|
MockZone(bool has_SOA = true) :
|
||||||
origin_(Name("example.com")),
|
origin_(Name("example.com")),
|
||||||
has_SOA_(has_SOA)
|
has_SOA_(has_SOA),
|
||||||
{}
|
delegation_rrset(RRsetPtr(new RRset(Name("delegation.example.com"),
|
||||||
|
RRClass::IN(), RRType::NS(),
|
||||||
|
RRTTL(3600)))),
|
||||||
|
cname_rrset(RRsetPtr(new RRset(Name("cname.example.com"),
|
||||||
|
RRClass::IN(), RRType::CNAME(),
|
||||||
|
RRTTL(3600))))
|
||||||
|
{
|
||||||
|
delegation_rrset->addRdata(rdata::generic::NS(
|
||||||
|
Name("glue.ns.example.com")));
|
||||||
|
delegation_rrset->addRdata(rdata::generic::NS(
|
||||||
|
Name("noglue.example.com")));
|
||||||
|
delegation_rrset->addRdata(rdata::generic::NS(
|
||||||
|
Name("cname.example.com")));
|
||||||
|
delegation_rrset->addRdata(rdata::generic::NS(
|
||||||
|
Name("example.org")));
|
||||||
|
cname_rrset->addRdata(rdata::generic::CNAME(
|
||||||
|
Name("www.example.com")));
|
||||||
|
}
|
||||||
virtual const isc::dns::Name& getOrigin() const;
|
virtual const isc::dns::Name& getOrigin() const;
|
||||||
virtual const isc::dns::RRClass& getClass() const;
|
virtual const isc::dns::RRClass& getClass() const;
|
||||||
|
|
||||||
@@ -59,6 +89,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
Name origin_;
|
Name origin_;
|
||||||
bool has_SOA_;
|
bool has_SOA_;
|
||||||
|
RRsetPtr delegation_rrset;
|
||||||
|
RRsetPtr cname_rrset;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Name&
|
const Name&
|
||||||
@@ -72,22 +104,34 @@ MockZone::getClass() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Zone::FindResult
|
Zone::FindResult
|
||||||
MockZone::find(const Name& name, const RRType& type, const FindOptions) const {
|
MockZone::find(const Name& name, const RRType& type,
|
||||||
|
const FindOptions options) const
|
||||||
|
{
|
||||||
// hardcode the find results
|
// hardcode the find results
|
||||||
if (name == Name("www.example.com")) {
|
if (name == Name("www.example.com")) {
|
||||||
return (FindResult(SUCCESS, a_rrset));
|
return (FindResult(SUCCESS, a_rrset));
|
||||||
|
} else if (name == Name("glue.ns.example.com") && type == RRType::A() &&
|
||||||
|
options == FIND_GLUE_OK) {
|
||||||
|
return (FindResult(SUCCESS, glue_a_rrset));
|
||||||
|
} else if (name == Name("noglue.example.com") && type == RRType::A()) {
|
||||||
|
return (FindResult(SUCCESS, noglue_a_rrset));
|
||||||
|
} else if (name == Name("glue.ns.example.com") && type == RRType::AAAA() &&
|
||||||
|
options == FIND_GLUE_OK) {
|
||||||
|
return (FindResult(SUCCESS, glue_aaaa_rrset));
|
||||||
} else if (name == Name("example.com") && type == RRType::SOA() &&
|
} else if (name == Name("example.com") && type == RRType::SOA() &&
|
||||||
has_SOA_)
|
has_SOA_)
|
||||||
{
|
{
|
||||||
return (FindResult(SUCCESS, soa_rrset));
|
return (FindResult(SUCCESS, soa_rrset));
|
||||||
} else if (name == Name("delegation.example.com")) {
|
} else if (name == Name("delegation.example.com")) {
|
||||||
return (FindResult(DELEGATION, RRsetPtr()));
|
return (FindResult(DELEGATION, delegation_rrset));
|
||||||
|
} else if (name == Name("ns.example.com")) {
|
||||||
|
return (FindResult(DELEGATION, ns_rrset));
|
||||||
} else if (name == Name("nxdomain.example.com")) {
|
} else if (name == Name("nxdomain.example.com")) {
|
||||||
return (FindResult(NXDOMAIN, RRsetPtr()));
|
return (FindResult(NXDOMAIN, RRsetPtr()));
|
||||||
} else if (name == Name("nxrrset.example.com")) {
|
} else if (name == Name("nxrrset.example.com")) {
|
||||||
return (FindResult(NXRRSET, RRsetPtr()));
|
return (FindResult(NXRRSET, RRsetPtr()));
|
||||||
} else if (name == Name("cname.example.com")) {
|
} else if ((name == Name("cname.example.com"))) {
|
||||||
return (FindResult(CNAME, RRsetPtr()));
|
return (FindResult(CNAME, cname_rrset));
|
||||||
} else {
|
} else {
|
||||||
return (FindResult(DNAME, RRsetPtr()));
|
return (FindResult(DNAME, RRsetPtr()));
|
||||||
}
|
}
|
||||||
@@ -121,11 +165,41 @@ TEST_F(QueryTest, matchZone) {
|
|||||||
// add a matching zone.
|
// add a matching zone.
|
||||||
memory_datasrc.addZone(ZonePtr(new MockZone()));
|
memory_datasrc.addZone(ZonePtr(new MockZone()));
|
||||||
query.process();
|
query.process();
|
||||||
|
EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
|
||||||
EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
|
EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
|
||||||
EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
|
EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
|
||||||
Name("www.example.com"), RRClass::IN(),
|
Name("www.example.com"), RRClass::IN(),
|
||||||
RRType::A()));
|
RRType::A()));
|
||||||
|
|
||||||
|
// Delegation
|
||||||
|
const Name delegation_name(Name("delegation.example.com"));
|
||||||
|
Query delegation_query(memory_datasrc, delegation_name, qtype, response);
|
||||||
|
delegation_query.process();
|
||||||
|
EXPECT_FALSE(response.getHeaderFlag(Message::HEADERFLAG_AA));
|
||||||
|
EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
|
||||||
|
EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
|
||||||
|
Name("delegation.example.com"),
|
||||||
|
RRClass::IN(), RRType::NS()));
|
||||||
|
// glue address records
|
||||||
|
EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
|
||||||
|
Name("glue.ns.example.com"),
|
||||||
|
RRClass::IN(), RRType::A()));
|
||||||
|
EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
|
||||||
|
Name("glue.ns.example.com"),
|
||||||
|
RRClass::IN(), RRType::AAAA()));
|
||||||
|
// noglue address records
|
||||||
|
EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
|
||||||
|
Name("noglue.example.com"),
|
||||||
|
RRClass::IN(), RRType::A()));
|
||||||
|
// NS name has a CNAME
|
||||||
|
EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
|
||||||
|
Name("www.example.com"),
|
||||||
|
RRClass::IN(), RRType::A()));
|
||||||
|
// NS name is out of zone
|
||||||
|
EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
|
||||||
|
Name("example.org"),
|
||||||
|
RRClass::IN(), RRType::A()));
|
||||||
|
|
||||||
// NXDOMAIN
|
// NXDOMAIN
|
||||||
const Name nxdomain_name(Name("nxdomain.example.com"));
|
const Name nxdomain_name(Name("nxdomain.example.com"));
|
||||||
Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
|
Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = . tests
|
SUBDIRS = . tests internal
|
||||||
|
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
||||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||||
|
1
src/lib/asiolink/internal/Makefile.am
Normal file
1
src/lib/asiolink/internal/Makefile.am
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = tests
|
37
src/lib/asiolink/internal/tests/Makefile.am
Normal file
37
src/lib/asiolink/internal/tests/Makefile.am
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
||||||
|
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||||
|
|
||||||
|
AM_CXXFLAGS = $(B10_CXXFLAGS)
|
||||||
|
|
||||||
|
if USE_STATIC_LINK
|
||||||
|
AM_LDFLAGS = -static
|
||||||
|
endif
|
||||||
|
|
||||||
|
CLEANFILES = *.gcno *.gcda
|
||||||
|
|
||||||
|
TESTS =
|
||||||
|
if HAVE_GTEST
|
||||||
|
TESTS += run_unittests
|
||||||
|
run_unittests_SOURCES = udpdns_unittest.cc
|
||||||
|
run_unittests_SOURCES += run_unittests.cc
|
||||||
|
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||||
|
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||||
|
run_unittests_LDADD = $(GTEST_LDADD)
|
||||||
|
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
|
||||||
|
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
|
||||||
|
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
|
||||||
|
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
|
||||||
|
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
|
||||||
|
# B10_CXXFLAGS)
|
||||||
|
run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
|
||||||
|
if USE_GXX
|
||||||
|
run_unittests_CXXFLAGS += -Wno-unused-parameter
|
||||||
|
endif
|
||||||
|
if USE_CLANGPP
|
||||||
|
# We need to disable -Werror for any test that uses internal definitions of
|
||||||
|
# ASIO when using clang++
|
||||||
|
run_unittests_CXXFLAGS += -Wno-error
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
noinst_PROGRAMS = $(TESTS)
|
21
src/lib/asiolink/internal/tests/run_unittests.cc
Normal file
21
src/lib/asiolink/internal/tests/run_unittests.cc
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// 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 <gtest/gtest.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[]) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return (RUN_ALL_TESTS());
|
||||||
|
}
|
@@ -18,7 +18,6 @@ TESTS += run_unittests
|
|||||||
run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
|
run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
|
||||||
run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
|
run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
|
||||||
run_unittests_SOURCES += asiolink_unittest.cc
|
run_unittests_SOURCES += asiolink_unittest.cc
|
||||||
run_unittests_SOURCES += udpdns_unittest.cc
|
|
||||||
run_unittests_SOURCES += run_unittests.cc
|
run_unittests_SOURCES += run_unittests.cc
|
||||||
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||||
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||||
|
@@ -17,6 +17,9 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
@@ -32,19 +35,21 @@
|
|||||||
#include <dns/buffer.h>
|
#include <dns/buffer.h>
|
||||||
#include <dns/message.h>
|
#include <dns/message.h>
|
||||||
|
|
||||||
|
// IMPORTANT: We shouldn't directly use ASIO definitions in this test.
|
||||||
|
// In particular, we must not include asio.hpp in this file.
|
||||||
|
// The asiolink module is primarily intended to be a wrapper that hide the
|
||||||
|
// details of the underlying implementations. We need to test the wrapper
|
||||||
|
// level behaviors. In addition, some compilers reject to compile this file
|
||||||
|
// if we include asio.hpp unless we specify a special compiler option.
|
||||||
|
// If we need to test something at the level of underlying ASIO and need
|
||||||
|
// their definition, that test should go to asiolink/internal/tests.
|
||||||
#include <asiolink/asiolink.h>
|
#include <asiolink/asiolink.h>
|
||||||
#include <asiolink/iosocket.h>
|
#include <asiolink/iosocket.h>
|
||||||
#include <asiolink/internal/tcpdns.h>
|
|
||||||
#include <asiolink/internal/udpdns.h>
|
|
||||||
|
|
||||||
#include <asio.hpp>
|
|
||||||
|
|
||||||
using isc::UnitTestUtil;
|
using isc::UnitTestUtil;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace asiolink;
|
using namespace asiolink;
|
||||||
using namespace isc::dns;
|
using namespace isc::dns;
|
||||||
using namespace asio;
|
|
||||||
using asio::ip::udp;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char* const TEST_SERVER_PORT = "53535";
|
const char* const TEST_SERVER_PORT = "53535";
|
||||||
@@ -330,10 +335,30 @@ protected:
|
|||||||
// ... and this one will block until the send has completed
|
// ... and this one will block until the send has completed
|
||||||
io_service_->run_one();
|
io_service_->run_one();
|
||||||
|
|
||||||
// Now we attempt to recv() whatever was sent
|
// Now we attempt to recv() whatever was sent.
|
||||||
const int ret = recv(sock_, buffer, size, MSG_DONTWAIT);
|
// XXX: there's no guarantee the receiving socket can immediately get
|
||||||
|
// the packet. Normally we can perform blocking recv to wait for it,
|
||||||
|
// but in theory it's even possible that the packet is lost.
|
||||||
|
// In order to prevent the test from hanging in such a worst case
|
||||||
|
// we add an ad hoc timeout.
|
||||||
|
const struct timeval timeo = { 10, 0 };
|
||||||
|
int recv_options = 0;
|
||||||
|
if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo,
|
||||||
|
sizeof(timeo))) {
|
||||||
|
if (errno == ENOPROTOOPT) {
|
||||||
|
// Workaround for Solaris: it doesn't accept SO_RCVTIMEO
|
||||||
|
// with the error of ENOPROTOOPT. Since this is a workaround
|
||||||
|
// for rare error cases anyway, we simply switch to the
|
||||||
|
// "don't wait" mode. If we still find an error in recv()
|
||||||
|
// can happen often we'll consider a more complete solution.
|
||||||
|
recv_options = MSG_DONTWAIT;
|
||||||
|
} else {
|
||||||
|
isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int ret = recv(sock_, buffer, size, recv_options);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
isc_throw(IOError, "recvfrom failed");
|
isc_throw(IOError, "recvfrom failed: " << strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass the message size back via the size parameter
|
// Pass the message size back via the size parameter
|
||||||
@@ -411,8 +436,7 @@ protected:
|
|||||||
// has completed.
|
// has completed.
|
||||||
class MockServer : public DNSServer {
|
class MockServer : public DNSServer {
|
||||||
public:
|
public:
|
||||||
explicit MockServer(asio::io_service& io_service,
|
explicit MockServer(IOService& io_service,
|
||||||
const asio::ip::address& addr, const uint16_t port,
|
|
||||||
SimpleCallback* checkin = NULL,
|
SimpleCallback* checkin = NULL,
|
||||||
DNSLookup* lookup = NULL,
|
DNSLookup* lookup = NULL,
|
||||||
DNSAnswer* answer = NULL) :
|
DNSAnswer* answer = NULL) :
|
||||||
@@ -426,9 +450,7 @@ protected:
|
|||||||
size_t length = 0)
|
size_t length = 0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void resume(const bool done) {
|
void resume(const bool) { // in our test this shouldn't be called
|
||||||
done_ = done;
|
|
||||||
io_.post(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DNSServer* clone() {
|
DNSServer* clone() {
|
||||||
@@ -443,7 +465,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
asio::io_service& io_;
|
IOService& io_;
|
||||||
bool done_;
|
bool done_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -462,8 +484,8 @@ protected:
|
|||||||
// This version of mock server just stops the io_service when it is resumed
|
// This version of mock server just stops the io_service when it is resumed
|
||||||
class MockServerStop : public MockServer {
|
class MockServerStop : public MockServer {
|
||||||
public:
|
public:
|
||||||
explicit MockServerStop(asio::io_service& io_service, bool* done) :
|
explicit MockServerStop(IOService& io_service, bool* done) :
|
||||||
MockServer(io_service, asio::ip::address(), 0),
|
MockServer(io_service),
|
||||||
done_(done)
|
done_(done)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -511,7 +533,6 @@ protected:
|
|||||||
string callback_address_;
|
string callback_address_;
|
||||||
vector<uint8_t> callback_data_;
|
vector<uint8_t> callback_data_;
|
||||||
int sock_;
|
int sock_;
|
||||||
private:
|
|
||||||
struct addrinfo* res_;
|
struct addrinfo* res_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -640,14 +661,12 @@ TEST_F(ASIOLinkTest, recursiveSetupV6) {
|
|||||||
// full code coverage including error cases.
|
// full code coverage including error cases.
|
||||||
TEST_F(ASIOLinkTest, recursiveSend) {
|
TEST_F(ASIOLinkTest, recursiveSend) {
|
||||||
setDNSService(true, false);
|
setDNSService(true, false);
|
||||||
asio::io_service& io = io_service_->get_io_service();
|
|
||||||
|
|
||||||
// Note: We use the test prot plus one to ensure we aren't binding
|
// Note: We use the test prot plus one to ensure we aren't binding
|
||||||
// to the same port as the actual server
|
// to the same port as the actual server
|
||||||
uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
|
uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
|
||||||
asio::ip::address addr = asio::ip::address::from_string(TEST_IPV4_ADDR);
|
|
||||||
|
|
||||||
MockServer server(io, addr, port, NULL, NULL, NULL);
|
MockServer server(*io_service_);
|
||||||
RecursiveQuery rq(*dns_service_, singleAddress(TEST_IPV4_ADDR, port));
|
RecursiveQuery rq(*dns_service_, singleAddress(TEST_IPV4_ADDR, port));
|
||||||
|
|
||||||
Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
|
Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
|
||||||
@@ -656,7 +675,7 @@ TEST_F(ASIOLinkTest, recursiveSend) {
|
|||||||
|
|
||||||
char data[4096];
|
char data[4096];
|
||||||
size_t size = sizeof(data);
|
size_t size = sizeof(data);
|
||||||
EXPECT_NO_THROW(recvUDP(AF_INET, data, size));
|
ASSERT_NO_THROW(recvUDP(AF_INET, data, size));
|
||||||
|
|
||||||
Message m(Message::PARSE);
|
Message m(Message::PARSE);
|
||||||
InputBuffer ibuf(data, size);
|
InputBuffer ibuf(data, size);
|
||||||
@@ -672,34 +691,27 @@ TEST_F(ASIOLinkTest, recursiveSend) {
|
|||||||
EXPECT_EQ(q.getClass(), q2->getClass());
|
EXPECT_EQ(q.getClass(), q2->getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
receive_and_inc(udp::socket* socket, int* num) {
|
|
||||||
(*num) ++;
|
|
||||||
static char inbuff[512];
|
|
||||||
socket->async_receive(asio::buffer(inbuff, 512),
|
|
||||||
boost::bind(receive_and_inc, socket, num));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test it tries the correct amount of times before giving up
|
// Test it tries the correct amount of times before giving up
|
||||||
TEST_F(ASIOLinkTest, recursiveTimeout) {
|
TEST_F(ASIOLinkTest, recursiveTimeout) {
|
||||||
// Prepare the service (we do not use the common setup, we do not answer
|
// Prepare the service (we do not use the common setup, we do not answer
|
||||||
setDNSService();
|
setDNSService();
|
||||||
asio::io_service& service = io_service_->get_io_service();
|
|
||||||
|
|
||||||
// Prepare the socket
|
// Prepare the socket
|
||||||
uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
|
res_ = resolveAddress(AF_INET, IPPROTO_UDP, true);
|
||||||
udp::socket socket(service, udp::v4());
|
sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
|
||||||
socket.set_option(socket_base::reuse_address(true));
|
if (sock_ < 0) {
|
||||||
socket.bind(udp::endpoint(ip::address::from_string(TEST_IPV4_ADDR), port));
|
isc_throw(IOError, "failed to open test socket");
|
||||||
// And count the answers
|
}
|
||||||
int num = -1; // One is counted before the receipt of the first one
|
if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
|
||||||
receive_and_inc(&socket, &num);
|
isc_throw(IOError, "failed to bind test socket");
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare the server
|
// Prepare the server
|
||||||
bool done(true);
|
bool done(true);
|
||||||
MockServerStop server(service, &done);
|
MockServerStop server(*io_service_, &done);
|
||||||
|
|
||||||
// Do the answer
|
// Do the answer
|
||||||
|
const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
|
||||||
RecursiveQuery query(*dns_service_, singleAddress(TEST_IPV4_ADDR, port),
|
RecursiveQuery query(*dns_service_, singleAddress(TEST_IPV4_ADDR, port),
|
||||||
10, 2);
|
10, 2);
|
||||||
Question question(Name("example.net"), RRClass::IN(), RRType::A());
|
Question question(Name("example.net"), RRClass::IN(), RRType::A());
|
||||||
@@ -707,7 +719,27 @@ TEST_F(ASIOLinkTest, recursiveTimeout) {
|
|||||||
query.sendQuery(question, buffer, &server);
|
query.sendQuery(question, buffer, &server);
|
||||||
|
|
||||||
// Run the test
|
// Run the test
|
||||||
service.run();
|
io_service_->run();
|
||||||
|
|
||||||
|
// Read up to 3 packets. Use some ad hoc timeout to prevent an infinite
|
||||||
|
// block (see also recvUDP()).
|
||||||
|
const struct timeval timeo = { 10, 0 };
|
||||||
|
int recv_options = 0;
|
||||||
|
if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
|
||||||
|
if (errno == ENOPROTOOPT) { // see ASIOLinkTest::recvUDP()
|
||||||
|
recv_options = MSG_DONTWAIT;
|
||||||
|
} else {
|
||||||
|
isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int num = 0;
|
||||||
|
do {
|
||||||
|
char inbuff[512];
|
||||||
|
if (recv(sock_, inbuff, sizeof(inbuff), recv_options) < 0) {
|
||||||
|
num = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (++num < 3);
|
||||||
|
|
||||||
// The query should fail
|
// The query should fail
|
||||||
EXPECT_FALSE(done);
|
EXPECT_FALSE(done);
|
||||||
|
@@ -81,7 +81,7 @@ class HotCacheImpl;
|
|||||||
/// from the tail of the list. This operation is not locked. BIND 10
|
/// from the tail of the list. This operation is not locked. BIND 10
|
||||||
/// does not currently use threads, but if it ever does (or if libdatasrc
|
/// does not currently use threads, but if it ever does (or if libdatasrc
|
||||||
/// is ever used by a threaded application), this will need to be
|
/// is ever used by a threaded application), this will need to be
|
||||||
//revisited.
|
/// revisited.
|
||||||
class HotCache {
|
class HotCache {
|
||||||
private:
|
private:
|
||||||
/// \name Static definitions
|
/// \name Static definitions
|
||||||
@@ -164,7 +164,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// Retrieves a record from the cache matching the given
|
/// Retrieves a record from the cache matching the given
|
||||||
/// query-tuple. Returns true if one is found. If it is a
|
/// query-tuple. Returns true if one is found. If it is a
|
||||||
/// posiitve cache entry, then 'rrset' is set to the cached
|
/// positive cache entry, then 'rrset' is set to the cached
|
||||||
/// RRset. For both positive and negative cache entries, 'flags'
|
/// RRset. For both positive and negative cache entries, 'flags'
|
||||||
/// is set to the query response flags. The cache entry is
|
/// is set to the query response flags. The cache entry is
|
||||||
/// then promoted to the head of the LRU queue. (NOTE: Because
|
/// then promoted to the head of the LRU queue. (NOTE: Because
|
||||||
|
@@ -103,14 +103,14 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
|
|||||||
new QueryTask(q, ns.getNSName(),
|
new QueryTask(q, ns.getNSName(),
|
||||||
Message::SECTION_ADDITIONAL,
|
Message::SECTION_ADDITIONAL,
|
||||||
QueryTask::GLUE_QUERY,
|
QueryTask::GLUE_QUERY,
|
||||||
QueryTask::GETADDITIONAL)));
|
QueryTask::GETADDITIONAL)));
|
||||||
} else if (rrset->getType() == RRType::MX()) {
|
} else if (rrset->getType() == RRType::MX()) {
|
||||||
const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
|
const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
|
||||||
q.tasks().push(QueryTaskPtr(
|
q.tasks().push(QueryTaskPtr(
|
||||||
new QueryTask(q, mx.getMXName(),
|
new QueryTask(q, mx.getMXName(),
|
||||||
Message::SECTION_ADDITIONAL,
|
Message::SECTION_ADDITIONAL,
|
||||||
QueryTask::NOGLUE_QUERY,
|
QueryTask::NOGLUE_QUERY,
|
||||||
QueryTask::GETADDITIONAL)));
|
QueryTask::GETADDITIONAL)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -672,7 +672,7 @@ void
|
|||||||
RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
|
RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
|
||||||
using namespace helper;
|
using namespace helper;
|
||||||
const isc::dns::Name sub_name = node.name_ - base_name;
|
const isc::dns::Name sub_name = node.name_ - base_name;
|
||||||
// using auto_ptr here is to avoid memory leak in case of exceptoin raised
|
// using auto_ptr here is to avoid memory leak in case of exception raised
|
||||||
// after the RBNode creation
|
// after the RBNode creation
|
||||||
std::auto_ptr<RBNode<T> > down_node(new RBNode<T>(sub_name));
|
std::auto_ptr<RBNode<T> > down_node(new RBNode<T>(sub_name));
|
||||||
std::swap(node.data_, down_node->data_);
|
std::swap(node.data_, down_node->data_);
|
||||||
@@ -680,7 +680,7 @@ RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
|
|||||||
down_node->down_ = node.down_;
|
down_node->down_ = node.down_;
|
||||||
node.name_ = base_name;
|
node.name_ = base_name;
|
||||||
node.down_ = down_node.get();
|
node.down_ = down_node.get();
|
||||||
//root node of sub tree, the initial color is BLACK
|
// root node of sub tree, the initial color is BLACK
|
||||||
down_node->color_ = RBNode<T>::BLACK;
|
down_node->color_ = RBNode<T>::BLACK;
|
||||||
++node_count_;
|
++node_count_;
|
||||||
down_node.release();
|
down_node.release();
|
||||||
|
@@ -1,5 +1,13 @@
|
|||||||
SUBDIRS = testdata
|
SUBDIRS = . testdata
|
||||||
|
|
||||||
EXTRA_DIST = srv_test.h
|
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
||||||
EXTRA_DIST += srv_unittest.h
|
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||||
EXTRA_DIST += mockups.h
|
AM_CXXFLAGS=$(B10_CXXFLAGS)
|
||||||
|
|
||||||
|
if HAVE_GTEST
|
||||||
|
lib_LTLIBRARIES = libtestutils.la
|
||||||
|
|
||||||
|
libtestutils_la_SOURCES = srv_test.h srv_test.cc
|
||||||
|
libtestutils_la_SOURCES += mockups.h
|
||||||
|
libtestutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||||
|
endif
|
||||||
|
@@ -1,4 +1,2 @@
|
|||||||
Here is some code used by more than one test. No code is used for bind10
|
Here is some code used by more than one test. No code is used for bind10
|
||||||
itself, only for testing.
|
itself, only for testing.
|
||||||
|
|
||||||
As it contains headers only currently, it does not compile here.
|
|
||||||
|
272
src/lib/testutils/srv_test.cc
Normal file
272
src/lib/testutils/srv_test.cc
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
// 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 <netinet/in.h>
|
||||||
|
|
||||||
|
#include <dns/message.h>
|
||||||
|
#include <dns/rcode.h>
|
||||||
|
|
||||||
|
#include <asiolink/asiolink.h>
|
||||||
|
|
||||||
|
#include <dns/tests/unittest_util.h>
|
||||||
|
|
||||||
|
#include <testutils/srv_test.h>
|
||||||
|
|
||||||
|
using namespace isc::dns;
|
||||||
|
using namespace asiolink;
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace testutils {
|
||||||
|
const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
|
||||||
|
|
||||||
|
const unsigned int QR_FLAG = 0x1;
|
||||||
|
const unsigned int AA_FLAG = 0x2;
|
||||||
|
const unsigned int TC_FLAG = 0x4;
|
||||||
|
const unsigned int RD_FLAG = 0x8;
|
||||||
|
const unsigned int RA_FLAG = 0x10;
|
||||||
|
const unsigned int AD_FLAG = 0x20;
|
||||||
|
const unsigned int CD_FLAG = 0x40;
|
||||||
|
|
||||||
|
SrvTestBase::SrvTestBase() : request_message(Message::RENDER),
|
||||||
|
parse_message(new Message(Message::PARSE)),
|
||||||
|
default_qid(0x1035),
|
||||||
|
opcode(Opcode(Opcode::QUERY())),
|
||||||
|
qname("www.example.com"),
|
||||||
|
qclass(RRClass::IN()),
|
||||||
|
qtype(RRType::A()), io_sock(NULL),
|
||||||
|
io_message(NULL), endpoint(NULL),
|
||||||
|
request_obuffer(0),
|
||||||
|
request_renderer(request_obuffer),
|
||||||
|
response_obuffer(new OutputBuffer(0))
|
||||||
|
{}
|
||||||
|
|
||||||
|
SrvTestBase::~SrvTestBase() {
|
||||||
|
delete io_message;
|
||||||
|
delete endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SrvTestBase::createDataFromFile(const char* const datafile,
|
||||||
|
const int protocol)
|
||||||
|
{
|
||||||
|
delete io_message;
|
||||||
|
data.clear();
|
||||||
|
|
||||||
|
delete endpoint;
|
||||||
|
|
||||||
|
endpoint = IOEndpoint::create(protocol,
|
||||||
|
IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
|
||||||
|
UnitTestUtil::readWireData(datafile, data);
|
||||||
|
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
|
||||||
|
&IOSocket::getDummyTCPSocket();
|
||||||
|
io_message = new IOMessage(&data[0], data.size(), *io_sock, *endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SrvTestBase::createRequestPacket(Message& message,
|
||||||
|
const int protocol)
|
||||||
|
{
|
||||||
|
message.toWire(request_renderer);
|
||||||
|
|
||||||
|
delete io_message;
|
||||||
|
|
||||||
|
endpoint = IOEndpoint::create(protocol,
|
||||||
|
IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
|
||||||
|
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
|
||||||
|
&IOSocket::getDummyTCPSocket();
|
||||||
|
io_message = new IOMessage(request_renderer.getData(),
|
||||||
|
request_renderer.getLength(),
|
||||||
|
*io_sock, *endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsupported requests. Should result in NOTIMP.
|
||||||
|
void
|
||||||
|
SrvTestBase::unsupportedRequest() {
|
||||||
|
for (unsigned int i = 0; i < 16; ++i) {
|
||||||
|
// set Opcode to 'i', which iterators over all possible codes except
|
||||||
|
// the standard query and notify
|
||||||
|
if (i == isc::dns::Opcode::QUERY().getCode() ||
|
||||||
|
i == isc::dns::Opcode::NOTIFY().getCode()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
createDataFromFile("simplequery_fromWire.wire");
|
||||||
|
data[2] = ((i << 3) & 0xff);
|
||||||
|
|
||||||
|
parse_message->clear(isc::dns::Message::PARSE);
|
||||||
|
processMessage();
|
||||||
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
||||||
|
headerCheck(*parse_message, default_qid, isc::dns::Rcode::NOTIMP(), i,
|
||||||
|
QR_FLAG, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple questions. Should result in FORMERR.
|
||||||
|
void
|
||||||
|
SrvTestBase::multiQuestion() {
|
||||||
|
createDataFromFile("multiquestion_fromWire.wire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
||||||
|
headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
|
||||||
|
opcode.getCode(), QR_FLAG, 2, 0, 0, 0);
|
||||||
|
|
||||||
|
isc::dns::QuestionIterator qit = parse_message->beginQuestion();
|
||||||
|
EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
|
||||||
|
EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
|
||||||
|
EXPECT_EQ(isc::dns::RRType::A(), (*qit)->getType());
|
||||||
|
++qit;
|
||||||
|
EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
|
||||||
|
EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
|
||||||
|
EXPECT_EQ(isc::dns::RRType::AAAA(), (*qit)->getType());
|
||||||
|
++qit;
|
||||||
|
EXPECT_TRUE(qit == parse_message->endQuestion());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incoming data doesn't even contain the complete header. Must be silently
|
||||||
|
// dropped.
|
||||||
|
void
|
||||||
|
SrvTestBase::shortMessage() {
|
||||||
|
createDataFromFile("shortmessage_fromWire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response messages. Must be silently dropped, whether it's a valid response
|
||||||
|
// or malformed or could otherwise cause a protocol error.
|
||||||
|
void
|
||||||
|
SrvTestBase::response() {
|
||||||
|
// A valid (although unusual) response
|
||||||
|
createDataFromFile("simpleresponse_fromWire.wire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
||||||
|
|
||||||
|
// A response with a broken question section. must be dropped rather than
|
||||||
|
//returning FORMERR.
|
||||||
|
createDataFromFile("shortresponse_fromWire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
||||||
|
|
||||||
|
// A response to iquery. must be dropped rather than returning NOTIMP.
|
||||||
|
createDataFromFile("iqueryresponse_fromWire.wire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_FALSE(dnsserv.hasAnswer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query with a broken question
|
||||||
|
void
|
||||||
|
SrvTestBase::shortQuestion() {
|
||||||
|
createDataFromFile("shortquestion_fromWire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
||||||
|
// Since the query's question is broken, the question section of the
|
||||||
|
// response should be empty.
|
||||||
|
headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
|
||||||
|
opcode.getCode(), QR_FLAG, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query with a broken answer section
|
||||||
|
void
|
||||||
|
SrvTestBase::shortAnswer() {
|
||||||
|
createDataFromFile("shortanswer_fromWire.wire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
||||||
|
|
||||||
|
// This is a bogus query, but question section is valid. So the response
|
||||||
|
// should copy the question section.
|
||||||
|
headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
|
||||||
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
isc::dns::QuestionIterator qit = parse_message->beginQuestion();
|
||||||
|
EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
|
||||||
|
EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
|
||||||
|
EXPECT_EQ(isc::dns::RRType::A(), (*qit)->getType());
|
||||||
|
++qit;
|
||||||
|
EXPECT_TRUE(qit == parse_message->endQuestion());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query with unsupported version of EDNS.
|
||||||
|
void
|
||||||
|
SrvTestBase::ednsBadVers() {
|
||||||
|
createDataFromFile("queryBadEDNS_fromWire.wire");
|
||||||
|
processMessage();
|
||||||
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
||||||
|
|
||||||
|
// The response must have an EDNS OPT RR in the additional section,
|
||||||
|
// it will be added automatically at the render time.
|
||||||
|
// Note that the DNSSEC DO bit is cleared even if this bit in the query
|
||||||
|
// is set. This is a limitation of the current implementation.
|
||||||
|
headerCheck(*parse_message, default_qid, isc::dns::Rcode::BADVERS(),
|
||||||
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 1);
|
||||||
|
EXPECT_FALSE(parse_message->getEDNS()); // EDNS isn't added at this point
|
||||||
|
|
||||||
|
isc::dns::InputBuffer ib(response_obuffer->getData(),
|
||||||
|
response_obuffer->getLength());
|
||||||
|
isc::dns::Message parsed(isc::dns::Message::PARSE);
|
||||||
|
parsed.fromWire(ib);
|
||||||
|
EXPECT_EQ(isc::dns::Rcode::BADVERS(), parsed.getRcode());
|
||||||
|
isc::dns::ConstEDNSPtr edns(parsed.getEDNS());
|
||||||
|
ASSERT_TRUE(edns);
|
||||||
|
EXPECT_FALSE(edns->getDNSSECAwareness());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SrvTestBase::axfrOverUDP() {
|
||||||
|
// AXFR over UDP is invalid and should result in FORMERR.
|
||||||
|
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
|
||||||
|
isc::dns::Name("example.com"),
|
||||||
|
isc::dns::RRClass::IN(),
|
||||||
|
isc::dns::RRType::AXFR());
|
||||||
|
createRequestPacket(request_message, IPPROTO_UDP);
|
||||||
|
processMessage();
|
||||||
|
EXPECT_TRUE(dnsserv.hasAnswer());
|
||||||
|
headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
|
||||||
|
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
|
||||||
|
const uint16_t opcodeval, const unsigned int flags,
|
||||||
|
const unsigned int qdcount,
|
||||||
|
const unsigned int ancount, const unsigned int nscount,
|
||||||
|
const unsigned int arcount)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(qid, message.getQid());
|
||||||
|
EXPECT_EQ(rcode, message.getRcode());
|
||||||
|
EXPECT_EQ(opcodeval, message.getOpcode().getCode());
|
||||||
|
EXPECT_EQ((flags & QR_FLAG) != 0,
|
||||||
|
message.getHeaderFlag(Message::HEADERFLAG_QR));
|
||||||
|
EXPECT_EQ((flags & AA_FLAG) != 0,
|
||||||
|
message.getHeaderFlag(Message::HEADERFLAG_AA));
|
||||||
|
EXPECT_EQ((flags & TC_FLAG) != 0,
|
||||||
|
message.getHeaderFlag(Message::HEADERFLAG_TC));
|
||||||
|
EXPECT_EQ((flags & RA_FLAG) != 0,
|
||||||
|
message.getHeaderFlag(Message::HEADERFLAG_RA));
|
||||||
|
EXPECT_EQ((flags & RD_FLAG) != 0,
|
||||||
|
message.getHeaderFlag(Message::HEADERFLAG_RD));
|
||||||
|
EXPECT_EQ((flags & AD_FLAG) != 0,
|
||||||
|
message.getHeaderFlag(Message::HEADERFLAG_AD));
|
||||||
|
EXPECT_EQ((flags & CD_FLAG) != 0,
|
||||||
|
message.getHeaderFlag(Message::HEADERFLAG_CD));
|
||||||
|
|
||||||
|
EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
|
||||||
|
EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
|
||||||
|
EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
|
||||||
|
EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
|
||||||
|
}
|
||||||
|
} // end of namespace testutils
|
||||||
|
} // end of namespace isc
|
||||||
|
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: c++
|
||||||
|
// End:
|
@@ -12,10 +12,6 @@
|
|||||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
// PERFORMANCE OF THIS SOFTWARE.
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
// $Id: auth_srv_unittest.cc 3310 2010-10-21 23:10:24Z each $
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <dns/buffer.h>
|
#include <dns/buffer.h>
|
||||||
@@ -27,139 +23,99 @@
|
|||||||
#include <dns/rrclass.h>
|
#include <dns/rrclass.h>
|
||||||
#include <dns/rrtype.h>
|
#include <dns/rrtype.h>
|
||||||
|
|
||||||
#include <cc/data.h>
|
|
||||||
#include <cc/session.h>
|
|
||||||
|
|
||||||
#include <xfr/xfrout_client.h>
|
|
||||||
|
|
||||||
#include <auth/auth_srv.h>
|
|
||||||
#include <asiolink/asiolink.h>
|
|
||||||
|
|
||||||
#include <dns/tests/unittest_util.h>
|
|
||||||
#include "mockups.h"
|
#include "mockups.h"
|
||||||
|
|
||||||
using namespace std;
|
namespace asiolink {
|
||||||
using namespace isc::cc;
|
class IOSocket;
|
||||||
using namespace isc::dns;
|
class IOMessage;
|
||||||
using namespace isc::data;
|
class IOEndpoint;
|
||||||
using namespace isc::xfr;
|
|
||||||
using namespace asiolink;
|
|
||||||
using isc::UnitTestUtil;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
|
|
||||||
|
|
||||||
// The base class for Auth and Resolver test case
|
|
||||||
class SrvTestBase : public ::testing::Test {
|
|
||||||
protected:
|
|
||||||
SrvTestBase() : request_message(Message::RENDER),
|
|
||||||
parse_message(new Message(Message::PARSE)),
|
|
||||||
default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
|
|
||||||
qname("www.example.com"), qclass(RRClass::IN()),
|
|
||||||
qtype(RRType::A()), io_sock(NULL),
|
|
||||||
io_message(NULL), endpoint(NULL),
|
|
||||||
request_obuffer(0), request_renderer(request_obuffer),
|
|
||||||
response_obuffer(new OutputBuffer(0))
|
|
||||||
{}
|
|
||||||
~SrvTestBase() {
|
|
||||||
delete io_message;
|
|
||||||
delete endpoint;
|
|
||||||
}
|
|
||||||
MockSession notify_session;
|
|
||||||
MockServer dnsserv;
|
|
||||||
Message request_message;
|
|
||||||
MessagePtr parse_message;
|
|
||||||
const qid_t default_qid;
|
|
||||||
const Opcode opcode;
|
|
||||||
const Name qname;
|
|
||||||
const RRClass qclass;
|
|
||||||
const RRType qtype;
|
|
||||||
IOSocket* io_sock;
|
|
||||||
IOMessage* io_message;
|
|
||||||
const IOEndpoint* endpoint;
|
|
||||||
OutputBuffer request_obuffer;
|
|
||||||
MessageRenderer request_renderer;
|
|
||||||
OutputBufferPtr response_obuffer;
|
|
||||||
vector<uint8_t> data;
|
|
||||||
|
|
||||||
void createDataFromFile(const char* const datafile, int protocol);
|
|
||||||
void createRequestPacket(Message& message, const int protocol);
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
SrvTestBase::createDataFromFile(const char* const datafile,
|
|
||||||
const int protocol = IPPROTO_UDP)
|
|
||||||
{
|
|
||||||
delete io_message;
|
|
||||||
data.clear();
|
|
||||||
|
|
||||||
delete endpoint;
|
|
||||||
|
|
||||||
endpoint = IOEndpoint::create(protocol,
|
|
||||||
IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
|
|
||||||
UnitTestUtil::readWireData(datafile, data);
|
|
||||||
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
|
|
||||||
&IOSocket::getDummyTCPSocket();
|
|
||||||
io_message = new IOMessage(&data[0], data.size(), *io_sock, *endpoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
namespace isc {
|
||||||
SrvTestBase::createRequestPacket(Message& message,
|
namespace testutils {
|
||||||
const int protocol = IPPROTO_UDP)
|
extern const char* const DEFAULT_REMOTE_ADDRESS;
|
||||||
{
|
|
||||||
message.toWire(request_renderer);
|
|
||||||
|
|
||||||
delete io_message;
|
|
||||||
|
|
||||||
endpoint = IOEndpoint::create(protocol,
|
|
||||||
IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
|
|
||||||
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
|
|
||||||
&IOSocket::getDummyTCPSocket();
|
|
||||||
io_message = new IOMessage(request_renderer.getData(),
|
|
||||||
request_renderer.getLength(),
|
|
||||||
*io_sock, *endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are flags to indicate whether the corresponding flag bit of the
|
// These are flags to indicate whether the corresponding flag bit of the
|
||||||
// DNS header is to be set in the test cases. (Note that the flag values
|
// DNS header is to be set in the test cases. (The flag values
|
||||||
// is irrelevant to their wire-format values)
|
// is irrelevant to their wire-format values)
|
||||||
const unsigned int QR_FLAG = 0x1;
|
extern const unsigned int QR_FLAG;
|
||||||
const unsigned int AA_FLAG = 0x2;
|
extern const unsigned int AA_FLAG;
|
||||||
const unsigned int TC_FLAG = 0x4;
|
extern const unsigned int TC_FLAG;
|
||||||
const unsigned int RD_FLAG = 0x8;
|
extern const unsigned int RD_FLAG;
|
||||||
const unsigned int RA_FLAG = 0x10;
|
extern const unsigned int RA_FLAG;
|
||||||
const unsigned int AD_FLAG = 0x20;
|
extern const unsigned int AD_FLAG;
|
||||||
const unsigned int CD_FLAG = 0x40;
|
extern const unsigned int CD_FLAG;
|
||||||
|
|
||||||
void
|
void
|
||||||
headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
|
headerCheck(const isc::dns::Message& message, const isc::dns::qid_t qid,
|
||||||
|
const isc::dns::Rcode& rcode,
|
||||||
const uint16_t opcodeval, const unsigned int flags,
|
const uint16_t opcodeval, const unsigned int flags,
|
||||||
const unsigned int qdcount,
|
const unsigned int qdcount,
|
||||||
const unsigned int ancount, const unsigned int nscount,
|
const unsigned int ancount, const unsigned int nscount,
|
||||||
const unsigned int arcount)
|
const unsigned int arcount);
|
||||||
{
|
|
||||||
EXPECT_EQ(qid, message.getQid());
|
|
||||||
EXPECT_EQ(rcode, message.getRcode());
|
|
||||||
EXPECT_EQ(opcodeval, message.getOpcode().getCode());
|
|
||||||
EXPECT_EQ((flags & QR_FLAG) != 0,
|
|
||||||
message.getHeaderFlag(Message::HEADERFLAG_QR));
|
|
||||||
EXPECT_EQ((flags & AA_FLAG) != 0,
|
|
||||||
message.getHeaderFlag(Message::HEADERFLAG_AA));
|
|
||||||
EXPECT_EQ((flags & TC_FLAG) != 0,
|
|
||||||
message.getHeaderFlag(Message::HEADERFLAG_TC));
|
|
||||||
EXPECT_EQ((flags & RA_FLAG) != 0,
|
|
||||||
message.getHeaderFlag(Message::HEADERFLAG_RA));
|
|
||||||
EXPECT_EQ((flags & RD_FLAG) != 0,
|
|
||||||
message.getHeaderFlag(Message::HEADERFLAG_RD));
|
|
||||||
EXPECT_EQ((flags & AD_FLAG) != 0,
|
|
||||||
message.getHeaderFlag(Message::HEADERFLAG_AD));
|
|
||||||
EXPECT_EQ((flags & CD_FLAG) != 0,
|
|
||||||
message.getHeaderFlag(Message::HEADERFLAG_CD));
|
|
||||||
|
|
||||||
EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
|
// The base class for Auth and Recurse test case
|
||||||
EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
|
class SrvTestBase : public ::testing::Test {
|
||||||
EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
|
protected:
|
||||||
EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
|
SrvTestBase();
|
||||||
}
|
virtual ~SrvTestBase();
|
||||||
|
|
||||||
}
|
/// Let the server process a DNS message.
|
||||||
|
///
|
||||||
|
/// The derived class implementation is expected to pass \c io_message,
|
||||||
|
/// \c parse_message, \c response_obuffer, and \c dnsserv to the server
|
||||||
|
/// implementation it is testing.
|
||||||
|
virtual void processMessage() = 0;
|
||||||
|
|
||||||
|
/// The following methods implement server independent test logic using
|
||||||
|
/// the template method pattern. Each test calls \c processMessage()
|
||||||
|
/// to delegate the server-dependent behavior to the actual implementation
|
||||||
|
/// classes.
|
||||||
|
void unsupportedRequest();
|
||||||
|
void multiQuestion();
|
||||||
|
void shortMessage();
|
||||||
|
void response();
|
||||||
|
void shortQuestion();
|
||||||
|
void shortAnswer();
|
||||||
|
void ednsBadVers();
|
||||||
|
void axfrOverUDP();
|
||||||
|
|
||||||
|
/// Create DNS packet data from a file.
|
||||||
|
///
|
||||||
|
/// It constructs wire-format DNS packet data from \c datafile in the
|
||||||
|
/// form of \c IOMessage in \c io_message.
|
||||||
|
/// The existing content of \c io_message, if any, will be deleted.
|
||||||
|
void createDataFromFile(const char* const datafile,
|
||||||
|
int protocol = IPPROTO_UDP);
|
||||||
|
|
||||||
|
/// Create DNS packet data from a message.
|
||||||
|
///
|
||||||
|
/// It constructs wire-format DNS packet data from \c message in the
|
||||||
|
/// form of \c IOMessage in \c io_message.
|
||||||
|
/// The existing content of \c io_message, if any, will be deleted.
|
||||||
|
void createRequestPacket(isc::dns::Message& message,
|
||||||
|
const int protocol = IPPROTO_UDP);
|
||||||
|
|
||||||
|
MockSession notify_session;
|
||||||
|
MockServer dnsserv;
|
||||||
|
isc::dns::Message request_message;
|
||||||
|
isc::dns::MessagePtr parse_message;
|
||||||
|
const isc::dns::qid_t default_qid;
|
||||||
|
const isc::dns::Opcode opcode;
|
||||||
|
const isc::dns::Name qname;
|
||||||
|
const isc::dns::RRClass qclass;
|
||||||
|
const isc::dns::RRType qtype;
|
||||||
|
asiolink::IOSocket* io_sock;
|
||||||
|
asiolink::IOMessage* io_message;
|
||||||
|
const asiolink::IOEndpoint* endpoint;
|
||||||
|
isc::dns::OutputBuffer request_obuffer;
|
||||||
|
isc::dns::MessageRenderer request_renderer;
|
||||||
|
isc::dns::OutputBufferPtr response_obuffer;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
};
|
||||||
|
} // end of namespace testutils
|
||||||
|
} // end of namespace isc
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// mode: c++
|
||||||
|
// End:
|
||||||
|
@@ -1,158 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// $Id: auth_srv_unittest.cc 3310 2010-10-21 23:10:24Z each $
|
|
||||||
|
|
||||||
#include "srv_test.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Unsupported requests. Should result in NOTIMP.
|
|
||||||
#define UNSUPPORTED_REQUEST_TEST \
|
|
||||||
for (unsigned int i = 0; i < 16; ++i) { \
|
|
||||||
/* set Opcode to 'i', which iterators over all possible codes except \
|
|
||||||
the standard query and notify */ \
|
|
||||||
if (i == Opcode::QUERY().getCode() || \
|
|
||||||
i == Opcode::NOTIFY().getCode()) { \
|
|
||||||
continue; \
|
|
||||||
} \
|
|
||||||
createDataFromFile("simplequery_fromWire.wire"); \
|
|
||||||
data[2] = ((i << 3) & 0xff); \
|
|
||||||
\
|
|
||||||
parse_message->clear(Message::PARSE); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, \
|
|
||||||
&dnsserv); \
|
|
||||||
EXPECT_TRUE(dnsserv.hasAnswer()); \
|
|
||||||
headerCheck(*parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG, \
|
|
||||||
0, 0, 0, 0); \
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple API check
|
|
||||||
#define VERBOSE_TEST \
|
|
||||||
EXPECT_FALSE(server.getVerbose()); \
|
|
||||||
server.setVerbose(true); \
|
|
||||||
EXPECT_TRUE(server.getVerbose()); \
|
|
||||||
server.setVerbose(false); \
|
|
||||||
EXPECT_FALSE(server.getVerbose()); \
|
|
||||||
|
|
||||||
|
|
||||||
// Multiple questions. Should result in FORMERR.
|
|
||||||
#define MULTI_QUESTION_TEST \
|
|
||||||
createDataFromFile("multiquestion_fromWire.wire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_TRUE(dnsserv.hasAnswer()); \
|
|
||||||
headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
|
|
||||||
QR_FLAG, 2, 0, 0, 0); \
|
|
||||||
\
|
|
||||||
QuestionIterator qit = parse_message->beginQuestion(); \
|
|
||||||
EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
|
|
||||||
EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
|
|
||||||
EXPECT_EQ(RRType::A(), (*qit)->getType()); \
|
|
||||||
++qit; \
|
|
||||||
EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
|
|
||||||
EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
|
|
||||||
EXPECT_EQ(RRType::AAAA(), (*qit)->getType()); \
|
|
||||||
++qit; \
|
|
||||||
EXPECT_TRUE(qit == parse_message->endQuestion());
|
|
||||||
|
|
||||||
// Incoming data doesn't even contain the complete header. Must be silently
|
|
||||||
// dropped.
|
|
||||||
#define SHORT_MESSAGE_TEST \
|
|
||||||
createDataFromFile("shortmessage_fromWire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
||||||
|
|
||||||
// Response messages. Must be silently dropped, whether it's a valid response
|
|
||||||
// or malformed or could otherwise cause a protocol error.
|
|
||||||
#define RESPONSE_TEST \
|
|
||||||
/* A valid (although unusual) response */\
|
|
||||||
createDataFromFile("simpleresponse_fromWire.wire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_FALSE(dnsserv.hasAnswer()); \
|
|
||||||
\
|
|
||||||
/* A response with a broken question section. must be dropped rather than \
|
|
||||||
returning FORMERR. */\
|
|
||||||
createDataFromFile("shortresponse_fromWire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_FALSE(dnsserv.hasAnswer()); \
|
|
||||||
\
|
|
||||||
/* A response to iquery. must be dropped rather than returning NOTIMP. */\
|
|
||||||
createDataFromFile("iqueryresponse_fromWire.wire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_FALSE(dnsserv.hasAnswer());
|
|
||||||
|
|
||||||
// Query with a broken question
|
|
||||||
#define SHORT_QUESTION_TEST \
|
|
||||||
createDataFromFile("shortquestion_fromWire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_TRUE(dnsserv.hasAnswer()); \
|
|
||||||
/* Since the query's question is broken, the question section of the \
|
|
||||||
response should be empty. */\
|
|
||||||
headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
|
|
||||||
QR_FLAG, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
// Query with a broken answer section
|
|
||||||
#define SHORT_ANSWER_TEST \
|
|
||||||
createDataFromFile("shortanswer_fromWire.wire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_TRUE(dnsserv.hasAnswer()); \
|
|
||||||
\
|
|
||||||
/* This is a bogus query, but question section is valid. So the response \
|
|
||||||
should copy the question section. */ \
|
|
||||||
headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
|
|
||||||
QR_FLAG, 1, 0, 0, 0); \
|
|
||||||
\
|
|
||||||
QuestionIterator qit = parse_message->beginQuestion(); \
|
|
||||||
EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
|
|
||||||
EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
|
|
||||||
EXPECT_EQ(RRType::A(), (*qit)->getType()); \
|
|
||||||
++qit; \
|
|
||||||
EXPECT_TRUE(qit == parse_message->endQuestion());
|
|
||||||
|
|
||||||
// Query with unsupported version of EDNS.
|
|
||||||
#define EDNS_BADVERS_TEST \
|
|
||||||
createDataFromFile("queryBadEDNS_fromWire.wire"); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_TRUE(dnsserv.hasAnswer()); \
|
|
||||||
\
|
|
||||||
/* The response must have an EDNS OPT RR in the additional section, \
|
|
||||||
it will be added automatically at the render time.
|
|
||||||
Note that the DNSSEC DO bit is cleared even if this bit in the query \
|
|
||||||
is set. This is a limitation of the current implementation. */ \
|
|
||||||
headerCheck(*parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(), \
|
|
||||||
QR_FLAG, 1, 0, 0, 1); \
|
|
||||||
EXPECT_FALSE(parse_message->getEDNS()); /* EDNS isn't added at this point */ \
|
|
||||||
\
|
|
||||||
InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength()); \
|
|
||||||
Message parsed(Message::PARSE); \
|
|
||||||
parsed.fromWire(ib); \
|
|
||||||
EXPECT_EQ(Rcode::BADVERS(), parsed.getRcode()); \
|
|
||||||
ConstEDNSPtr edns(parsed.getEDNS()); \
|
|
||||||
ASSERT_TRUE(edns); \
|
|
||||||
EXPECT_FALSE(edns->getDNSSECAwareness());
|
|
||||||
|
|
||||||
|
|
||||||
#define AXFR_OVER_UDP_TEST \
|
|
||||||
/* AXFR over UDP is invalid and should result in FORMERR. */\
|
|
||||||
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid, \
|
|
||||||
Name("example.com"), RRClass::IN(), \
|
|
||||||
RRType::AXFR()); \
|
|
||||||
createRequestPacket(request_message, IPPROTO_UDP); \
|
|
||||||
server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
|
|
||||||
EXPECT_TRUE(dnsserv.hasAnswer()); \
|
|
||||||
headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
|
|
||||||
QR_FLAG, 1, 0, 0, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Reference in New Issue
Block a user