// If this is an error to a query or notify, we should also copy the
// question section.
if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
- questions.assign(message->beginQuestion(), message->endQuestion());
+ questions.assign(message.beginQuestion(), message.endQuestion());
}
- message->clear(Message::RENDER);
- message->setQid(qid);
- message->setOpcode(opcode);
- message->setHeaderFlag(Message::HEADERFLAG_QR);
+ message.clear(Message::RENDER);
+ message.setQid(qid);
+ message.setOpcode(opcode);
+ message.setHeaderFlag(Message::HEADERFLAG_QR);
if (rd) {
- message->setHeaderFlag(Message::HEADERFLAG_RD);
+ message.setHeaderFlag(Message::HEADERFLAG_RD);
}
if (cd) {
- message->setHeaderFlag(Message::HEADERFLAG_CD);
+ message.setHeaderFlag(Message::HEADERFLAG_CD);
}
for_each(questions.begin(), questions.end(), QuestionInserter(message));
- message->setRcode(rcode);
- message.setRcode(rcode);
+
++ message.setRcode(rcode);
+
MessageRenderer renderer;
- renderer.setBuffer(buffer.get());
+ renderer.setBuffer(&buffer);
if (tsig_context.get() != NULL) {
- message->toWire(renderer, *tsig_context);
+ message.toWire(renderer, *tsig_context);
} else {
- message->toWire(renderer);
+ message.toWire(renderer);
}
renderer.setBuffer(NULL);
LOG_DEBUG(auth_logger, DBG_AUTH_MESSAGES, AUTH_SEND_ERROR_RESPONSE)
return (true);
}
- MessageRenderer renderer;
- renderer.setBuffer(&buffer);
+ renderer_.clear();
+ renderer_.setBuffer(buffer.get());
++
const bool udp_buffer =
(io_message.getSocket().getProtocol() == IPPROTO_UDP);
- renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
+ renderer_.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
if (tsig_context.get() != NULL) {
- message.toWire(renderer, *tsig_context);
+ message->toWire(renderer_, *tsig_context);
} else {
- message.toWire(renderer);
+ message->toWire(renderer_);
}
- renderer.setBuffer(NULL);
LOG_DEBUG(auth_logger, DBG_AUTH_MESSAGES, AUTH_SEND_NORMAL_RESPONSE)
- .arg(renderer.getLength()).arg(message);
-
+ .arg(renderer_.getLength()).arg(message->toText());
-
return (true);
}
return (false);
}
- message->makeResponse();
- message->setHeaderFlag(Message::HEADERFLAG_AA);
- message->setRcode(Rcode::NOERROR());
+ message.makeResponse();
+ message.setHeaderFlag(Message::HEADERFLAG_AA);
+ message.setRcode(Rcode::NOERROR());
- MessageRenderer renderer;
- renderer.setBuffer(&buffer);
+ renderer_.clear();
+ renderer_.setBuffer(buffer.get());
if (tsig_context.get() != NULL) {
- message.toWire(renderer, *tsig_context);
+ message->toWire(renderer_, *tsig_context);
} else {
- message.toWire(renderer);
+ message->toWire(renderer_);
}
- renderer.setBuffer(NULL);
return (true);
}
}
}
++<<<<<<< HEAD
++=======
+ // Convenience method for tests that expect to return SERVFAIL
+ // It calls processMessage, checks if there is an answer, and
+ // check the header for default SERVFAIL data
+ void processAndCheckSERVFAIL() {
+ processMessage();
+ EXPECT_TRUE(dnsserv.hasAnswer());
+ headerCheck(*parse_message, default_qid, Rcode::SERVFAIL(),
+ opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+ }
+
++>>>>>>> master
IOService ios_;
DNSService dnss_;
MockSession statistics_session;
"Released tokens");
}
++<<<<<<< HEAD
+TEST_F(AuthSrvTest, processNormalQuery_reuseRenderer1) {
+ UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+ default_qid, Name("example.com"),
+ RRClass::IN(), RRType::NS());
+
+ request_message.setHeaderFlag(Message::HEADERFLAG_AA);
+ createRequestPacket(request_message, IPPROTO_UDP);
+ server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
+ EXPECT_NE(request_message.getRcode(), parse_message->getRcode());
+}
+
+TEST_F(AuthSrvTest, processNormalQuery_reuseRenderer2) {
+ UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+ default_qid, Name("example.com"),
+ RRClass::IN(), RRType::SOA());
+
+ request_message.setHeaderFlag(Message::HEADERFLAG_AA);
+ createRequestPacket(request_message, IPPROTO_UDP);
+ server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv);
+ ConstQuestionPtr question = *parse_message->beginQuestion();
+ EXPECT_STRNE(question->getType().toText().c_str(),RRType::NS().toText().c_str());
++=======
+ //
+ // Tests for catching exceptions in various stages of the query processing
+ //
+ // These tests work by defining two proxy classes, that act as an in-memory
+ // client by default, but can throw exceptions at various points.
+ //
+ namespace {
+
+ /// A the possible methods to throw in, either in FakeInMemoryClient or
+ /// FakeZoneFinder
+ enum ThrowWhen {
+ THROW_NEVER,
+ THROW_AT_FIND_ZONE,
+ THROW_AT_GET_ORIGIN,
+ THROW_AT_GET_CLASS,
+ THROW_AT_FIND,
+ THROW_AT_FIND_ALL,
+ THROW_AT_FIND_NSEC3
+ };
+
+ /// convenience function to check whether and what to throw
+ void
+ checkThrow(ThrowWhen method, ThrowWhen throw_at, bool isc_exception) {
+ if (method == throw_at) {
+ if (isc_exception) {
+ isc_throw(isc::Exception, "foo");
+ } else {
+ throw std::exception();
+ }
+ }
+ }
+
+ /// \brief proxy class for the ZoneFinder returned by the InMemoryClient
+ /// proxied by FakeInMemoryClient
+ ///
+ /// See the documentation for FakeInMemoryClient for more information,
+ /// all methods simply check whether they should throw, and if not, call
+ /// their proxied equivalent.
+ class FakeZoneFinder : public isc::datasrc::ZoneFinder {
+ public:
+ FakeZoneFinder(isc::datasrc::ZoneFinderPtr zone_finder,
+ ThrowWhen throw_when,
+ bool isc_exception) :
+ real_zone_finder_(zone_finder),
+ throw_when_(throw_when),
+ isc_exception_(isc_exception)
+ {}
+
+ virtual isc::dns::Name
+ getOrigin() const {
+ checkThrow(THROW_AT_GET_ORIGIN, throw_when_, isc_exception_);
+ return (real_zone_finder_->getOrigin());
+ }
+
+ virtual isc::dns::RRClass
+ getClass() const {
+ checkThrow(THROW_AT_GET_CLASS, throw_when_, isc_exception_);
+ return (real_zone_finder_->getClass());
+ }
+
+ virtual isc::datasrc::ZoneFinderContextPtr
+ find(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ isc::datasrc::ZoneFinder::FindOptions options)
+ {
+ checkThrow(THROW_AT_FIND, throw_when_, isc_exception_);
+ return (real_zone_finder_->find(name, type, options));
+ }
+
+ virtual isc::datasrc::ZoneFinderContextPtr
+ findAll(const isc::dns::Name& name,
+ std::vector<isc::dns::ConstRRsetPtr> &target,
+ const FindOptions options = FIND_DEFAULT)
+ {
+ checkThrow(THROW_AT_FIND_ALL, throw_when_, isc_exception_);
+ return (real_zone_finder_->findAll(name, target, options));
+ }
+
+ virtual FindNSEC3Result
+ findNSEC3(const isc::dns::Name& name, bool recursive) {
+ checkThrow(THROW_AT_FIND_NSEC3, throw_when_, isc_exception_);
+ return (real_zone_finder_->findNSEC3(name, recursive));
+ }
+
+ virtual isc::dns::Name
+ findPreviousName(const isc::dns::Name& query) const {
+ return (real_zone_finder_->findPreviousName(query));
+ }
+
+ private:
+ isc::datasrc::ZoneFinderPtr real_zone_finder_;
+ ThrowWhen throw_when_;
+ bool isc_exception_;
+ };
+
+ /// \brief Proxy InMemoryClient that can throw exceptions at specified times
+ ///
+ /// It is based on the memory client since that one is easy to override
+ /// (with setInMemoryClient) with the current design of AuthSrv.
+ class FakeInMemoryClient : public isc::datasrc::InMemoryClient {
+ public:
+ /// \brief Create a proxy memory client
+ ///
+ /// \param real_client The real in-memory client to proxy
+ /// \param throw_when if set to any value other than never, that is
+ /// the method that will throw an exception (either in this
+ /// class or the related FakeZoneFinder)
+ /// \param isc_exception if true, throw isc::Exception, otherwise,
+ /// throw std::exception
+ FakeInMemoryClient(AuthSrv::InMemoryClientPtr real_client,
+ ThrowWhen throw_when,
+ bool isc_exception) :
+ real_client_(real_client),
+ throw_when_(throw_when),
+ isc_exception_(isc_exception)
+ {}
+
+ /// \brief proxy call for findZone
+ ///
+ /// if this instance was constructed with throw_when set to find_zone,
+ /// this method will throw. Otherwise, it will return a FakeZoneFinder
+ /// instance which will throw at the method specified at the
+ /// construction of this instance.
+ virtual FindResult
+ findZone(const isc::dns::Name& name) const {
+ checkThrow(THROW_AT_FIND_ZONE, throw_when_, isc_exception_);
+ const FindResult result = real_client_->findZone(name);
+ return (FindResult(result.code, isc::datasrc::ZoneFinderPtr(
+ new FakeZoneFinder(result.zone_finder,
+ throw_when_,
+ isc_exception_))));
+ }
+
+ private:
+ AuthSrv::InMemoryClientPtr real_client_;
+ ThrowWhen throw_when_;
+ bool isc_exception_;
+ };
+
+ } // end anonymous namespace for throwing proxy classes
+
+ // Test for the tests
+ //
+ // Set the proxies to never throw, this should have the same result as
+ // queryWithInMemoryClientNoDNSSEC, and serves to test the two proxy classes
+ TEST_F(AuthSrvTest, queryWithInMemoryClientProxy) {
+ // Set real inmem client to proxy
+ updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
+
+ AuthSrv::InMemoryClientPtr fake_client(
+ new FakeInMemoryClient(server.getInMemoryClient(rrclass),
+ THROW_NEVER,
+ false));
+
+ ASSERT_NE(AuthSrv::InMemoryClientPtr(), server.getInMemoryClient(rrclass));
+ server.setInMemoryClient(rrclass, fake_client);
+
+ createDataFromFile("nsec3query_nodnssec_fromWire.wire");
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
+ &dnsserv);
+
+ EXPECT_TRUE(dnsserv.hasAnswer());
+ headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+ opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
+ }
+
+ // Convenience function for the rest of the tests, set up a proxy
+ // to throw in the given method
+ // If isc_exception is true, it will throw isc::Exception, otherwise
+ // it will throw std::exception
+ void
+ setupThrow(AuthSrv* server, const char *config, ThrowWhen throw_when,
+ bool isc_exception)
+ {
+ // Set real inmem client to proxy
+ updateConfig(server, config, true);
+
+ // Set it to throw on findZone(), this should result in
+ // SERVFAIL on any exception
+ AuthSrv::InMemoryClientPtr fake_client(
+ new FakeInMemoryClient(
+ server->getInMemoryClient(isc::dns::RRClass::IN()),
+ throw_when,
+ isc_exception));
+
+ ASSERT_NE(AuthSrv::InMemoryClientPtr(),
+ server->getInMemoryClient(isc::dns::RRClass::IN()));
+ server->setInMemoryClient(isc::dns::RRClass::IN(), fake_client);
+ }
+
+ TEST_F(AuthSrvTest, queryWithThrowingProxyServfails) {
+ // Test the common cases, all of which should simply return SERVFAIL
+ // Use THROW_NEVER as end marker
+ ThrowWhen throws[] = { THROW_AT_FIND_ZONE,
+ THROW_AT_GET_ORIGIN,
+ THROW_AT_FIND,
+ THROW_AT_FIND_NSEC3,
+ THROW_NEVER };
+ UnitTestUtil::createDNSSECRequestMessage(request_message, opcode,
+ default_qid, Name("foo.example."),
+ RRClass::IN(), RRType::TXT());
+ for (ThrowWhen* when(throws); *when != THROW_NEVER; ++when) {
+ createRequestPacket(request_message, IPPROTO_UDP);
+ setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, true);
+ processAndCheckSERVFAIL();
+ // To be sure, check same for non-isc-exceptions
+ createRequestPacket(request_message, IPPROTO_UDP);
+ setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, false);
+ processAndCheckSERVFAIL();
+ }
+ }
+
+ // Throw isc::Exception in getClass(). (Currently?) getClass is not called
+ // in the processMessage path, so this should result in a normal answer
+ TEST_F(AuthSrvTest, queryWithInMemoryClientProxyGetClass) {
+ createDataFromFile("nsec3query_nodnssec_fromWire.wire");
+ setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_AT_GET_CLASS, true);
+
+ // getClass is not called so it should just answer
+ server.processMessage(*io_message, *parse_message, *response_obuffer,
+ &dnsserv);
+
+ EXPECT_TRUE(dnsserv.hasAnswer());
+ headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+ opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
++>>>>>>> master
}
}