Commit 2b8a0c37 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

merged branches/trac327


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@3903 e5f2f494-b856-4b98-b285-d166d9295462
parents f9ccf457 f7fd282f
134. [func] vorner
b10-recurse supports timeouts and retries in forwarder mode.
(Trac #401, svn r3660)
133. [func] vorner
New temporary logging function available in isc::log. It is used by
b10-recurse.
(Trac #393, r3602)
132. [func] vorner
The b10-recursive is configured through config manager.
It has "listen_on" and "forward_addresses" options.
(Trac #389, r3448)
131. [func] feng, jerry
src/lib/datasrc: Introduced two template classes RBTree and RBNode
to provide the generic map with domain name as key and anything as
......@@ -25,6 +39,7 @@
for root zone was added.
(Trac #85, svn r3836)
>>>>>>> .merge-right.r3894
127. [bug] stephen
During normal operation process termination and resurrection messages
are now output regardless of the state of the verbose flag.
......
......@@ -556,9 +556,9 @@ AC_CONFIG_FILES([Makefile
src/bin/msgq/tests/Makefile
src/bin/auth/Makefile
src/bin/auth/tests/Makefile
src/bin/auth/tests/testdata/Makefile
src/bin/auth/benchmarks/Makefile
src/bin/recurse/Makefile
src/bin/recurse/tests/Makefile
src/bin/xfrin/Makefile
src/bin/xfrin/tests/Makefile
src/bin/xfrout/Makefile
......@@ -575,6 +575,8 @@ AC_CONFIG_FILES([Makefile
src/bin/usermgr/Makefile
src/bin/tests/Makefile
src/lib/Makefile
src/lib/asiolink/Makefile
src/lib/asiolink/tests/Makefile
src/lib/bench/Makefile
src/lib/bench/example/Makefile
src/lib/bench/tests/Makefile
......@@ -609,6 +611,9 @@ AC_CONFIG_FILES([Makefile
src/lib/datasrc/Makefile
src/lib/datasrc/tests/Makefile
src/lib/xfr/Makefile
src/lib/log/Makefile
src/lib/testutils/Makefile
src/lib/testutils/testdata/Makefile
src/lib/nsas/Makefile
src/lib/nsas/tests/Makefile
])
......@@ -625,9 +630,8 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
src/bin/xfrout/xfrout.spec.pre
src/bin/xfrout/tests/xfrout_test
src/bin/xfrout/run_b10-xfrout.sh
src/bin/recurse/recurse.py
src/bin/recurse/recurse.spec.pre
src/bin/recurse/run_b10-recurse.sh
src/bin/recurse/spec_config.h.pre
src/bin/zonemgr/zonemgr.py
src/bin/zonemgr/zonemgr.spec.pre
src/bin/zonemgr/tests/zonemgr_test
......
......@@ -568,7 +568,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/lib/bench ../src/lib/nsas
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......
......@@ -3,8 +3,9 @@ SUBDIRS = . tests benchmarks
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiolink
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
......@@ -33,26 +34,6 @@ auth.spec: auth.spec.pre
spec_config.h: spec_config.h.pre
$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
# This is a wrapper library solely used for b10-auth. The ASIO header files
# have some code fragments that would hit gcc's unused-parameter warning,
# which would make the build fail with -Werror (our default setting).
# We don't want to lower the warning level for our own code just for ASIO,
# so as a workaround we extract the ASIO related code into a separate library,
# only for which we accept the unused-parameter warning.
lib_LIBRARIES = libasio_link.a
libasio_link_a_SOURCES = asio_link.cc asio_link.h
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS)
if USE_GXX
libasio_link_a_CXXFLAGS += -Wno-unused-parameter
endif
if USE_CLANGPP
# Same for clang++, but we need to turn off -Werror completely.
libasio_link_a_CXXFLAGS += -Wno-error
endif
libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
BUILT_SOURCES = spec_config.h
pkglibexec_PROGRAMS = b10-auth
b10_auth_SOURCES = auth_srv.cc auth_srv.h
......@@ -65,7 +46,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.la
b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
b10_auth_LDADD += libasio_link.a
b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
b10_auth_LDADD += $(SQLITE_LIBS)
......
This diff is collapsed.
......@@ -14,6 +14,8 @@
// $Id$
#include <config.h>
#include <netinet/in.h>
#include <algorithm>
......@@ -21,6 +23,12 @@
#include <iostream>
#include <vector>
#include <asiolink/asiolink.h>
#include <config/ccsession.h>
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include <dns/buffer.h>
......@@ -34,22 +42,16 @@
#include <dns/rrset.h>
#include <dns/rrttl.h>
#include <dns/message.h>
#include <config/ccsession.h>
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include <datasrc/query.h>
#include <datasrc/data_source.h>
#include <datasrc/static_datasrc.h>
#include <datasrc/sqlite3_datasrc.h>
#include <cc/data.h>
#include <xfr/xfrout_client.h>
#include <auth/common.h>
#include <auth/auth_srv.h>
#include <auth/asio_link.h>
using namespace std;
......@@ -61,7 +63,7 @@ using namespace isc::dns::rdata;
using namespace isc::data;
using namespace isc::config;
using namespace isc::xfr;
using namespace asio_link;
using namespace asiolink;
class AuthSrvImpl {
private:
......@@ -73,32 +75,34 @@ public:
~AuthSrvImpl();
isc::data::ConstElementPtr setDbFile(isc::data::ConstElementPtr config);
bool processNormalQuery(const IOMessage& io_message, Message& message,
MessageRenderer& response_renderer);
bool processAxfrQuery(const IOMessage& io_message, Message& message,
MessageRenderer& response_renderer);
bool processNotify(const IOMessage& io_message, Message& message,
MessageRenderer& response_renderer);
std::string db_file_;
bool processNormalQuery(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer);
bool processAxfrQuery(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer);
bool processNotify(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer);
/// Currently non-configurable, but will be.
static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
/// These members are public because AuthSrv accesses them directly.
ModuleCCSession* config_session_;
bool verbose_mode_;
AbstractSession* xfrin_session_;
/// Hot spot cache
isc::datasrc::HotCache cache_;
private:
std::string db_file_;
MetaDataSrc data_sources_;
/// We keep a pointer to the currently running sqlite datasource
/// so that we can specifically remove that one should the database
/// file change
ConstDataSrcPtr cur_datasrc_;
bool verbose_mode_;
AbstractSession* xfrin_session_;
bool xfrout_connected_;
AbstractXfroutClient& xfrout_client_;
/// Currently non-configurable, but will be.
static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
/// Hot spot cache
isc::datasrc::HotCache cache_;
};
AuthSrvImpl::AuthSrvImpl(const bool use_cache,
......@@ -126,60 +130,127 @@ AuthSrvImpl::~AuthSrvImpl() {
}
}
// This is a derived class of \c DNSLookup, to serve as a
// callback in the asiolink module. It calls
// AuthSrv::processMessage() on a single DNS message.
class MessageLookup : public DNSLookup {
public:
MessageLookup(AuthSrv* srv) : server_(srv) {}
virtual void operator()(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer, DNSServer* server) const
{
server_->processMessage(io_message, message, buffer, server);
}
private:
AuthSrv* server_;
};
// This is a derived class of \c DNSAnswer, to serve as a
// callback in the asiolink module. It takes a completed
// set of answer data from the DNS lookup and assembles it
// into a wire-format response.
class MessageAnswer : public DNSAnswer {
public:
MessageAnswer(AuthSrv* srv) : server_(srv) {}
virtual void operator()(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer) const
{
MessageRenderer renderer(*buffer);
if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
ConstEDNSPtr edns(message->getEDNS());
renderer.setLengthLimit(edns ? edns->getUDPSize() :
Message::DEFAULT_MAX_UDPSIZE);
} else {
renderer.setLengthLimit(65535);
}
message->toWire(renderer);
if (server_->getVerbose()) {
cerr << "[b10-auth] sending a response (" << renderer.getLength()
<< " bytes):\n" << message->toText() << endl;
}
}
private:
AuthSrv* server_;
};
// This is a derived class of \c SimpleCallback, to serve
// as a callback in the asiolink module. It checks for queued
// configuration messages, and executes them if found.
class ConfigChecker : public SimpleCallback {
public:
ConfigChecker(AuthSrv* srv) : server_(srv) {}
virtual void operator()(const IOMessage&) const {
if (server_->getConfigSession()->hasQueuedMsgs()) {
server_->getConfigSession()->checkCommand();
}
}
private:
AuthSrv* server_;
};
AuthSrv::AuthSrv(const bool use_cache, AbstractXfroutClient& xfrout_client) :
impl_(new AuthSrvImpl(use_cache, xfrout_client))
impl_(new AuthSrvImpl(use_cache, xfrout_client)),
checkin_(new ConfigChecker(this)),
dns_lookup_(new MessageLookup(this)),
dns_answer_(new MessageAnswer(this))
{}
AuthSrv::~AuthSrv() {
delete impl_;
delete checkin_;
delete dns_lookup_;
delete dns_answer_;
}
namespace {
class QuestionInserter {
public:
QuestionInserter(Message* message) : message_(message) {}
QuestionInserter(MessagePtr message) : message_(message) {}
void operator()(const QuestionPtr question) {
message_->addQuestion(question);
}
Message* message_;
MessagePtr message_;
};
void
makeErrorMessage(Message& message, MessageRenderer& renderer,
makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
const Rcode& rcode, const bool verbose_mode)
{
// extract the parameters that should be kept.
// XXX: with the current implementation, it's not easy to set EDNS0
// depending on whether the query had it. So we'll simply omit it.
const qid_t qid = message.getQid();
const bool rd = message.getHeaderFlag(Message::HEADERFLAG_RD);
const bool cd = message.getHeaderFlag(Message::HEADERFLAG_CD);
const Opcode& opcode = message.getOpcode();
const qid_t qid = message->getQid();
const bool rd = message->getHeaderFlag(Message::HEADERFLAG_RD);
const bool cd = message->getHeaderFlag(Message::HEADERFLAG_CD);
const Opcode& opcode = message->getOpcode();
vector<QuestionPtr> questions;
// 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.toWire(renderer);
for_each(questions.begin(), questions.end(), QuestionInserter(message));
message->setRcode(rcode);
MessageRenderer renderer(*buffer);
message->toWire(renderer);
if (verbose_mode) {
cerr << "[b10-auth] sending an error response (" <<
renderer.getLength() << " bytes):\n" << message.toText() << endl;
renderer.getLength() << " bytes):\n" << message->toText() << endl;
}
}
}
......@@ -219,143 +290,147 @@ AuthSrv::getConfigSession() const {
return (impl_->config_session_);
}
bool
AuthSrv::processMessage(const IOMessage& io_message, Message& message,
MessageRenderer& response_renderer)
void
AuthSrv::processMessage(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer, DNSServer* server)
{
InputBuffer request_buffer(io_message.getData(), io_message.getDataSize());
// First, check the header part. If we fail even for the base header,
// just drop the message.
try {
message.parseHeader(request_buffer);
message->parseHeader(request_buffer);
// Ignore all responses.
if (message.getHeaderFlag(Message::HEADERFLAG_QR)) {
if (message->getHeaderFlag(Message::HEADERFLAG_QR)) {
if (impl_->verbose_mode_) {
cerr << "[b10-auth] received unexpected response, ignoring"
<< endl;
}
return (false);
server->resume(false);
return;
}
} catch (const Exception& ex) {
return (false);
if (impl_->verbose_mode_) {
cerr << "[b10-auth] DNS packet exception: " << ex.what() << endl;
}
server->resume(false);
return;
}
// Parse the message. On failure, return an appropriate error.
try {
message.fromWire(request_buffer);
// Parse the message.
message->fromWire(request_buffer);
} catch (const DNSProtocolError& error) {
if (impl_->verbose_mode_) {
cerr << "[b10-auth] returning " << error.getRcode().toText()
<< ": " << error.what() << endl;
}
makeErrorMessage(message, response_renderer, error.getRcode(),
makeErrorMessage(message, buffer, error.getRcode(),
impl_->verbose_mode_);
return (true);
server->resume(true);
return;
} catch (const Exception& ex) {
if (impl_->verbose_mode_) {
cerr << "[b10-auth] returning SERVFAIL: " << ex.what() << endl;
}
makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
makeErrorMessage(message, buffer, Rcode::SERVFAIL(),
impl_->verbose_mode_);
return (true);
server->resume(true);
return;
} // other exceptions will be handled at a higher layer.
if (impl_->verbose_mode_) {
cerr << "[b10-auth] received a message:\n" << message.toText() << endl;
cerr << "[b10-auth] received a message:\n" << message->toText() << endl;
}
// Perform further protocol-level validation.
if (message.getOpcode() == Opcode::NOTIFY()) {
return (impl_->processNotify(io_message, message, response_renderer));
} else if (message.getOpcode() != Opcode::QUERY()) {
bool sendAnswer = true;
if (message->getOpcode() == Opcode::NOTIFY()) {
sendAnswer = impl_->processNotify(io_message, message, buffer);
} else if (message->getOpcode() != Opcode::QUERY()) {
if (impl_->verbose_mode_) {
cerr << "[b10-auth] unsupported opcode" << endl;
}
makeErrorMessage(message, response_renderer, Rcode::NOTIMP(),
impl_->verbose_mode_);
return (true);
}
if (message.getRRCount(Message::SECTION_QUESTION) != 1) {
makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
makeErrorMessage(message, buffer, Rcode::NOTIMP(),
impl_->verbose_mode_);
return (true);
}
ConstQuestionPtr question = *message.beginQuestion();
const RRType &qtype = question->getType();
if (qtype == RRType::AXFR()) {
return (impl_->processAxfrQuery(io_message, message,
response_renderer));
} else if (qtype == RRType::IXFR()) {
makeErrorMessage(message, response_renderer, Rcode::NOTIMP(),
} else if (message->getRRCount(Message::SECTION_QUESTION) != 1) {
makeErrorMessage(message, buffer, Rcode::FORMERR(),
impl_->verbose_mode_);
return (true);
} else {
return (impl_->processNormalQuery(io_message, message,
response_renderer));
ConstQuestionPtr question = *message->beginQuestion();
const RRType &qtype = question->getType();
if (qtype == RRType::AXFR()) {
sendAnswer = impl_->processAxfrQuery(io_message, message, buffer);
} else if (qtype == RRType::IXFR()) {
makeErrorMessage(message, buffer, Rcode::NOTIMP(),
impl_->verbose_mode_);
} else {
sendAnswer = impl_->processNormalQuery(io_message, message, buffer);
}
}
server->resume(sendAnswer);
}
bool
AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
MessageRenderer& response_renderer)
AuthSrvImpl::processNormalQuery(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer)
{
ConstEDNSPtr remote_edns = message.getEDNS();
ConstEDNSPtr remote_edns = message->getEDNS();
const bool dnssec_ok = remote_edns && remote_edns->getDNSSECAwareness();
const uint16_t remote_bufsize = remote_edns ? remote_edns->getUDPSize() :
Message::DEFAULT_MAX_UDPSIZE;
message.makeResponse();
message.setHeaderFlag(Message::HEADERFLAG_AA);
message.setRcode(Rcode::NOERROR());
message->makeResponse();
message->setHeaderFlag(Message::HEADERFLAG_AA);
message->setRcode(Rcode::NOERROR());
if (remote_edns) {
EDNSPtr local_edns = EDNSPtr(new EDNS());
local_edns->setDNSSECAwareness(dnssec_ok);
local_edns->setUDPSize(AuthSrvImpl::DEFAULT_LOCAL_UDPSIZE);
message.setEDNS(local_edns);
message->setEDNS(local_edns);
}
try {
Query query(message, cache_, dnssec_ok);
Query query(*message, cache_, dnssec_ok);
data_sources_.doQuery(query);
} catch (const Exception& ex) {
if (verbose_mode_) {
cerr << "[b10-auth] Internal error, returning SERVFAIL: " <<
ex.what() << endl;
}
makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
verbose_mode_);
makeErrorMessage(message, buffer, Rcode::SERVFAIL(), verbose_mode_);
return (true);
}
MessageRenderer renderer(*buffer);
const bool udp_buffer =
(io_message.getSocket().getProtocol() == IPPROTO_UDP);
response_renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
message.toWire(response_renderer);
renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
message->toWire(renderer);
if (verbose_mode_) {
cerr << "[b10-auth] sending a response ("
<< response_renderer.getLength()
<< " bytes):\n" << message.toText() << endl;
<< renderer.getLength()
<< " bytes):\n" << message->toText() << endl;
}
return (true);
}
bool
AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
MessageRenderer& response_renderer)
AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer)
{
if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
if (verbose_mode_) {
cerr << "[b10-auth] AXFR query over UDP isn't allowed" << endl;
}
makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
verbose_mode_);
makeErrorMessage(message, buffer, Rcode::FORMERR(), verbose_mode_);
return (true);
}
......@@ -382,8 +457,7 @@ AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
cerr << "[b10-auth] Error in handling XFR request: " << err.what()
<< endl;
}
makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
verbose_mode_);
makeErrorMessage(message, buffer, Rcode::SERVFAIL(), verbose_mode_);
return (true);
}
......@@ -391,28 +465,26 @@ AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
}
bool
AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
MessageRenderer& response_renderer)
AuthSrvImpl::processNotify(const IOMessage& io_message, MessagePtr message,
OutputBufferPtr buffer)
{
// The incoming notify must contain exactly one question for SOA of the
// zone name.
if (message.getRRCount(Message::SECTION_QUESTION) != 1) {
if (message->getRRCount(Message::SECTION_QUESTION) != 1) {
if (verbose_mode_) {
cerr << "[b10-auth] invalid number of questions in notify: "
<< message.getRRCount(Message::SECTION_QUESTION) << endl;
<< message->getRRCount(Message::SECTION_QUESTION) << endl;
}
makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
verbose_mode_);
makeErrorMessage(message, buffer, Rcode::FORMERR(), verbose_mode_);
return (true);
}
ConstQuestionPtr question = *message.beginQuestion();
ConstQuestionPtr question = *message->beginQuestion();
if (question->getType() != RRType::SOA()) {
if (verbose_mode_) {
cerr << "[b10-auth] invalid question RR type in notify: "
<< question->getType() << endl;
}